One or two kinds of proxy modes: static agent and dynamic agent
Agent mode, basically have subject role, realsubject role, proxy Role. Where: the subject role is responsible for defining the interface that the Realsubject and proxy roles should implement, and the Realsubject role is used to actually complete the business services function, and the proxy role is responsible for invoking the request of itself, calling Realsubject The corresponding request function to achieve business functions, do not really do business.
When this proxy relationship is specified in the Code phase, the proxy class is compiled into a class file by the compiler, and the class already exists when the system is running. While this static proxy mode has great advantages in accessing inaccessible resources and enhancing existing interface business functions, the large use of this static proxy will increase the size of the classes within our system and is not easy to maintain, and since the functions of proxy and realsubject are essentially the same, Proxy is only played the role of intermediary, the presence of such agents in the system, resulting in a system structure is more bloated and loose.
In order to solve this problem, there is the idea of dynamically creating a proxy: in the running state, where agents are required, according to subject and realsubject, dynamically create a proxy, after use, will be destroyed, so you can avoid the proxy The class of the character is jumbled up in the System.
Ii. Dynamic agent Requirements: dynamically generate and load class classes
After the Java compiler compiles the Java file, The. class file is generated on Disk. This class file is a binary file, and the content is the machine code that only the JVM virtual machine can recognize. The JVM virtual machine reads the bytecode file, takes out the binary data, loads it into memory, parses the information in The. class file, and generates the corresponding class Object. A class bytecode file is generated based on the bytecode organization rules specified in the JVM virtual machine Specification.
Since the JVM loads the class through the binary information of the bytecode, then, if we are in the Run-time system, Follow the Java compilation system to organize the format and structure of The. class file, generate the corresponding binary data, and then load the binary data into the corresponding class, thus completing the ability to dynamically create a class in the Code. For example, the runtime generates and loads classes dynamically in code by generating bytecode from the CALSS file organization structure and letting the JVM ClassLoader load Execution.
third, dynamic generation of bytecode switch open source Framework: ASM, Javassist
ASM is a Java bytecode manipulation Framework. It can modify existing classes or dynamically generate classes in binary Form. ASM can produce a binary class file directly, or it can dynamically change the class behavior before the class is loaded into the Java virtual Machine. When ASM reads information from a class file, it can change class behavior, parse class information, and even generate new classes based on user Requirements.
However , when ASM creates the class bytecode, the level of manipulation is the assembly instruction level of the underlying jvm, which requires the ASM user to have a certain understanding of the class organization structure and the JVM assembly Instructions.
Javassist is an open source class library for parsing, editing, and creating Java Bytecode. it was created by Shigeru Chiba (thousand Yezi) of the Department of Mathematics and Computer Science at the Tokyo Institute of Technology. It has joined the open source JBoss Application Server project to implement the dynamic AOP framework for JBoss by using javassist to bytecode Operations. Javassist is a sub-project of jboss, its main advantage is simple, and Fast. You can dynamically change the structure of a class or dynamically generate classes by using the Java encoding directly, without needing to know the virtual machine instructions.
Iv. How to implement dynamic agent
If the mode of static proxy is used to generate dynamic proxy class directly by modifying bytecode, it will include too much business code in the process of creation, increase the complexity of dynamically creating proxy class process, and the package is not good, not extensibility and universality, for this reason consider the decomposition of Proxy's duty, The method invocation of the generic real delegate class is implemented by a common interface, which in turn introduces the Invocationhandler Role.
In static proxies, the methods in proxy proxies specify the corresponding methods in the invocation of a particular realsubject: the thing that the proxy does is to invoke the method that triggers the realsubject corresponding to the invocation at different request; more abstract point, The thing that the proxy does; in Java Chinese law (METHOD) is also regarded as an object, the Basic mode of dynamic agent work is to give the Invocationhandler character the realization of its method Function. Outside of the proxy role of each method of the call, the proxy role will be handed to Invocationhandler to handle, and Invocationhandler invoke the method of the specific object Role. As shown in the Following:
In this mode: proxy proxies and realsubject should implement the same functionality (what I say here, which can be understood as the public method of a class).
In object-oriented programming, if we want to agree that proxy and realsubject can achieve the same functionality, there are two ways:
A. A more intuitive way is to define a functional interface, and then have proxies and realsubject to implement this interface .
B. There is also a more obscure way of passing inheritance . Because if proxy inherits from realsubject, so proxy has the function of realsubject, Proxy can also realize polymorphism by rewriting the method in Realsubject.
the mechanism of creating dynamic agents provided in JDK is designed by a, while Cglib is designed by B Idea. ( two modes will eventually dynamically generate the class bytecode and load, where Cglib is directly implemented by invoking the ASM Library.) )
five, JDK Dynamic Agent
Related classes or interfaces:
- Java.lang.reflect.Proxy: This is the main class of the Java Dynamic Agent mechanism, which provides a set of static methods for dynamically generating proxy classes and their objects for a set of Interfaces. Listing 1. static method of Proxy
123456789101112 |
//method 1: This method is used to get the calling processor //method 2: The method is used to obtain the class object associated with the dynamic proxy class for the specified class loader and a set of interfaces static class Getproxyclass (ClassLoader loader, class[] interfaces) //method 3: This method is used to determine whether the specified class object is a dynamic proxy class static boolean isproxyclass (Class cl) //method 4: This method is used to generate a dynamic proxy class instance for the specified class loader, a set of interfaces, and a call processor static Object newproxyinstance ( ClassLoader loader, class[] interfaces, Code class= "htmlscript plain" >invocationhandler h) |
- Java.lang.reflect.InvocationHandler: This is the call processor interface, which customizes an invoke method that centralizes the method invocation on the dynamic proxy class object, typically implementing proxy access to the delegate class in the Method. Listing 2. The core approach of Invocationhandler
123 |
// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象 // 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行 Object invoke(Object proxy, Method method, Object[] args) |
Each time a dynamic proxy class object is generated, you need to specify a call processor object that implements the interface (see the third parameter of Proxy static method 4).
- Java.lang.ClassLoader: This is the class loader class, which is responsible for loading the bytecode of the class into the Java virtual machine (JVM) and defining the class object for it, and then the class can be Used. Proxy static method generating dynamic proxy classes also need to be loaded through a class loader to use, and the only difference from the normal class is that its bytecode is generated dynamically by the JVM at runtime rather than pre-existing in Any. class File.
You need to specify a class loader object each time a dynamic proxy class object is generated (see the first parameter of the proxy static method 4)
The following four steps are Specific:
- Create your own calling processor by implementing the Invocationhandler interface;
- Create a dynamic proxy class by specifying a ClassLoader object and a set of interface for the proxy class;
- The constructor of the dynamic proxy class is obtained through the reflection mechanism, and its unique parameter type is the calling processor interface type;
- Creates an instance of a dynamic proxy class through a constructor that constructs a call to a processor object as a parameter is passed IN.
Listing 3. Dynamic proxy object creation process
123456789101112 |
// Invocationhandlerimpl implements the Invocationhandler interface and can implement method calls from the proxy class to the delegate Class's Dispatch forwarding // The interior typically contains a reference to an instance of the delegate class that is used to actually execute the method call that was forwarded over the invocationhandler handler = new Invocationhandlerimpl (..); //dynamically creates a class object for the proxy class by proxy for a set of interfaces, including the Interface interface class clazz = proxy.getproxyclass (classLoader, new class[] {interface.class, ...}); //get The constructor object from the generated class object by reflection //create A dynamic proxy class instance from a constructor object interface Proxy = (Interface) constructor.newinstance (new object[] {handler}); |
The actual use of the process is more simple, because the static method of Proxy Newproxyinstance has encapsulated steps 2 through 4 of the process, so the simplified process is as follows
Listing 4. Simplified dynamic proxy object creation process
1234567 |
// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发 InvocationHandler handler = new InvocationHandlerImpl(..); // 通过 Proxy 直接创建动态代理类实例 Interface proxy = (Interface)Proxy.newProxyInstance( classLoader, new Class[] { Interface.class }, handler ); |
Now let's look at some of the features of the Java dynamic agent Mechanism.
first, There are some characteristics of the dynamically generated proxy class Itself. 1) package: If the interface being proxied is public, then it will be defined in the top-level package (that is, The package path is empty), if there is a non-public interface in the Proxied interface (because The interface cannot be defined as protect or private, it is the default except Public) Package Access level), Then it will be defined in the packet where the interface is located (assuming that a non-public interface A is represented in the Com.ibm.developerworks package, the package that contains the newly generated proxy class is com.ibm.developerworks), The purpose of this design is to ensure that the dynamic proxy class is not able to be successfully defined and accessed due to the problem of package management; 2) class Modifier: the proxy class has the final and public modifiers, which means that it can be accessed by all classes , but cannot be re-inherited; 3) class name: The format is "$ProxyN", where n is an increment of Arabic numerals, representing the proxy class nth generation of dynamic proxy class, It is worth noting that not every time the static method call proxy to create a dynamic proxy class will increase the N value, The reason is that if you attempt to create a dynamic proxy class repeatedly for the same set of interfaces (including the order of the interfaces), it will be wise to return the class object of the proxy class that was previously created, instead of trying to create a completely new proxy class, which saves unnecessary code duplication and increases the efficiency of the proxy class Creation. 4) class inheritance Relationship: The inheritance relationship of this class
Figure 2. Inheritance diagram for dynamic proxy classes
As the diagram shows, the proxy class is its parent class, and this rule applies to all dynamic proxy classes created by Proxy. And the class implements a set of interfaces that it proxies, which is why it can be safely typed to the root cause of an interface it Proxies.
Let's take a look at some of the characteristics of proxy class Instances. Each instance is associated with a calling processor object, which can be getinvocationhandler to get the calling processor object of the proxy class instance through the static method provided by Proxy. When a method declared in the interface of its proxy is invoked on a proxy class instance, these methods will eventually be executed by the Invoke method of the calling processor, in addition, it is worth noting that there are three methods in the root class java.lang.Object of the proxy class that are also dispatched to the calling Processor's invoke Method execution, which are hashcode,equals and toString, may be due to the fact that these methods are public and non-final types, can be overridden by proxy classes, and because these methods tend to present a characteristic attribute of a class with a certain degree of sensitivity, therefore, in order to ensure that the proxy class and the delegation class external consistency, these three methods should also be assigned to the delegate class Execution. When a set of interfaces for an agent has a repeating method and the method is called, the proxy class always gets the method object from the first interface and assigns it to the calling processor, regardless of whether the proxy class instance is externally referenced in the form of that interface (or a sub-interface that inherits from the Interface). Because it is not possible to differentiate its current referenced type within a proxy class.
Let's look at the characteristics of a group of interfaces that are being Proxied. first, be aware that you cannot have duplicate interfaces to avoid compilation errors when the dynamic proxy class code is Generated. second, These interfaces must be visible to the class loader, or the class loader will not be able to link them, causing the class definition to Fail. again, all non-public interfaces that need to be proxied must be in the same package, or the proxy class generation will Fail. finally, the number of interfaces cannot exceed 65535, which is the limit set by the JVM.
finally, let's look at the characteristics of exception handling. From the method that invokes the processor interface declaration, It can be seen theoretically that it can throw any type of exception, because all exceptions are inherited from the Throwable interface, but is it true? The answer is no, because we must obey an inheritance principle: when a subclass overrides a parent or implements a parent interface, the exception thrown must be within the list of exceptions supported by the original METHOD. So while the calling processor is theoretically capable, it is actually often limited unless the method in the parent interface supports throwing Throwable exceptions. So what if the Invoke method does produce an exception that is not supported in the interface method declaration? Rest assured, the Java dynamic proxy class has designed a workaround for us: it will throw a undeclaredthrowableexception Exception. This exception is a runtimeexception type, so it does not cause a compilation Error. With the Exception's getcause method, You can also get the original unsupported exception object for error Diagnosis.
A detailed description of the Java dynamic Agent mechanism (JDK and Cglib,javassist,asm)
Https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html
Java Dynamic Agent