1, Agent mode
①. concept
For some reason, an object needs to be provided with a proxy to control access to the object. At this time, the access object is not suitable or cannot directly reference the target object. The proxy object acts as the intermediary between the access object and the target object
②. structure
- Abstract Subject class: business methods implemented by declaring real subjects and proxy objects through interfaces or abstract classes.
- Real Subject class: it implements the specific business in the abstract subject. It is the real object represented by the proxy object and the object to be referenced finally.
- Proxy class: it provides the same interface as the real topic. It contains references to the real topic. It can access, control or expand the functions of the real topic.
1. Static agent
- UML
1.1 code
- SellTrickets
public interface SellTrickets { void sell(); }
- Cinema
public class Cinema implements SellTrickets { @Override public void sell() { System.out.println("Cinema tickets"); } }
- ProxyPerson
public class ProxyPerson implements SellTrickets{ private Cinema cinema = new Cinema(); @Override public void sell() { System.out.println("Agent selling tickets,Earned price difference"); cinema.sell(); } }
- Test class
public class Client { public static void main(String[] args) { ProxyPerson proxy = new ProxyPerson(); proxy.sell(); } } //results of enforcement Agent selling tickets,Earned price difference Cinema tickets
2. JDK dynamic agent
- UML
2.1 code
- Diagnostic tools
- ProxyFactory
public class ProxyFactory { private Cinema cinema = new Cinema(); public SellTrickets getProxyObject(){ /* ClassLoader loader: Class loader, which is used to load proxy classes. The class loader can be obtained through the target object Class<?>[] interfaaces: Bytecode object of interface implemented by proxy class InvocationHandler h : Call handler for proxy object */ SellTrickets sellTrickets = (SellTrickets)Proxy.newProxyInstance( cinema.getClass().getClassLoader(), cinema.getClass().getInterfaces(), new InvocationHandler() { /* Objcet proxy:The proxy object is the same object as the proxyObject object, and is basically not used in the invoke method Method method:method object that encapsulates the methods in the interface */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Proxy of invoke Called"); Object invoke = method.invoke(cinema, args); return invoke; } } ); return sellTrickets; } }
- Test class
public class Client { public static void main(String[] args) { //Create proxy factory object ProxyFactory factory = new ProxyFactory(); //Get the proxy object using the method of the factory object SellTrickets proxyObject = factory.getProxyObject(); proxyObject.sell(); System.out.println(proxyObject.getClass()); //Keep the program running, or you won't get the proxy class //1. Find Arthas boot Jar, run cmd under the file //2. Type Java - jar Arthas boot jar //3. Select the name of the runtime //3. Full class name of JAD object (see test results) while (true); } }
- test result
Proxy of invoke Called Cinema tickets class com.sun.proxy.$Proxy0//The full class name of the object
- Dynamic acquisition
public final class $Proxy0 extends Proxy implements SellTrickets { private static Method m3; public $Proxy0(InvocationHandler invocationHandler) { super(invocationHandler); } static { m3 = Class.forName("End typeāSquat?.DP01 XigProcessing mode″Spin.Proxy02 Forceㄦ?Bluff } public final void sell() { try { this.h.invoke(this, m3, null); return; } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } }
2.3 execution process
- Call the sell() method through the proxy object in the test class
- According to the characteristics of polymorphism, the sell() method in the proxy class ($Proxy0) is executed
- The sell() method in the proxy class ($Proxy0) calls the invoke method of the subclass object of the InvocationHandler interface
- The invoke method executes the sell() method in the class to which the real object belongs (Cinema) through reflection
3. CGLib dynamic agent
If the SellTickets interface is not defined, only Cinema (Cinema class) is defined. Obviously, JDK agent cannot be used, because JDK dynamic agent requires that the interface must be defined and represented.
<!-- asm package --><dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>9.0-beta</version></dependency><!-- cglib package --><dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version></dependency>
- UML
3.1 code
- Cinema
public class Cinema implements SellTrickets { @Override public void sell() { System.out.println("Cinema tickets"); }}
- ProxyFactory
public class ProxyFactory implements MethodInterceptor { //Declare the railway station object private cinema station = new cinema(); Public cinema getproxyobject() {/ / create an Enhancer object, which is similar to the Proxy class Enhancer = new Enhancer(); / / set the bytecode object of the parent class. Specify the parent class enhancer.setSuperclass(Cinema.class); / / set the callback function enhancer.setCallback(this) ; // Create Proxy object cinema proxyobject = (Cinema) Enhancer create(); return proxyObject; } Public object intercept (object o, method, method, object [] objects, methodproxy, methodproxy) throws throwable {/ / System.out.println("method executed"); System.out.println("CGLib Proxy"); / / the method of the target object to be called object obj = method.invoke (station, objects); return obj;}}
- Test class
public class Client { public static void main(String[] args) { //Create proxy factory object ProxyFactory factory = new ProxyFactory(); //Get proxy object Cinema proxyObject = factory.getProxyObject(); //Call the sell method in the proxy object to sell tickets proxyObject.sell(); } } Earned price difference for sale(CGLib agent) Cinema tickets
4. Comparison of three agents
4.1 comparison
- jdk agent and CGLIB agent
- CGLib is used to realize dynamic proxy. The bottom layer of CGLib adopts ASM bytecode generation framework and bytecode technology to generate proxy classes. In jdk1 Before 6, it was more efficient than using Java reflection. The only thing to note is that CGLib cannot delegate classes or methods declared as final, because the principle of CGLib is to dynamically generate subclasses of the delegated class.
- In jdk1 6,JDK1.7,JDK1.8 after gradually optimizing the JDK dynamic agent, the efficiency of JDK agent is higher than that of cglib agent under the condition of less calls. Only when a large number of calls are made, jdk1 6 and jdk1 7 is a little less efficient than cglib agent, but to jdk1 8, the efficiency of JDK agent is higher than that of cglib agent. Therefore, if there is an interface, use JDK dynamic proxy, and if there is no interface, use cglib proxy.
- Dynamic agent and static agent
- Compared with static proxy, the biggest advantage of dynamic proxy is that all methods declared in the interface are transferred to a centralized method of the calling processor (InvocationHandler.invoke). In this way, when there are a large number of interface methods, we can handle them flexibly without transferring each method like a static agent.
- If a method is added to the interface, all proxy classes need to implement this method in addition to all implementation classes in the static proxy mode. It increases the complexity of code maintenance. Dynamic agents do not have this problem
4.2 advantages and disadvantages
4.2.1 advantages
- Proxy mode plays an intermediary role between the client and the target object and protects the target object;
- The proxy object can extend the function of the target object;
- The proxy mode can separate the client from the target object and reduce the coupling degree of the system to a certain extent;
4.2.2 disadvantages
- It increases the complexity of the system;
4.3 usage scenarios
- Remote agent
- Virtual processing
- Protection agent
- Firewall agent