Dynamic Agent for Java
Proxy mode
Proxy mode is a common Java design pattern, his characteristic is that the proxy class and the delegate class have the same interface, the proxy class is mainly responsible for the delegate class preprocessing messages, filtering messages, forwarding messages to the delegate class, and post-processing messages. There is usually an association between the proxy class and the delegate class, and the object of a proxy class is associated with an object of a delegate class, and the object of the proxy class does not actually implement the service, but instead provides a specific service by invoking the related method of the object of the delegate class.
The proxy class can be divided into two types according to the agent's creation period.
Static proxy: The source code is generated automatically by the programmer or a specific tool, and then compiled. Before the program runs, the. class file for the proxy classes already exists.
Dynamic Agent: When the program is running, it is created dynamically using the reflection mechanism.
First look at the static proxy:
1.cat.java
Package proxy; /** */Publicinterface car {// View car method publicvoid querycar (); // Modifying car methods Public void Updatecar ();}
2.carimpl.java
Package proxy; /** */Publicclassimplements Car { @Override publicvoid Querycar () { System.out.println ("View Car method ..."); @Override publicvoid Updatecar () { System.out.println ("View Car method ..."); }}
3.carproxy.java
Packageproxy; Public classCarproxyImplementsCar {PrivateCarimpl Carimpl; /*** Override default constructor * *@paramCarimpl*/ Publiccarproxy (Carimpl carimpl) { This. Carimpl =Carimpl; } @Override Public voidQuerycar () {System.out.println ("Before transaction processing"); //the method of invoking the delegate class;Carimpl.querycar (); System.out.println ("After transaction processing"); } @Override Public voidUpdatecar () {System.out.println ("Before transaction processing"); //the method of invoking the delegate class;Carimpl.updatecar (); System.out.println ("After transaction processing"); }}
4.TestCar (Test call Class)
Package proxy; Public class Testcar { publicstaticvoid main (string[] args) { New Carimpl (); New Carproxy (Countimpl); Carproxy.updatecar (); Carproxy.querycar (); }}
Observation code can find that each proxy class can only serve one interface, so that the development of the program will inevitably generate too many agents, and all the agent operation in addition to the method called, the other operations are the same, then it must be duplicated code. The best way to solve this problem is to complete the proxy function through a proxy class, which must be done using dynamic proxy.
Let's take a look at the dynamic proxy:
The JDK dynamic agent contains a class and an interface:
Invocationhandler Interface:
Public interface Invocationhandler {
public object Invoke (Object Proxy,method method,object[] args) throws Throwable;
}
Parameter description:
Object proxy: Refers to the objects being proxied.
Method: Methods to invoke
object[] args: Parameters required for method invocation
The subclass of the Invocationhandler interface can be imagined as a proxy's final operation class, replacing the Proxysubject.
Proxy class:
The proxy class is an action class that specifically completes the proxy, which can be used to dynamically generate an implementation class for one or more interfaces, which provides the following operations:
public static Object newproxyinstance (ClassLoader loader, class<?>[] interfaces,
Invocationhandler h) throws IllegalArgumentException
Parameter description:
ClassLoader Loader: Class loader
Class<?>[] Interfaces: Get all the interfaces
Invocationhandler h: Get subclass instance of Invocationhandler interface
Ps: Class Loader
In the proxy class in the Newproxyinstance () method requires an instance of the ClassLoader class, ClassLoader actually corresponds to the class loader, in Java, there are three kinds of loaders;
Booststrap ClassLoader: This loader is written in C + + and is not visible in general development;
Extendsion ClassLoader: Used to load the extension class, generally corresponding to the class in the Jre\lib\ext directory;
Appclassloader: (default) Loads the class specified by Classpath, which is most commonly used as an loader.
Dynamic Agent
Compared with the static proxy class, dynamic proxy class, the bytecode of dynamic proxy class is generated dynamically by the Java reflection mechanism when the program runs, without the programmer writing its source code manually. The dynamic proxy class not only simplifies programming, but also improves the scalability of the software system, because the Java reflection mechanism can generate any type of dynamic proxy class. The proxy class and the Invocationhandler interface in the Java.lang.reflect package provide the ability to generate dynamic proxy classes.
Dynamic Proxy Example:
1.Animal
Package Axny; /** */Publicinterface Animal {publicvoid Addanimal ();}
2.AnimalImpl
Package Axny; /** */Publicclassimplements Animal { @Override publicvoid addanimal () { System.out.println ("Increase animal methods ... "); }}
3.AnimalProxy
PackageAxny;ImportJava.lang.reflect.InvocationHandler;ImportJava.lang.reflect.Method;ImportJava.lang.reflect.Proxy;/*** proxy class*/ Public classAnimalproxyImplementsInvocationhandler {PrivateObject Target; /*** Bind the delegate object and return a proxy class *@paramTarget *@return */ Publicobject bind (object target) { This. target =Target; //Get proxy Object returnproxy.newproxyinstance (Target.getclass (). getClassLoader (), Target.getclass (). Getinterfaces (), This); } @Override PublicObject Invoke (Object proxy, Method method, object[] args)throwsthrowable {Object result=NULL; System.out.println ("Transaction Start"); //Execution Methodresult =Method.invoke (target, args); System.out.println ("End of Transaction"); returnresult; }}
4.AnimalTest
Package Axny; Public class animaltest { publicstaticvoid main (string[] args) { new animalproxy (); = (Animal) proxy.bind (new Animalimpl ()); Animalproxy.addanimal (); }}
Output:
Things start
Increase the animal method ...
The end of Things
However, the dynamic proxy of the JDK relies on the interface, and if some classes do not implement the interface, then the JDK proxy cannot be used, which will use the Cglib dynamic proxy.
Cglib Dynamic Agent
The dynamic agent mechanism of JDK can only implement the class of the interface, and the class that cannot implement the interface cannot implement the dynamic proxy of the JDK, the cglib is to implement the proxy for the class, his principle is to generate a subclass for the target class, and overwrite the method implementation enhancement, but because inherit is adopted, Therefore, the final decorated class cannot be proxied.
Example:
1.animalproxycglib.java
PackageCG;ImportJava.lang.reflect.Method;ImportNet.sf.cglib.proxy.Enhancer;ImportNet.sf.cglib.proxy.MethodInterceptor;ImportNet.sf.cglib.proxy.MethodProxy;/*** Use cglib dynamic agent * *@authorStudent **/ Public classAnimalproxycglibImplementsMethodinterceptor {PrivateObject Target; /*** Create proxy Object * *@paramTarget *@return */ Publicobject GetInstance (object target) { This. target =Target; Enhancer Enhancer=Newenhancer (); Enhancer.setsuperclass ( This. Target.getclass ()); //callback MethodEnhancer.setcallback ( This); //Create a proxy object returnenhancer.create (); } @Override//callback Method PublicObject Intercept (Object obj, Method method, object[] args, methodproxy proxy)throwsthrowable {System.out.println ("Things start."); Proxy.invokesuper (obj, args); System.out.println ("The end of things."); return NULL; }}
2.testcglib.java
Package CG; Import Axny. Animalimpl; Public class Testcglib { publicstaticvoid main (string[] args) { Animalproxycglib cglib=new animalproxycglib (); Animalimpl bookcglib= (Animalimpl) cglib.getinstance (new Animalimpl ()); Bookcglib.addanimal (); }}
The output is the same:
Things start
Increase the animal method ...
The end of Things
Difference:
First, from the number of files, Cglib is less than the JDK implementation of an interface class. Because the proxy object returned by Cglib is a subclass of the target object. Both the proxy object and the target object generated by the JDK implement a common interface.
Dynamic Agent:
dynamic agents are divided into two types: * JDK Dynamic proxy * proxy object and target object implement common interface * Interceptor must implement Invocationhanlder interface * cglib Dynamic proxy * Proxy object is a subclass of the target object * Interceptors must implement Methodinterceptor interface * Session.load in Hibernate is implemented by Cglib
Java Dynamic Agents (JDK and Cglib)