Proxy mode is a common Java design pattern, it is characterized by proxy class and delegate class have the same interface, Agent class is mainly responsible for the delegation class preprocessing messages, filtering messages, forwarding messages to the delegate class, and afterwards processing messages. There is usually an association between a proxy class and a delegate class, 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 rather provides a specific service by invoking the methods associated with the object of the delegate class.
Comparison of various dynamic proxy implementations in Java
Interface
interface addinterface{
int Add (int a, int b);
}
Interface subinterface{
int sub (int a, int b);
}
Implementation class
Class arithmetic implements AddInterface, subinterface{
@Override public
int sub (int a, int b) {return a
b;
}
@Override public
int Add (int a, int b) {return
a+b;
}
}
Mode 1: Dynamic Proxy with JDK
1. Implementation mode
The dynamic proxy mechanism introduced by Java after JDK1.3 enables us to create proxy classes dynamically during runtime. Using dynamic proxies to implement AOP requires four roles: the proxy class, the interface of the proxy class, the Loom, and the Invocationhandler, and the loom uses the interface reflection mechanism to generate a proxy class and then weave the code into the proxy class. The proxy class is the target of AOP, Invocationhandler is the slice, it contains the advice and pointcut.
2, the implementation of Vinvocationhandler interface
Class Jdkdpqueryhandler implements invocationhandler{
private arithmetic real;
Public Jdkdpqueryhandler (arithmetic real) {
this.real = real;
}
@Override Public
object Invoke (Object proxy, Method method, object[] args) throws Throwable {
String methodname = Method.getname ();
System.out.println (method);
System.out.println ("The method:" + methodname + "Start, Parameters:" +arrays.aslist (args));
Object result = Method.invoke (real, args);
System.out.println ("The Method:" +methodname+ "End, Results:" + result);
return result;
}
3. Create proxy class and Invoke proxy class
public class main{
private static int a = 4, b = 2;
public static object Createjdkproxy (arithmetic real) {
Object proxyarithmetic = proxy.newproxyinstance ( Real.getclass (). getClassLoader (),
Real.getclass (), Getinterfaces (), New Jdkdpqueryhandler (real);
return proxyarithmetic;
}
public static void Main (string[] args) {
arithmetic real = new Arithmetic ();
Object proxyarithmetic = Createjdkproxy (real);
((AddInterface) proxyarithmetic). Add (A, b);
((subinterface) proxyarithmetic). Sub (A, b);
}
}
Mode 2: Dynamic byte code generation (Cglib)
1. Implementation mode
Enhancer and Methodinterceptor. Enhancer can be used to dynamically generate a class that can inherit a specified class and implement some of the specified interfaces. At the same time, enhancer needs to specify a callback before generating a class, and when the class method is called, the execution of the method is assigned to the Callback,methodinterceptor is a more inherited from the callback interface, It has only one method declaration.
2, Interface Invocationhandler (JDK) and interface Methodinterceptor (CGLIB) contrast
Public interface Methodinterceptor extends Callback {public
object intercept (object obj, Java.lang.reflect.Method Method, object[] Args,methodproxy proxy) throws Throwable;
}
Public interface Invocationhandler {public
object Invoke (Object proxy, Method method, object[] args) throws Throwable ;
}
From the composition of the parameters, Methodinterceptor input parameters than invocationhandler one, in fact, the first 3 parameter objects and the meaning of the invocationhandler is the same.
The first parameter represents which object the calling method comes from;
The second parameter represents the method object that invokes the methods;
The third parameter represents the input parameter list for this call;
The extra parameter is the Methodproxy type, it should be an object that Cglib generates to replace the method object, and it is more efficient to use methodproxy than to invoke the JDK itself to execute methods directly.
3, Achieve 1
Implementation of Methodinterceptor interface
Class Cglibdpqueryinterceptor implements methodinterceptor{
private arithmetic real;
Public cglibdpqueryinterceptor (arithmetic real) {
this.real = real;
}
@Override Public
Object Intercept (object target, Method method, object[] args, Methodproxy proxy) throws Throwable {
string methodname = Method.getname ();
System.out.println (method);
System.out.println ("The method:" + methodname + "Start, Parameters:" +arrays.aslist (args));
Object result = Method.invoke (real, args);//Two ways you can get object result
= Proxy.invoke (real, args);
System.out.println ("The Method:" +methodname+ "End, Results:" + result);
return result;
}
To create a proxy class and invoke the proxy class
public class main{
private static int a = 4, b = 2;
public static Object Createcglibproxy (arithmetic real) {
enhancer enhancer = new enhancer ();
Enhancer.setcallback (new Cglibdpqueryinterceptor (real));
Enhancer.setinterfaces (Real.getclass (). Getinterfaces ());
return Enhancer.create ();
}
public static void Main (string[] args) {
arithmetic real = new Arithmetic ();
Object proxyarithmetic = Createcglibproxy (real);
((AddInterface) proxyarithmetic). Add (A, b);
((subinterface) proxyarithmetic). Sub (A, b);
}
}
Note that Methodproxy provides 2 methods for executing a function
public object invoke (Object obj, object[] args) throws throwable the public
object Invokesuper (Object obj, object[) args ) throws Throwable
In which, Javadoc says that the Invoke () method can be used to execute methods of other objects in the same class, that is, obj in this method needs to pass in another object of one of the same classes (the above method is to pass in the different objects of the arithmetic class). Otherwise, you will enter an infinite recursive loop (stackoverflowerror after the test). Think carefully and you will find that the target in the public object intercept (object target, Method method, object[] args, Methodproxy proxy) is the proxy class object that is implemented. Invoking the Add () method via target triggers The Intercept () method to be invoked, and if Method.invoke (target, args) is called again in The Intercept () method, the Add () method is called in the Add () method. leads to infinite recursive loops. However, if the execution of Method.invoke (real, args) is not, because the true and target are different objects of the same class, really is the actual logical theme, and target is the agent of real subject.
Here's an example to simulate:
Interface solveinterface{
void Solve ();
}
Class Real implements solveinterface{public
void Solve () {
System.out.println (' real solve! ');
}
Class Target extends real{
private Object obj;
public void SetObject (Object obj) {
this.obj = obj;
}
private void Invoke () {
try {method method
= SolveInterface.class.getMethod ("Solve", new class[]{});
Method.invoke (obj, new class[]{});
catch (Exception e) {
e.printstacktrace ();
}
}
public void Solve () {
System.out.println ("Target solve!");
Invoke ();
}
public class Main{public static void Main (string[] args) throws exception{
target target = new target ();
Target.setobject (new Real ());//correct
//target.setobject (target); loop call
target.solve ();
}
}
In fact, the Invoke () method of methods invokes the corresponding solve () method, which is polymorphism, according to the type of obj.
4, Achieve 2
Implementation of Methodinterceptor interface
Class Cglibdpqueryinterceptor implements methodinterceptor{
@Override public
object Intercept (object target, Method method, object[] args, Methodproxy proxy) throws Throwable {
String methodname = Method.getname ();
System.out.println (method);
System.out.println ("The method:" + methodname + "Start, Parameters:" +arrays.aslist (args));
Printing class Information: Target.getclass (); omitting
Object result = Proxy.invokesuper (target, args);
System.out.println ("The Method:" +methodname+ "End, Results:" + result);
return result;
}
To create a proxy class and invoke the proxy class
public class main{
private static int a = 4, b = 2;
public static Object Createcglibproxy () {
enhancer enhancer = new enhancer ();
Enhancer.setcallback (New Cglibdpqueryinterceptor ());
Enhancer.setsuperclass (arithmetic.class);
return Enhancer.create ();
}
public static void Main (string[] args) {
arithmetic real = new Arithmetic ();
Object proxyarithmetic = Createcglibproxy ();
((AddInterface) proxyarithmetic). Add (A, b);
((subinterface) proxyarithmetic). Sub (A, b);
}
}
Note that implementation 2 Enhancer does not have an interface set, because the superclass is set (that is, the parent class of the proxy class is arithmetic), and our proxy class inherits it, and arithmetic has implemented our interface. To prove this, you can print the class information of Target.getclass () in the Methodinterceptor intercept method, and you will find that the parent class of the proxy class is different for the Cglib two ways. As follows:
Implementation 1:
public class com.test.arithmetic$ $EnhancerByCGLIB $$4fa786eb extends Java.lang.Object
Implementation 2:
public class com.test.arithmetic$ $EnhancerByCGLIB $$4fa786eb extends Com.test.Arithmetic
Mode 3: javassist Generate dynamic proxies (Agent factory creation or dynamic code creation)
Javassist is a framework for editing bytecode that allows you to manipulate bytecode very simply. It can define or modify class at run time. The principle of using javassist to implement AOP is to modify the method that needs to be cut directly before bytecode loading. This is more efficient than using cglib to implement AOP, and there are not too many limitations, the principle of implementation is as follows:
Implementation 1:
Implementation of the interface
Class Javassistdpqueryhandler implements methodhandler{
@Override public
object Invoke (object target, method method, method Proxy, object[] args throws Throwable {
String methodname = Method.getname ();
System.out.println (method);
System.out.println ("The method:" + methodname + "Start, Parameters:" +arrays.aslist (args));
Object result = Proxy.invoke (target, args);
System.out.println ("The Method:" +methodname+ "End, Results:" + result);
return result;
}
To create a proxy class and invoke the proxy class
public class main{
private static int a = 4, b = 2;
public static Object Createjavassistproxy () throws exception{
proxyfactory factory = new Proxyfactory ();
Factory.setsuperclass (arithmetic.class);
Factory.sethandler (New Javassistdpqueryhandler ());
Return Factory.createclass (). newinstance ();
public static void Main (string[] args) throws exception{
arithmetic real = new Arithmetic ();
Object proxyarithmetic = Createjavassistproxy ();
((AddInterface) proxyarithmetic). Add (A, b);
((subinterface) proxyarithmetic). Sub (A, b);
}
}
Note: The definition of the Invoke method in the Methodhandler interface is as follows:
public object Invoke (Object target, Method method, method proxy, object[] args)
Method represents an object that invokes methods, which are generated by the proxy class and that are substituted for the means, otherwise, method.invoke (target, args) produces an infinite loop call.
Implementation 2:
Javassist The common agent process using dynamic Java code is slightly different from the method used in the preceding article. Javassist can generate bytecode internally through dynamic Java code. Dynamic proxies created in this way can be very flexible and can even generate business logic at run time.
Custom Interceptor Interface Interface Interceptorhandler {/** * The method that invokes the dynamic proxy object will reflect this method, and you can add the ex post operation similar to AOP in the implementation of this method, and only add the following code in this method body The proxy's method is executed, and the return value is returned to the agent's final return to the program * @param obj Object-Proxy Object * @param method methods to be proxy objects * @param args object[] The parameter of the method of the proxy object * @return The return value after the method of the object is executed * @throws Throwable */Public object invoke (Object obj.
method, object[] args) throws Throwable; }//Interceptor implementation class Interceptorhandlerimpl implements interceptorhandler{@Override public object Invoke (object obj, Me
Thod method, object[] args) throws Throwable {String methodname = Method.getname ();
System.out.println (method);
System.out.println ("The method:" + methodname + "Start, Parameters:" +arrays.aslist (args));
Object result = Method.invoke (obj, args);
System.out.println ("The Method:" +methodname+ "End, Results:" + result);
return result;
The class Myproxyimpl {/** dynamic proxy class name suffix */private final static String Proxy_class_name_suffix = "$MyProxy _"; /**Interceptor Interface */private final static String Interceptor_handler_interface = "Com.test.InterceptorHandler";
/** the class name index of the dynamic proxy class to prevent class name repetition * * private static int proxyclassindex = 1; /** * Exposed to the user's dynamic proxy interface, return an interface of the dynamic proxy object, note that this proxy implementation needs and Com.cuishen.myAop.InterceptorHandler interceptor with the * use, that is, users want to use this dynamic agent, you need to realize the first com.cuish En.myAop.InterceptorHandler Interceptor Interface * @param interfaceclassname String the interface class name to be dynamically proxied, e.g test. Studentinfoservice * @param classtoproxy String The class name of the implementation class for the interface to be dynamically proxied, e.g test. Studentinfoserviceimpl * @param interceptorhandlerimplclassname String User-supplied Interceptor interface class name of the implementation class * @return Object returns the dynamic of an interface State proxy Object * @throws instantiationexception * @throws illegalaccessexception * @throws notfoundexception * @thr
oWS cannotcompileexception * @throws classnotfoundexception * @see Com.cuishen.myAop.InterceptorHandler * * public static Object newproxyinstance (String interfaceclassname, String classtoproxy, String Interceptorhandlerimplclassname) throws Instantiationexception, IllEgalaccessexception, Notfoundexception, Cannotcompileexception, classnotfoundexception {class InterfaceClass = Class
. forname (Interfaceclassname);
Class Interceptorhandlerimplclass = Class.forName (interceptorhandlerimplclassname);
Return Dynamicimplementsinterface (Classtoproxy, Interfaceclass, Interceptorhandlerimplclass); /** * Dynamically implements the interface to proxy * @param classtoproxy String The class name of the implementation class of the interface to be dynamically proxied, e.g test. Studentinfoserviceimpl * @param Interfaceclass class to dynamically proxy interface classes, e.g test. Studentinfoservice * @param interceptorhandlerimplclass class User-provided implementation classes for interceptor interfaces * @return object returns a dynamic proxy object for an interface * @throws notfoundexception * @throws cannotcompileexception * @throws instantiationexception * @throws Illegala Ccessexception */private static Object Dynamicimplementsinterface (String Classtoproxy, class Interfaceclass, class Interceptorhandlerimplclass) throws Notfoundexception, Cannotcompileexception, Instantiationexception, Illegalaccessexception {classpool cp = Classpool.getdefault ();
String InterfaceName = Interfaceclass.getname ();
dynamically specifies the class name of the proxy class String proxyclassname = InterfaceName + Proxy_class_name_suffix + proxyclassindex++;
The package name + interface name String Interfacenamepath = InterfaceName of the interface to be implemented;
Ctclass ctinterface = Cp.getctclass (Interfacenamepath);
Ctclass cc = Cp.makeclass (proxyclassname);
Cc.addinterface (Ctinterface);
method [] Methods = Interfaceclass.getmethods ();
for (int i = 0; i < Methods.length i++) {Method method = Methods[i];
Dynamicimplementsmethodsfrominterface (Classtoproxy, Cc, method, Interceptorhandlerimplclass, i);
Return (Object) Cc.toclass (). newinstance (); /** * Dynamic implementation of the method in the interface * @param classtoproxy String The class name of the implementation class of the interface to be dynamically proxied, e.g test. Studentinfoserviceimpl * @param implementer ctclass Dynamic proxy class Packaging * @param Methodtoimpl method Dynamic proxy class The wrapper for the interface methods to implement * @param interceptorclass class User-provided interceptor implementation classes * @param methOdindex int the method to implement the index * @throws cannotcompileexception * * private static void Dynamicimplementsmethodsfrominter Face (String classtoproxy, Ctclass Implementer, Method Methodtoimpl, Class interceptorclass, int methodindex) throws Canno tcompileexception {String Methodcode = Generatemethodcode (Classtoproxy, Methodtoimpl, Interceptorclass, MethodIndex)
;
Ctmethod cm = Ctnewmethod.make (methodcode, implementer);
Implementer.addmethod (CM); /** * Dynamic assembly method body, of course, the implementation of the method inside the agent is not a simple method copy, but the reflection calls the interceptor invoke method, and will receive the parameters passed * @param classtoproxy String to dynamically proxy The class name of the implementation class for the interface, e.g test.
Studentinfoserviceimpl * @param Methodtoimpl method The package of interface methods to implement in Dynamic proxy class * @param the Interceptor implementation class provided by the Interceptorclass class user * @param methodindex int An index of the method to be implemented * @return string of the method that is dynamically assembled by String */private static string Generatemethodcod E (String classtoproxy, Method Methodtoimpl, Class interceptorclass, int methodindex) {String methodname = Methodtoim
Pl.getname (); String MeThodreturntype = Methodtoimpl.getreturntype (). GetName ();
class[] Parameters = Methodtoimpl.getparametertypes ();
class[] Exceptiontypes = Methodtoimpl.getexceptiontypes ();
StringBuffer exceptionbuffer = new StringBuffer ();
Exception Declaration of assembly method if (Exceptiontypes.length > 0) exceptionbuffer.append ("throws"); for (int i = 0; i < exceptiontypes.length i++) {if (I!= exceptiontypes.length-1) exceptionbuffer.append (excep
Tiontypes[i].getname ()). Append (",");
Else Exceptionbuffer.append (Exceptiontypes[i].getname ());
} stringbuffer Parameterbuffer = new StringBuffer ();
The parameter list for the assembly method for (int i = 0; i < parameters.length i++) {Class parameter = Parameters[i];
String parametertype = Parameter.getname ();
Variable name for dynamically specifying method parameters String RefName = "a" + I;
if (i!= parameters.length-1) parameterbuffer.append (parametertype). Append ("" + RefName). Append (","); else Parameterbuffer.append (parametertyPE). Append ("" + refName);
} stringbuffer methoddeclare = new StringBuffer (); The method declaration, because it is the method that implements the interface, is public methoddeclare.append ("public"). Append (Methodreturntype). Append (""). Append (
methodname). Append ("("). Append (Parameterbuffer). Append (")"). Append (Exceptionbuffer). Append ("{\ n");
String interceptorimplname = Interceptorclass.getname (); Method Body Methoddeclare.append (Interceptor_handler_interface). Append ("interceptor = new"). Append (Interceptorimplname)
. Append ("(); \ n"); Reflection invokes the user's Interceptor Interface methoddeclare.append ("Object returnobj = Interceptor.invoke (Class.forName (\" + classtoproxy + "\"). NE
Winstance (), Class.forName (\ "" + Classtoproxy + "\"). GetMethods () ["+ Methodindex +"], ");
The parameter if (Parameters.length > 0) methoddeclare.append ("New object[]{") in the transfer method; for (int i = 0; i < parameters.length i++) {//($W) converts from a primitive type to the corresponding wrapper
type:e.g.
Integer i = ($w) 5; if (i!= parameters.length-1) Methoddeclare.append ("($w) a" + i + ",");
Else Methoddeclare.append ("($w) a" + i);
if (Parameters.length > 0) methoddeclare.append ("}); \ n");
else Methoddeclare.append ("null); \ n"); Wraps the return value of the calling interceptor if (Methodtoimpl.getreturntype (). Isprimitive ()) {if (Methodtoimpl.getreturntype (). Equals (Boole An.
TYPE)) Methoddeclare.append ("Return ((Boolean) returnobj). Booleanvalue (); \ n"); else if (Methodtoimpl.getreturntype (). Equals (Integer.type)) Methoddeclare.append ("Return" ((Integer) returnobj).
Intvalue (); \ n "); else if (Methodtoimpl.getreturntype (). Equals (Long.type)) Methoddeclare.append ("Return" ((Long) returnobj). Longvalue (
); \ n "); else if (Methodtoimpl.getreturntype (). Equals (Float.type)) Methoddeclare.append ("Return" ((Float) returnobj).
Floatvalue (); \ n "); else if (Methodtoimpl.getreturntype (). Equals (Double.type)) Methoddeclare.append ("Return (Double) returnobj).
Doublevalue (); \ n "); else if (Methodtoimpl.getreturntype (). Equals (Character.type)) Methoddeclare.append ("Return (Character) returnobj). Charvalue (); \ n"); else if (Methodtoimpl.getreturntype (). Equals (Byte.type)) Methoddeclare.append ("Return" ((Byte) returnobj). Bytevalue (
); \ n "); else if (Methodtoimpl.getreturntype (). Equals (Short.type)) Methoddeclare.append ((short) returnobj).
Shortvalue (); \ n ");
else {methoddeclare.append ("return (" + Methodreturntype + ") returnobj;\n");
} methoddeclare.append ("}");
System.out.println (Methoddeclare.tostring ());
return methoddeclare.tostring (); } public class main{public static void Main (string[] args) throws exception{//corresponding to the interface class name to be implemented by the proxy class, it is necessary to substitute Class name of the class, user-defined Interceptor implementation class class name Object proxyarithmetic = myproxyimpl.newproxyinstance ("Com.test.ArithmeticInterface", "
Com.test.Arithmetic "," Com.test.InterceptorHandlerImpl ");
((Arithmeticinterface) proxyarithmetic). Add (A, b); ((Arithmeticinterface) ProxyarithmeTIC). Sub (A, b);
}
}
Print the code for the dynamic implementation interface as follows:
public int Add (int a0,int A1) {
Com.test.InterceptorHandler interceptor = new Com.test.InterceptorHandlerImpl ();
Object returnobj = Interceptor.invoke (Class.forName ("com.test.Arithmetic"). Newinstance (), Class.forName (" Com.test.Arithmetic "). GetMethods () [0], New object[]{($w) A0, ($w) A1});
Return ((Integer) returnobj). Intvalue ();
public int sub (int a0,int A1) {
Com.test.InterceptorHandler interceptor = new Com.test.InterceptorHandlerImpl ();
Object returnobj = Interceptor.invoke (Class.forName ("com.test.Arithmetic"). Newinstance (), Class.forName (" Com.test.Arithmetic "). GetMethods () [1], New object[]{($w) A0, ($w) A1});
Return ((Integer) returnobj). Intvalue ();
The above is about the dynamic agent implementation mechanism in Java in detail, I hope to help you learn.