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