Analysis of proxy mode and proxy mode used by spring

What is an agent

Proxy is a design pattern that provides another way to access the target object, that is, to access the target object through a proxy. Advantages: you can extend the functions of the target object without modifying the functions of the target object. *. (extend the function of the target object).

Static proxy:

introduce

Static proxy: by writing the proxy class in advance, it realizes the public interface and internal maintenance of the real role. Some function extensions are made on the basis of the real role, and the methods of the real role can be called through the proxy class

Roles involved in static proxy:

  • Abstract role: it is generally implemented using interfaces or abstract classes
  • Real role: represented object
  • Agent role: represent the real role and do some ancillary operations
  • Customer: use the agent role to perform some operations

example

//Abstract interface: Rental
public interface Rent {
    public void rent();
}
//Real role: landlord -- > rent a house
public class Host implements Rent{
    public void rent() {
        System.out.println("House rental");
    }
}

//Agent: Intermediary
public class Proxy implements Rent{
    // Receive and save the target object [the real work or the real role Host], so you need to maintain the reference of the Host
    Host host;
    public Proxy(Host host){this.host = host;}
    public void rent() {
        seeHouse();//House viewing
        host.rent();    Method of executing target object
        fare();//charge
    }

    public void seeHouse(){
        System.out.println("Show the tenant");
    }
    public void fare(){
        System.out.println("Intermediary fee");
    }

}

//Customer class: execute a series of business through agent class
public class Client {
    public static void main(String[] args) {
        // Target object
        Host host = new Host(); 
        // agent
        Proxy proxy = new Proxy(host);
        proxy.rent(); // What is executed is the proxy method
    }
}

Advantages and disadvantages of static agent

  • advantage:

    • It can make the real role more pure and stop paying attention to some public things

    • The public business is completed by the agent to complete the division of business

    • When public business is expanded, it is more centralized and convenient

  • Disadvantages:

    • If the interface is changed, the of the agent should also be changed

    • Because the proxy object needs to implement the same interface as the target object, there will be many proxy classes, which increases the amount of code

    • The proxy class and target object are established in the compilation time, which is not conducive to the expansion of the program.

Dynamic agent

introduce

Dynamic proxy: when the proxy class is written, it does not specify who the proxy class is. The proxy class is generated dynamically. Through the java reflection mechanism, the interface of a target class is obtained at runtime and the proxy class is created

Dynamic agents are divided into two categories: interface based dynamic agents; Class based dynamic agent

  • Interface based dynamic proxy JDK API dynamic proxy
  • Class based dynamic proxy – cglib dynamic proxy

JDK API dynamic proxy:

Both the proxy class and the proxy class implement the same set of interfaces. The proxy class first depends on who the proxy is. The proxy class is loaded in at runtime, and the interface proxy class implemented by the proxy class is also implemented, so that the methods of the target object can be called and extended

Two important classes:

**Proxy class: * * it is the superclass of all dynamic proxy classes. Calling its static method newProxyInstance() can generate the proxy object of the target object

    + public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
    
    - Parameter 1: which class loader is used to generate proxy objects [generally, we use the loader of proxy classes]
    - Parameter 2: specify the object to proxy through the interface [specify the interface of the class to proxy]
    - Parameter 3: the calling handler to which the method call is to be dispatched [can be implemented by itself Invocationhandler [interface incoming]

InvocationHandler: [calling handler] each proxy instance has an associated calling handler. When a method is called on a proxy instance, the method call is encoded and distributed to the invoke method of its call handler to execute and return the result.

InvocationHandler is the core of JDK dynamic proxy. The method calls of the generated proxy objects will be delegated to InvocationHandler Invoke() method

+ invoke()yes InvocationHandler Interface is the only method
+ public Object invoke(Object proxy, Method method, Object[] args)

- Parameter 1: the proxy instance that the method was invoked on (Proxy instance of the method being called)
- Parameter 2: instance corresponding to the interface method invoked on the proxy instance.(method Corresponds to an instance that invokes an interface method on a proxy instance)
- Parameter three args:Parameters in the currently called proxy instance method

be careful:

  • The proxy object has the same method as the target object [because parameter 2 specifies the interface of the object]
  • What method the user calls the proxy object is the invoke method of the processor.
  • The JDK dynamic agent must have an interface [parameter 2 requires an interface]

example

//Abstract interfaces and real characters are still used in the above one
//proxy class
public class JdkProxy implements InvocationHandler {
     // Receive save target object
    private Object target;
    public void setRent(Rent rent){this.target = rent;}
    
    //Generate proxy class
    public Object  getJdkProxt(){return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
//
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHouse();
        //Core: the essence is realized by reflection
        Object result = method.invoke(target, args);
        fare();
        return result;
    }

    public void seeHouse(){
        System.out.println("Show the tenant");
    }
    
    public void fare(){
        System.out.println("Intermediary fee");
    }
}

//The above code can also be written in another way. Instead of implementing the InvocationHandler interface, you can directly pass in the anonymous class anonymous object of InvocationHandler in newinstance() to bind the calling handler
public class JdkProxy2 {
    Object target;
    public void setRent(Rent rent){this.target = rent;}
    public Object  getJdkProxt(){return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                seeHouse();
                Object result = method.invoke(target, args);
                fare();
                return result;
            }
        })
                
    }
    public void seeHouse(){
        System.out.println("Show the tenant");
    }
    public void fare(){
        System.out.println("Intermediary fee");
    }
}


