记一次Spring自定义切面不执行bug定位
Posted 敲代码的小小酥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次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方法,证明就没有调用被增强的方法,所以找到哪里调用的这个方法是关键。
以上是关于记一次Spring自定义切面不执行bug定位的主要内容,如果未能解决你的问题,请参考以下文章