Introduction to Spring AOP and its underlying implementation mechanism -- dynamic proxy

Keywords: Java Spring Programming JDK Database

AOP introduction

AOP (aspect oriented programming) is called: aspect oriented programming, which is a kind of programming idea. AOP is the continuation of OOP (Object Oriented Programming)

AOP adopts horizontal extraction mechanism to replace the traditional vertical inheritance system of repetitive code writing (such as performance monitoring, transaction management, security check, cache, logging, etc.)

AOP core idea

Based on the idea of agent, the agent object is created for the original target object. Without modifying the original object code, the original business method is enhanced by calling the enhanced code through the agent object

Aspect: need to proxy some methods and enhance code

AOP application scenarios

Scenario 1: log

Scenario 2: monitoring method run time (monitoring performance)

Scenario 3: permission control

Scenario 4: cache optimization (the first call to query the database, put the query results into the memory object, the second call, directly return from the memory object, no need to query the database)

Scenario 5: transaction management (start transaction before calling method, commit or roll back or close transaction after calling method)

Two ways of Spring AOP programming

Method 1: Spring AOP is implemented in pure Java, without special compilation process and classloader, and the target class is embedded with enhanced code by proxy during runtime (programming is very complex)

Mode 2: after Spring 2.0, it supports the third-party AOP framework (AspectJ), and implements another AOP programming (recommended)

AOP programming related terms

1. Aspect: it is a combination of notification and pointcut. Notification and pointcut jointly define the whole content about the aspect - its function, when and where to complete its function

2. Join point: the so-called join points refer to those intercepted. In spring, these points refer to methods, because spring only supports connection points of method type

3. Pointcut: the so-called pointcut refers to the definition of which join points we want to intercept. When the notification defines "what" and "when" of the cut, the pointcut defines "where"

4. Advice (notification, enhancement): the so-called notification refers to the notification that is the thing to be done after intercepting the joinpoint. Notifications are divided into pre notification, post notification, exception notification, final notification, and surround notification (functions to be completed in all aspects)

5. Target: the target object of the agent

6. Weaving: refers to the process of applying the facet to the target object to create a new proxy object. The facet is woven into the target object at the specified connection point

7. Introduction (not required to master): without modifying the class code, introduction can dynamically add some methods or fields to the class during the runtime

The underlying mechanism of AOP programming

AOP is to create proxy objects for the target. Spring AOP is based on dynamic proxy, which is based on two dynamic proxy mechanisms: JDK dynamic proxy and CGLIB dynamic proxy

Mode 1: JDK dynamic agent

JDK dynamic proxy, proxy for the interface of the target object, dynamically generate the implementation class of the interface (there must be an interface)

Key points of process

1. A proxy must be generated for the interface

2. Use Proxy object to create Proxy object for the target through newProxyInstance method.

This method receives three parameters:

(1) target object class loader

(2) interface implemented by the target object

(3) InvocationHandler after agent

3. Implement the invoke method in the InvocationHandler interface. When each method of the target object is called, the invoke will be executed

service level

//Interface (represents the target interface of the agent)
public interface ICustomerService {
    //Preservation
    void save();
    //query
    int find();
}

//Implementation layer
public class CustomerServiceImpl implements ICustomerService{

    @Override
    public void save() {
       System.out.println("The customer saved.....");
    }

    @Override
    public int find() {
       System.out.println("The number of customer inquiries.....");
       return 100;
    }
}

JDK dynamic agent factory

//General purpose for generating dynamic proxy objects for jdk
public class JdkProxyFactory{
    //Target target object
    private Object target;
    
    //Inject target target object
    public JdkProxyFactory(Object target) {
       this.target = target;
    }

    public Object getProxyObject(){

        /**
        * Parameter 1: class loader of the target object
        * Parameter 2: interface implemented by the target object
        * Parameter 3: callback method object
       */
       return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), 
            new InvocationHandler(){
                public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
                    //If it is a saved method, log it
                    if(method.getName().equals("save")){
                        System.out.println("Enhanced Code: write log...");
                     }
                    //Target object original method execution
                    Object object = method.invoke(target, args);//Call a method of the target object and return the target object
                    return object;
                 }
        });
    }
}

test method