//client
public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        JdkProxy jdkProxy = new JdkProxy();
        jdkProxy.setRent(host);
        Rent proxy = (Rent)jdkProxy.getProxt();
        proxy.rent();
    }
}

cglib dynamic proxy

introduce

JDK dynamic Proxy must implement the interface to Proxy. If a class does not implement the interface, Proxy dynamic Proxy cannot be used. At this time, CGLIB (Code Generation Library) dynamic agent can be used to realize enhancement.

cglib [code generator bibrary], a code generator, can dynamically generate bytecode objects, that is, generate subclasses of the target class, which can be realized by calling the methods of the parent class (target class), and then enhanced in the proxy when calling the methods of the parent class

Steps to implement dynamic proxy with cglib:

  • Generate a bytecode object (empty)

  • Sets that the parent class of the bytecode object is the target object

  • Find the method definitions of all non final public types on the target class;

  • Convert the qualified method definition into bytecode;

  • Callback the method by generating bytecode object. In the process of callback, add function code (extension of method function)

  • Convert the bytecode into the class object of the corresponding agent;

  • Implement the MethodInterceptor interface, which is used to process requests for all methods on the proxy class

**Enhance class: * * generate dynamic subclasses to enable method interception. The dynamically generated subclass will override the non final method of the parent class and call back to the hook implemented by the user-defined interceptor

**MethodInterceptor: * * method interceptor

Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy)
Parameter 1: by CGLib Generated proxy class instance
 Parameter 2: the reference of the proxy method called on the proxy class
 Parameter 3: parameters of the called method
 Parameter 4: reference to the method of the parent class to be triggered

Preconditions for using CGLIB:
1) If the class is an abstract class, you can only call the implemented method. If you call the abstract method, an error will be reported
2) Class cannot be final, otherwise an error will be reported

example

//Target class
public class Host{
    public void rent() {
        System.out.println("House rental");
    }
}


public class CglibProxy implements MethodInterceptor {
    private Object target;//Target object requiring proxy
    public Object getCglibProxy(Object objectTarget){
        //Assign a value to the target object target
        this.target = objectTarget;
        Enhancer enhancer = new Enhancer();
        //Set the parent class. Because Cglib generates a subclass for the specified class, you need to specify the parent class
        enhancer.setSuperclass(objectTarget.getClass());
        // Set callback
        enhancer.setCallback(this);
		//Create and return proxy objects
        return enhancer.create();
    }
    
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        seeHouse();
        Object result = methodProxy.invoke(target, args);
        fare();
        return result;
    }

    public void seeHouse(){
        System.out.println("Show the tenant");
    }
    public void fare(){
        System.out.println("Intermediary fee");
    }

}

Comparison between JDK dynamic agent and CGLIB

1)

  • JDK dynamic proxy: Based on the Java reflection mechanism, it is necessary to implement the business class of the interface before generating the proxy object, and call the invoke() of InvokeHandler before calling the specific method.

  • CGLIB dynamic proxy: use asm open source package to load the class file of proxy object class and generate subclasses by modifying its bytecode.

2)

  • If the target object implements the interface, the dynamic agent of JDK will be used to implement AOP by default

  • If the target object implements the interface, you can force the use of CGLIB to implement AOP

How to force the use of CGLIB to implement AOP?
(1) Add CGLIB library, SPRING_HOME/cglib/*.jar
(2) Add < AOP: AspectJ AutoProxy proxy target class = "true" / > to the spring configuration file

  • If the target object does not implement the interface, the CGLIB library must be adopted, and spring will automatically convert between JDK dynamic agent and CGLIB

3)

  • JDK dynamic proxy can only generate proxy for classes that implement interfaces, not for classes
  • CGLIB implements proxy for classes. It mainly generates a subclass of a specified class and overrides the methods in it. Because it is inheritance, it is better not to declare this class or method as final

4)

  • Advantages of JDK Proxy:

Minimize dependencies, simplify code implementation, simplify development and maintenance, JDK native support, more reliable than CGLIB, and upgrade smoothly with JDK version. The bytecode class library usually needs to be updated to ensure that it can be used on the new version of Java.

  • Advantages of CGLIB:

There is no need to implement the interface, so that the proxy class does not invade, and only operates the concerned classes without increasing the workload for other related classes. High performance.

Advantages and disadvantages of dynamic agent

  • advantage:
    • It can make the real role more pure and stop paying attention to some public things
    • The public business is completed by the agent to complete the division of business
    • When public business is expanded, it is more centralized and convenient
    • Multiple classes can be represented. A dynamic proxy class represents an interface. As long as the class that implements the interface can be represented

Proxy method used by Spring AOP

  • JDK dynamic proxy is used by default, so that all interface types can be proxy

  • If the target object does not implement any interface, it defaults to the proxy mode of CGLIB

  • You can force CGLIB, specify proxy target class = "true" or @ enableaspectjautoproxy based on annotation (proxytargetclass = true)

org.springframework.aop.framework.ProxyProcessorSupport

org.springframework.aop.framework.DefaultAopProxyFactory

spring will judge all interfaces of the current class. If there is no satisfied interface, set proxyTargetClass to true. If there is, record the interface to facilitate the creation of proxy class when using JDK proxy mode.

In createAopProxy(), config If isproxytargetclass() is true, it will enter the first if branch. In this branch, if the bean itself is an interface or a proxy object, a JDK proxy will be created. Otherwise, the proxy object will be created in the way of CGLIB.

Reference documents: https://blog.csdn.net/w449226544/article/details/103365446

Keywords: Java Spring

Added by affordit on Sun, 30 Jan 2022 11:44:52 +0200