First, what is the dynamic agent?
recommended to see dynamic agent before the first look at the reflection click here
First look at a small case, assuming there is a coffee class a,b,c. There is additive class a,b,c,. The coffee class is now enhanced. (like adding sugar to the brown, milk, etc.).
There are three ways to enhance a class:
1. Inheritance, you can directly inherit the properties and methods of the parent class, adding your own properties and methods. So we have to enhance each kind of coffee, a total need to write 3*3 inheritance class to complete. The enhanced objects and content are immutable.
2. Decorator mode, combine a property that needs to be enhanced in a class that needs to be enhanced. Then we need to write three combinations of coffee classes, each of which adds an add-on interface attribute, and different implementations of the add-on interface can be used to enhance the coffee class. The enhanced content is mutable, but the enhanced object is immutable.
3. Dynamic agents, through an agent factory, to the need to enhance the coffee class and add class, which automatically generated an enhanced proxy class. We just need to implement the Proxy factory class.
Second, the implementation of dynamic Java Agent
There is a class proxy in Java, which has a static method object proxy = Proxy.newproxyinstance (ClassLoader ClassLoader, class[] interfaces, Invocationhandler); A proxy object can be obtained by this method. Let's take a look at these three parameters.
The ClassLoader class loader, which is responsible for loading the agent's ClassLoader. For more information about class loader click here
Class[] The interface that the target class implements is represented by an array of class objects.
The Invocationhandler processor, when invoking the proxy class, is actually called the Invoke () method of the processor. The following is an explanation of the Invoke method.
Object Invoke (Object proxy, Method method, object[] args);
Proxy: Agent object. Method: The way to execute the proxy object. Args: Arguments passed in when invoking a method of a proxy object.
The following paste code implementation
Target class Interface
Package cn.edu; Public Interface Waiter { publicvoid server ();}
Front-facing notification interface
Package cn.edu; Public Interface Advicebefore { publicvoid before ();}
Post Notification interface
Package cn.edu; Public Interface Adviceafter { publicvoid after ();}
Agent Factory
Packagecn.edu;ImportJava.lang.reflect.InvocationHandler;ImportJava.lang.reflect.Method;ImportJava.lang.reflect.Proxy;/*** Agent factory for production of proxy objects * *@authorWanghang **/ Public classProxyfactory {PrivateObject Target;//target Object PrivateAdvicebefore Advicebefore;//front-facing notifications PrivateAdviceafter Adviceafter;//Post Notification//build Proxy Object Core method PublicObject getproxyinstance () {ClassLoader loader= Proxyfactory.class. getClassLoader ();//class LoaderClass[] interfaces = Target.getclass (). Getinterfaces ();//interfaces implemented by the classInvocationhandler H=NewInvocationhandler () {//Processor PublicObject Invoke (Object proxy, Method method, object[] args)throwsThrowable {if(Advicebefore! =NULL) {advicebefore.before (); //call a pre-notification} Object result= Method.invoke (target, args);//calling the target method if(Adviceafter! =NULL) {//call the Post notificationAdviceafter.after (); } returnresult; } }; Object Proxy= proxy.newproxyinstance (loader, interfaces, h);//generates a dynamic proxy object with a given three parameters returnProxy//returns the proxy object } PublicAdvicebefore Getadvicebefore () {returnAdvicebefore; } Public voidSetadvicebefore (Advicebefore advicebefore) { This. Advicebefore =Advicebefore; } PublicAdviceafter Getadviceafter () {returnAdviceafter; } Public voidSetadviceafter (Adviceafter adviceafter) { This. Adviceafter =Adviceafter; } PublicObject Gettarget () {returnTarget; } Public voidsettarget (Object target) { This. target =Target; }}
Anonymous inner class for testing, implementation of interfaces
Packagecn.edu;Importorg.junit.Test; Public classproxytest {@Test Public voidFun () {Waiter Waiter=NewWaiter () {//Build target Object@Override Public voidServer () {System.out.println ("In the service ... "); } }; Advicebefore before=NewAdvicebefore () {//generate a pre-notification@Override Public voidbefore () {System.out.println ("Welcome to visit!" "); } }; Adviceafter After=NewAdviceafter () {@Override Public voidAfter () {System.out.println ("Thank you for coming!");//generate a post-notification } }; Proxyfactory proxyfactory=NewProxyfactory ();//Build FactoryProxyfactory.settarget (Waiter); //set the target objectProxyfactory.setadvicebefore (before);//set up a pre-notificationProxyfactory.setadviceafter (after);//set up post notificationsWaiter Proxy= (waiter) proxyfactory.getproxyinstance ();//Get proxy ObjectProxy.server (); //methods to invoke the target object } }
Operation Result:
Third, the implementation of Cglib dynamic agent
the implementation of the Java Dynamic Agent requires the target class to implement the interface, and the dynamic proxy cannot be completed without an interface. Cglib Code Genaration Liarbry is a powerful code generation class library that can extend Java classes while the program is running. It does not require the target class to implement the interface, it takes an inherited approach to extend the target class.
The following with Cglib implementation agent, the rest of the class does not change, just change the agent factory, and to waiter add an implementation class Waiterimpl,cglib Proxy is required class, with anonymous class will be error . The parts of the change are as follows.
Waiter Implementation Class
Package Cn.edu.cglibProxy; Public class Implements Waiter { @Override publicvoid server () { // TODO auto-generated Method Stub System.out.println ("in service ... "); }}
Agent Factory class
PackageCn.edu.cglibProxy;ImportJava.lang.reflect.Method;ImportOrg.springframework.cglib.proxy.Enhancer;ImportOrg.springframework.cglib.proxy.MethodInterceptor;ImportOrg.springframework.cglib.proxy.MethodProxy;/*** Agent factory for production of proxy objects * *@authorWanghang **/ Public classProxyfactory {PrivateObject Target;//target Object PrivateAdvicebefore Advicebefore;//front-facing notifications PrivateAdviceafter Adviceafter;//Post Notification//build Proxy Object Core method PublicObject getproxyinstance () {Enhancer enhancer=Newenhancer (); Enhancer.setsuperclass (Target.getclass ()); Enhancer.setcallback (NewMethodinterceptor () {@Override PublicObject Intercept (Object proxy, method, object[] args, Methodproxy methodproxy)throwsthrowable {advicebefore.before (); Object result=Method.invoke (target, args); Adviceafter.after (); returnresult; } }); Object Proxy=enhancer.create (); returnProxy//returns the proxy object } PublicAdvicebefore Getadvicebefore () {returnAdvicebefore; } Public voidSetadvicebefore (Advicebefore advicebefore) { This. Advicebefore =Advicebefore; } PublicAdviceafter Getadviceafter () {returnAdviceafter; } Public voidSetadviceafter (Adviceafter adviceafter) { This. Adviceafter =Adviceafter; } PublicObject Gettarget () {returnTarget; } Public voidsettarget (Object target) { This. target =Target; }}
Test class
PackageCn.edu.cglibProxy;Importorg.junit.Test; Public classproxytest {@Test Public voidFun () {Waiter Waiter=NewWaiterimpl (); Advicebefore before=NewAdvicebefore () {//generate a pre-notification@Override Public voidbefore () {System.out.println ("Welcome to visit!" "); } }; Adviceafter After=NewAdviceafter () {@Override Public voidAfter () {System.out.println ("Thank you for coming!");//generate a post-notification } }; Proxyfactory proxyfactory=NewProxyfactory ();//Build FactoryProxyfactory.settarget (Waiter); //set the target objectProxyfactory.setadvicebefore (before);//set up a pre-notificationProxyfactory.setadviceafter (after);//set up post notificationsWaiter Proxy= (waiter) proxyfactory.getproxyinstance ();//Get proxy ObjectProxy.server (); //methods to invoke the target object } }
Test results
Iv. Summary
Through the above two examples, you can realize the advantages of dynamic agents. Static proxy is written by the programmer manually Good source code, the program is running when the class file already exists, and dynamic agent is at run time as needed to dynamically generate, not only reduce the workload, use more flexible.
Java Dynamic agent and Cglib dynamic agent