//Objective: to use dynamic agents to enhance the original method without changing the original code.
//JDK dynamic proxy: interface based (object type, interface must be implemented!)
@Test
public void testJdkProxy(){
   //Target (target object)
   ICustomerService target = new CustomerServiceImpl();
   //Instantiate injection target object
   JdkProxyFactory jdkProxyFactory = new JdkProxyFactory(target);
   //Get Object proxy Object: Object of subtype based on the type of interface of target Object type
   //The interface object must be used to de enforce
   ICustomerService proxy = (ICustomerService)jdkProxyFactory.getProxyObject();
   //Method to call the target object
   proxy.save();
   System.out.println("----------");
   proxy.find();
}                                                                                  

Be careful

The object generated by JDK dynamic agent is no longer the original object

  • Error:
CustomerServiceImpl proxy = (CustomerServiceImpl)jdkProxyFactory.getProxyObject();                                
  • Correct
ICustomerService proxy = (ICustomerService)jdkProxyFactory.getProxyObject();

Mode 2: Cglib dynamic agent

Cglib is introduced to solve the problem of direct proxy of classes (generation of proxy subclasses), which can be proxy without interface

The proxy mode requires the corresponding jar package, but does not need to be imported. Because the Spring core package already contains cglib, and at the same time contains the package of asm that cglib relies on (the operation class library of dynamic bytecode)

//Classes without interfaces
public class ProductService {
    public void save() {
       System.out.println("The goods are preserved.....");
    }
    
    public int find() {
       System.out.println("The quantity of the goods inquired.....");
       return 99;
    }
}

Using cglib proxy

//Cglib dynamic proxy factory: used to generate cglib proxy objects
public class CglibProxyFactory implements MethodInterceptor{
    private Object target;

    //Inject proxy object
    public CglibProxyFactory(Object target) {
       this.target = target;
    }
    
    //Get proxy object
    public Object getProxyObject(){
       //1. Proxy object generator (factory idea)
       Enhancer enhancer = new Enhancer();
        // Class loader
       enhancer.setClassLoader(target.getClass().getClassLoader());
       
       //2. Set two properties on the intensifier
       //Set target object to generate proxy object: subtype of the generated target object type
       enhancer.setSuperclass(target.getClass());
       //Set callback method
       enhancer.setCallback(this);
        
       //3. Create acquisition object
       return enhancer.create();
    }
    
    //Callback method (method of proxy object)
    /**
     *  Parameter 1: proxy object
     *  Parameter 2: method object of target object
     *  Parameter 3: the value of the parameter of the method of the target object
     *  Parameter 4: method object of proxy object
     */
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
       //If it is a saved method, log it
       if(method.getName().equals("save")){
            System.out.println("Enhanced Code: write log...");
       }
        //Target object original method execution
        //Call a method of the target object and return the target object
       Object object = method.invoke(target, args);
       return object;
    }
}

test method

//cglib dynamic proxy: proxy objects can be generated based on classes without implementing interfaces
    @Test
    public void testCglibProxy(){
       //Target target:
       ProductService target = new ProductService();

       //Agent factory object, injection target
       CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(target);
       
       //Get proxy
       //The proxy object is actually a subtype of the target object type
       ProductService proxy = (ProductService)cglibProxyFactory.getProxyObject();
       //Method to call the proxy object
       proxy.save();
       System.out.println("----------—");
       proxy.find();
    }

summary

spring generates dynamic proxy objects at runtime without special compiler

Spring AOP preferentially proxies the interface (using Jdk dynamic proxy). If the target object does not implement any interface, the class will be proxied (using cglib dynamic proxy)

Be careful

1. Creating a proxy for an interface is better than creating a proxy for a class. Because it will produce a more loosely coupled system, spring uses the JDK proxy by default. Class broker is a third-party class library that allows legacy systems or interfaces that cannot be implemented to be notified, which should be an alternative solution

2. Methods marked final cannot be notified. spring generates subclasses for the target class. Any method that needs to be notified is copied and the notification is woven in. The final method is not allowed to be overridden

3.spring only supports method connection points: it does not provide attribute access points. spring's point of view is that attribute interception breaks the encapsulation. The concept of object-oriented is that objects handle their own work, and other objects can only get results through method calls

Posted by frANZi on Thu, 12 Dec 2019 23:43:41 -0800