code example
In the Java Native API, there are two APIs commonly used by dynamic agents: Invocationhandler interface and proxy class
First on the Code Staffloggeraspect.java
public class StaffLoggerAspect implements InvocationHandler { Object target; public Object getObject(Object object) { target = object; return Proxy.newProxyInstance(Staff.class.getClassLoader(), Staff.class.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(proxy.getClass().getName()); return method.invoke(target, args); }}
Main method of main class
public static void main(String[] args) { StaffLoggerAspect aspect = new StaffLoggerAspect(); Staff staff1 = new Staff(); staff1.setName(""); System.out.println(staff1); Object staff2 = aspect.getObject(staff1); System.out.println(staff2);}
Output results
Staff{name=‘‘, age=0}com.sun.proxy.$Proxy0Staff{name=‘‘, age=0}
Precautions
First to explain the GetObject method, many online tutorials have some kind of function to do similar things, this function is used to return a proxy object implemented the same interface of the proxy object
Note that it returns the proxy object , not the original object. The proxy object is a subclass of the proxy class (API documentation) that implements all interfaces of the Proxied object, so the conversion of this function result must be converted to the corresponding interface type instead of the object type , what about an object without an interface? can only be converted to object objects, of course, you can use the Proxy method is only object with Equals, ToString and so on, some object method will not trigger the Invoke method, see the next proxy object features the last. the class name of the proxy object is the reserved class name . See the Java API for the proxy class
Java API Proxy Part original and explanationFeatures of the proxy class
A proxy class has the following properties:
- Proxy classes is public, final, and not abstract. (i.e. non-inheritable)
- The unqualified name of a proxy class is unspecified. The space of class names this begin with the string "$Proxy" should is, however, reserved for Proxy classes. (the Proxy object class name is not explicitly defined, but the class name starting with $proxy is reserved for the proxy object, so if the class name of a class is found to start with $proxy, it must be the proxy object, and the output will be visible)
- A proxy class extends Java.lang.reflect.Proxy. (The proxy object is all subclasses of this class, so you can use instanceof to determine whether it is a proxy object)
- A proxy class implements exactly the interfaces specified at it creation, in the same order. (The interface between the proxy object and the Proxied object is exactly the same, and the order is consistent, what is the order?) In the back of the original document is a section titled Methods duplicated in multiple Proxy Interfaces, which is used to handle multiple interfaces with the same function declaration, not detailed here)
- If a proxy class implements a Non-public interface, then it'll be is defined in the same package as that interface. Otherwise, the package of a proxies class is also unspecified. Note that the package sealing won't prevent a proxy class from being successfully defined in a particular package at Runtim E, and neither would classes already defined by the same class loader and the same package with particular signers. (a good long string, meaning: If the public interface, then the package name is not certain, even the internal interface of the package, the other package can not access, if the agent, then the package will be more than a proxy class.) The latter is not related to the agent, said that the use of reflection dynamic creation of the object, package airtight is not able to resist the Wolf class, completely stop it)
- Since a proxy class implements all of the interfaces specified at it creation, invoking getinterfaces on its class object Would return an array containing the same list of interfaces (with the order specified at its creation), invoking GetMethods On its Class object would return an array of Method objects this include all of the methods in those interfaces, and Invok ing GetMethod'll find methods in the proxy interfaces as would be expected. (Because of some previously mentioned principles, the getinterfaces of the proxy object returns all interfaces of the Proxied object, in the same order, the proxy object's GetMethod returns the methods of those interfaces)
- The Proxy.isproxyclass method would return true if it is passed a Proxy Class–a class returned by Proxy.getproxyclass or T He class of an object returned by Proxy.newproxyinstance–and false otherwise. (proxy object Two ways to get: Proxy.getproxyclass or proxy.newproxyinstance other ways to get the Proxy.isproxyclass will return false)
- The Java.security.ProtectionDomain of a proxy class is the same as, the system classes loaded by the Bootstrap class Lo Ader, such as Java.lang.Object, because the code for a proxy class was generated by trusted system code. This protection domain would typically be granted java.security.AllPermission. (The proxy object has very high permissions, has java.security.AllPermission, and is consistent with Java.lang.Object and other startup objects)
- Each proxy class have one public constructor that takes one argument, an implementation of the interface Invocationhandler, To set the invocation handler for a proxy instance. Rather than have to use the reflection API to access the public constructor, a proxy instance can is also be created by Calling the Proxy.newproxyinstance method, which combines the actions of calling Proxy.getproxyclass with invoking the con Structor with an invocation handler. (The proxy class has a public single-argument constructor that requires the Invocationhandler object as an input parameter)
The characteristics of the proxy object
And the following cast operation would succeed (rather than throwing a classcastexception):
(Foo) proxy
(First of all, to pay attention to the segmentation, English words implemented by the back is easy to get wrong, it should be its proxy class/foo, the overall is this: Given a proxy instance proxy and one of its INTERFA CES, for example Foo, ... Foo is an interface, not an object of the proxy class!!! According to the description of the previous proxy object, this is not difficult to understand itself, it is easy to explain the fact that it is easily mistaken)
Each proxy instance have an associated invocation handler, the one is passed to its constructor. The static Proxy.getinvocationhandler method would return the invocation handler associated with the Proxy instance passed As its argument. (Nonsense, that is, if you want to get the Invocationhandler of a proxy object, call the Proxy.getinvocationhandler method)
An interface method invocation on a proxy instance would be encoded and dispatched to the invocation handler ' s invoke metho D as described in the documentation for that method. (The method call on the proxy object is sent to the Invoke method of the Invocationhandler object associated with it, note that all method calls are forwarded and need to be in invoke to determine if it is the method you are trying to get)
An invocation of the hashcode, Equals, or ToString methods declared in Java.lang.Object on a proxy instance would be encode D and dispatched to the invocation handler's Invoke method in the same manner as interface method invocations is encoded and dispatched, as described above. The declaring class of the Method object passed to invoke'll be java.lang.Object. Other public methods of a proxies instance inherited from Java.lang.Object is not overridden by a proxy class, so Invocatio NS of those methods behave like they does for instances of Java.lang.Object. (Hashcode, Equals, the ToString method will also be forwarded to the proxy object Invocationhandler the Invoke method, the other does not forward!!!) Important!!! Be careful!!! )
Instructions for use
The important part of the document is explained, and there are some practical ways to use it, including the way of thinking.
At first I saw that the target set in the GetObject is not a proxy object a little turn, in fact, to think clearly, the process is this:
- You get a proxy object outside of an agent, not an object of the original type, so return is a proxy object so that it can be forwarded when the method of the interface is called.
- It is necessary to store a target here, for what it is, because you want to save the information of the Proxied object. Like the proxy object created at the time completely do not need to be the entity of the proxy object, only the information of its class, but not the Record object itself, the example code of the staff name of the value of a lot of possibilities, we have different staff of the agent, we want to be the proxy object corresponding to the getname will not problem, Then we need a target of the original object to call the corresponding method, so we have to record it, so, usually this target is assigned in GetObject, is used in the Invoke method
- The first parameter of the Invoke method is the proxy object , and do not invoke the proxy object on the Invoke method that can be forwarded , for example, you have processed the ToString, You also invoke the ToString method of the proxy object in the Invoke method (such as implicitly: SYSTEM.OUT.PRINTLN), which is absolutely forbidden! Because you invoke the forward method on the proxy object, it causes the Invoke function to be called again, resulting in a recursive result, and most operating systems have a limit on the number of recursive layers, which can cause serious consequences , so If there is no need to invoke the proxy object method in invoke, but you call SYSTEM.OUT.PRINTLN (target) is safe, because it will be forwarded only proxy object corresponding method, the direct method call of the proxy object is not forwarded!!!
Considerations for using the Java API Dynamic agent simply say here, for the use of method objects and considerations please find the relevant API or tutorial, Cglib Dynamic Agent implementation principle is different, the similarity certainly has, but attention and Java native API dynamic proxy differences ( Java native generates an object of those interfaces directly from the Getinterfaces () by reflection, and is constructed very quickly, regardless of the extends part of the Proxied object, but performs at a low performance because of the need for various forwarding; Cglib directly generates the subclass of the Proxied object by reflection , so it is not available to the final class of proxy, because this class can not be inherited, while the content of the invoke will be written to the generated proxy object, so the generation will be very slow, but this object is directly the object of the same type of proxy objects, after all, is generated by the proxy class subclass, so easy to use, The Proxied object can not require an interface, and the execution method is fast. Because the principle difference is big, cglib certainly also has other Java API different characteristics, the author temporarily did not have the time to study the characteristics of cglib, not in detail. On the selection, for the singleton pattern of the object, or compared to the number of object method calls, the number of construction of the object is proposed with Cglib, for the need for a large number of constructs (such as a database record, a request object of the network service), The Java Native API is recommended for each object where the method invocation is not a large number of objects.
found that the article is inappropriate, I hope to correct, especially Cglib and Java API comparison part, is from the principle of some inference, not sure, suggest you go to see Cglib related documents.
The author is not easy, reproduced please indicate the source, humbly
Some considerations for using the Java AOP API to accomplish dynamic proxies