记一次Spring自定义切面不执行bug定位

背景

项目中,一个第三方jar包提供的方法无法满足需求,需要对jar包方法进行增强。使用了Spring的自定义切面进行方法的增强。代码如下:

@Aspect
@Component
public class SendMessageAspect{

    public SendMessageAspect(){
        System.out.println("测试入口");
    }

    @Autowired
    ICimKeywordService keywordService;


    @Pointcut("execution(public * com.farsunset.cim.component.handler.SendMessageHandler.process(..))")
   // @Pointcut("execution(public * com.farsunset.cim.config.CIMConfig.process(..))")
    public void execute() {

    }


    @Around("execute()")
    public void around(ProceedingJoinPoint joinPoint)throws Throwable {
        // 获取目标方法的名称
        String methodName = joinPoint.getSignature().getName();
        // 获取方法传入参数
        Object[] params = joinPoint.getArgs();
        SentBody body=(SentBody)params[1];
        String content=body.get("content");
        String format=body.get("format");
        if("text".equals(format)&& StringUtils.isNotEmpty(content)){
            //将关键字替换成*
          List<CimKeyword> keywords= keywordService.selectCimKeywordList(null);
          if(keywords!=null&&keywords.size()>0){
              for (CimKeyword keyword:
                      keywords) {
                  if(content.contains(keyword.getKeyword())){
                      content=content.replaceAll(keyword.getKeyword(),"**");
                  }
              }
              body.put("content",content);
              params[1]=body;
          }
        }

        // 执行源方法
        joinPoint.proceed(params);

    }
}

问题

执行代码后,发现不但没有增强效果,之前jar包的方法反而也执行不到了。around方法根本执行不进来。但是切面确实起作用了,因为去掉切面后,jar包的方法正常执行,加上切面后,jar包的方法无法正常执行。这说明切面是拦截到方法的。

解决

刚开始遇到这个问题,也是无从下手,甚至想到了从Spring源码入手,看切面的执行流程,进行问题的查找。如果真这么解决这个问题,那时间成本就大了去了。最终还是放弃了这种想法。
解决问题的本质还是理解切面的含义。切面中定义的切入点就是在执行切入点的方法时,调用around方法,进行方法的增强。而断点是没走进around方法的,证明就没有调用要增强的方法。所以,解决这个问题,还得找哪里调用的这个切入点方法。
由于这个jar包是我们自己开发的jar包,所以很容易找到了切入点调用的地方,方法如下:

	@Override
	public void process(Channel channel, SentBody body) {
		
        CIMRequestHandler handler = handlerMap.get(body.getKey());
		
		if(handler == null) {return ;}
		
		handler.process(channel, body);
		
	}

可以看到,切入点方法的对象是存入了handlerMap中,这里通过Map获得切入点对象,然后执行切入点方法process。我现在对这个方法进行了增强,加了切面,那这个对象就是代理对象了,而不是原生对象了。所以,我们要看handlerMap是在哪里加的这个对象。代码如下:
在这里插入图片描述
可以看到,该方法是Spring事件机制中的监听者方法,从Spring容器中获取CIMRequestHandler类型的对象,然后遍历,判断对象是否有CIMHandler注解,如果有,才加入handlerMap集合。因为我用了代理,所以现在获取到的是代理对象,该方法之前用的

CIMHandler annotation = handler.getClass().getAnnotation(CIMHandler.class);

代码无法获取到代理对象的注解。相当于注解丢失了。所以handlerMap中不会有切入点的代理对象。这就是为什么走不到around方法的原因。因为压根就没有这个对象,更不用说调用它的方法了。
解决方法是用如下方法获取代理对象的注解:

CIMHandler annotation =AnnotatedElementUtils.findMergedAnnotation(handler.getClass(),CIMHandler.class);

这里用到了AnnotatedElementUtils工具类。这个类,我们以后进行单独详解。

总结

解决该bug主要是从哪里考虑问题。没有执行around方法,证明就没有调用被增强的方法,所以找到哪里调用的这个方法是关键。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,针对您的问题,我可以简单地为您介绍一下在 Spring 中如何定义注解切面。 首先,您需要使用 Spring AOP 实现切面编程。Spring AOP 是基于代理模式的 AOP 框架,它可以在不修改原有代码的情况下,通过动态代理的方式对方法进行增强。 其次,您需要定义一个自定义注解,例如: ``` @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value() default ""; } ``` 这个注解可以在方法上进行标注,用来表示需要被切面增强的方法。 接下来,您可以定义一个切面类,实现对 MyAnnotation 注解进行切面增强,例如: ``` @Aspect @Component public class MyAspect { @Pointcut("@annotation(com.example.demo.MyAnnotation)") public void myPointcut() {} @Around("myPointcut()") public Object around(ProceedingJoinPoint pjp) throws Throwable { // 在方法执行前进行增强 System.out.println("before method execute..."); // 执行原有方法 Object result = pjp.proceed(); // 在方法执行后进行增强 System.out.println("after method execute..."); return result; } } ``` 在这个切面类中,我们使用 @Pointcut 定义了一个切点,表示需要增强被 MyAnnotation 注解标注的方法。在 around 方法中,我们可以在方法执行前后进行增强操作。 最后,您需要在 Spring 配置文件中将切面类注册为 Bean,并开启 AOP 自动代理,例如: ``` @Configuration @EnableAspectJAutoProxy @ComponentScan(basePackages = "com.example.demo") public class AppConfig { @Bean public MyAspect myAspect() { return new MyAspect(); } } ``` 这样,当您使用 MyAnnotation 注解标注一个方法时,该方法就会被 MyAspect 切面类增强。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码的小小酥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值