background
In the project, the method provided by a third-party jar package cannot meet the requirements, and the jar package method needs to be enhanced. Spring's custom facet is used to enhance the method. The code is as follows:
@Aspect @Component public class SendMessageAspect{ public SendMessageAspect(){ System.out.println("Test entrance"); } @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 { // Gets the name of the target method String methodName = joinPoint.getSignature().getName(); // Get method passed in parameters 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)){ //Replace keyword with* 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; } } // Execution source method joinPoint.proceed(params); } }
problem
After executing the code, it is found that not only there is no enhancement effect, but the methods of the previous jar package can not be executed. The around method cannot be executed at all. However, the facet does work, because after removing the facet, the methods of the jar package execute normally. After adding the facet, the methods of the jar package cannot execute normally. This shows that the section intercepts the method.
solve
When I first encountered this problem, I had no way to start. I even thought of starting with the Spring source code, looking at the execution process of all aspects and finding problems. If this problem is really solved, the time cost will be large. Finally gave up the idea.
The essence of solving problems is to understand the meaning of aspects. The pointcut defined in the aspect is to call the around method to enhance the method when executing the method of the pointcut. The breakpoint does not enter the around method, which proves that the method to be enhanced is not called. Therefore, to solve this problem, we have to find where to call the pointcut method.
Since this jar package is a jar package developed by ourselves, it is easy to find the place where the pointcut is called. The method is as follows:
@Override public void process(Channel channel, SentBody body) { CIMRequestHandler handler = handlerMap.get(body.getKey()); if(handler == null) {return ;} handler.process(channel, body); }
You can see that the object of the pointcut method is stored in the handlerMap. Here, the pointcut object is obtained through the Map, and then the pointcut method process is executed. Now I have enhanced this method and added facets. Then this object is a proxy object, not a native object. Therefore, we need to see where handlerMap adds this object. The code is as follows:
It can be seen that this method is a listener method in the Spring event mechanism. It obtains an object of type CIMRequestHandler from the Spring container, and then traverses it to determine whether the object has CIMHandler annotation. If so, it is added to the handlerMap collection. Because I used the proxy, now I get the proxy object, which was used before this method
CIMHandler annotation = handler.getClass().getAnnotation(CIMHandler.class);
The code could not get the annotation of the proxy object. Equivalent to missing annotations. Therefore, there will be no proxy object for the pointcut in the handlerMap. This is why we can't get to the around method. Because there is no such object at all, let alone the method that calls it.
The solution is to obtain the annotation of the proxy object as follows:
CIMHandler annotation =AnnotatedElementUtils.findMergedAnnotation(handler.getClass(),CIMHandler.class);
The AnnotatedElementUtils tool class is used here. This class will be explained separately in the future.
summary
Where is the main consideration for solving the bug. If the around method is not executed, it is proved that the enhanced method is not called, so finding where to call this method is the key.