In Spring AOP, the problem of using this to call the method

scene problem

Suppose we have a core payment class, which has the pay() payment function, and will record which users have accessed this core function through the record() method.

As the business continues to expand, we need to count the time-consuming action of saving the access log to see if it will have a greater impact on the core payment function.

Therefore, we use Spring AOP for aspect processing.

The aspect class is very simple. The record method is cut in and out through the @Around method, and the execution time of the method is recorded.

looks fine

Let's create a new controller to see if our aspect class takes effect.

 

 Start the service and visit http://localhost:8080/demo/pay.

A problem occurred.

According to the above code, after printing the business log, it should print a line to record the time-consuming log. However, the console is empty, indicating that our aspect class has not taken effect.

The problem is the this call in the pay() method.

We can see that this in the figure points to a normal PayService object, not a bean enhanced by Spring.

And what is the working principle of SpringAOP: Spring generates a proxy class for the target class through JDK dynamic proxy and CGlib proxy, and enhances the functions in the proxy class.

Let's take a look at the PayService in the controller:

It can be seen that the payService in the controller is a proxy class enhanced by SpringCLlib, and what we refer to through this is just an ordinary bean object for Spring, which naturally cannot realize the AOP function.

When will Spring proxy an object?

Spring will judge whether to perform proxy when a bean is created. The core class is AnnotationAwareAspectJAutoProxyCreator, which is essentially a BeanPostProcessor. When AOP needs to be used, it will wrap the created original Bean object into a proxy object and return it as a Bean.

Therefore, the final conclusion is: only objects that are dynamically proxied can be enhanced by Spring and have AOP capabilities .

Solution

There are two ways.

One, quote yourself

Inject yourself directly in the current class, so that Spring will proxy the properties in the class and generate a payService proxy class.

It should be noted that this is actually artificially creating circular dependencies. In higher versions of Springboot , circular dependencies are turned off by default. If you want to enable circular dependencies, you need to configure spring.main.allow-circular-references=true.

Second, through AopContext

AopContext internally maintains a ThreadLocal that saves the proxy . Simply put, it binds the proxy to the current thread through a ThreadLocal, so that the Proxy bound to the current thread can be taken out at any time.

If you use this method, you need to add a configuration item exposeProxy = true in @EnableAspectJAutoProxy.

/**
 * @author 戴着假发的程序员
 * 
 * @description
 */
@Component
public class MessageService {
    public String showMessage(String info) {
        System.out.println("OtherInfoServcie-showMessage展示信息:"+info);
        //使用AopContext的静态方法获取当前的代理对象
        ((MessageService)AopContext.currentProxy()).formartMsg(info);
        return null;
    }
    public String formartMsg(String info){
        System.out.println("OtherInfoServcie-formartMsg对象消息"+info+"进行格式化");
        return  info;
    }
}

 

Summarize

Spring AOP will actually automatically create a Proxy for us, so that the caller can call the specified method unconsciously, which is essentially a dynamic proxy. Only by accessing the methods of these proxy objects can we obtain the functions implemented by AOP, so it is impossible to use AOP functions correctly through this reference.

Guess you like

Origin blog.csdn.net/qq_30436011/article/details/129654691