Thoroughly understand the Java dynamic Agent

Source: Internet
Author: User

Proxy design mode

Definition: Provides a proxy for other objects to control access to this object.

The structure of the proxy mode is as shown.

Dynamic Proxy usage

The Java dynamic Agent mechanism implements the design concept of proxy mode in a clever way.

Proxy Mode Sample Code

 public interface Subject {public void dosomething (); 

public class Realsubject implements Subject {public void dosomething () {System.out.pri Ntln ("Call DoSomething ()"); }}

public class Proxyhandler implements Invocationhandler {private Object proxied; Public Proxyhandler (Object proxied) {this.proxied = proxied; public object invoke (object proxy, method, object[] args) throws Throwable {//before the target object is transferred, you can To perform some function to process//transpose a specific target object to the method return Method.invoke (proxied, args); After you have transferred the target object, you can perform some function processing}}
Import Java.lang.reflect.InvocationHandler;   Import Java.lang.reflect.Method;   Import Java.lang.reflect.Proxy;   Import Sun.misc.ProxyGenerator;   Import java.io.*; public class Dynamicproxy {public static void main (String args[]) {realsubject real = new Realsubject        ();      Subject Proxysubject = (Subject) proxy.newproxyinstance (Subject.class.getClassLoader (), New Class[]{subject.class},              New Proxyhandler (real));        Proxysubject.dosomething ();     Write Proxysubject class binary data to File Createproxyclassfile ();       } public static void Createproxyclassfile () {String name = "Proxysubject";       byte[] data = Proxygenerator.generateproxyclass (name, new class[] {subject.class});         try {fileoutputstream out = new FileOutputStream (name + ". Class");         Out.write (data);       Out.close ();       } catch (Exception e) {e.printstacktrace ();   }     }   }
Dynamic agent Internal implementation

First, take a look at the Code of Class proxy to implement the main static variables of proxy

Mapping table: Used to maintain the class loader object to its corresponding proxy class cache private static Map Loadertocache = new Weakhashmap (); Tag: Used to mark a dynamic proxy class being created in private static object Pendinggenerationmarker = new Object (); Synchronization table: Record the type of dynamic proxy class that has been created, mainly by method Isproxyclass to determine the private static Map proxyclasses = Collections.synchronizedmap (new Weakhashmap ()); The associated call processor references protected Invocationhandler h;

The construction method of Proxy

Proxy static method Newproxyinstance

public static Object newproxyinstance (ClassLoader loader, Class<?>[]interfaces,invocationhandler h) throws illegalargumentexception {     //check h is not empty, otherwise throw exception    if (h = = null) {         throw new NullPointerException ();     }     Gets the proxy class type object associated with the specified class loader and a set of interfaces class    CL = Getproxyclass (loader, interfaces);     Gets the constructor object by reflection and generates a proxy class instance    try {         Constructor cons = Cl.getconstructor (constructorparams);         Return (Object) cons.newinstance (new object[] {h});     } catch (Nosuchmethodexception e) {throw new Internalerror (E.tostring ())     } catch (Illegalaccessexception e) {throw n EW Internalerror (e.tostring ());     } catch (Instantiationexception e) {throw new Internalerror (E.tostring ())     } catch (InvocationTargetException e) {th Row New Internalerror (e.tostring ());     } }

The getproxyclass method of class Proxy calls proxygenerator 's generateproxyclass The Proxysubject.class method produces binary data of the binary:

public static byte[] Generateproxyclass (final String name, class[] interfaces)

We can import Sun.misc.ProxyGenerator, call the Generateproxyclass method to produce binary data, and then write to the file, Finally, the Anti-compilation tool is adopted to view the internal implementation principle. newproxyinstance of Proxysubject.java Proxy static method after anti-compilation

Import java.lang.reflect.*;       Public final class Proxysubject extends Proxy implements Subject {private static Method M1;       private static Method M0;       private static Method m3;       private static Method m2;       Public Proxysubject (Invocationhandler Invocationhandler) {super (Invocationhandler); } Public Final Boolean equals (Object obj) {try {return (Boolean) super.h.in           Voke (this, M1, new object[] {obj})). Booleanvalue (); } catch (Error _ex) {} catch (Throwable throwable) {throw new Undeclaredthrowa           Bleexception (Throwable); }} public final int hashcode () {try {return (Integer) Super.h.invoke (this, M0, null)).           Intvalue (); } catch (Error _ex) {} catch (Throwable throwable) {throw new UndeclaredtHrowableexception (Throwable); }} public final void dosomething () {try {Super.h.invoke (this, M3, Nu               ll);           Return } catch (Error _ex) {} catch (Throwable throwable) {throw new Undeclaredthrowa           Bleexception (Throwable); }} public final String toString () {try {return (String) Super.h.invok           E (this, M2, null); } catch (Error _ex) {} catch (Throwable throwable) {throw new Undeclaredthrowa           Bleexception (Throwable); }} static {try {m1 = Class.forName ("Java.lang.Object"). GetMethod ("E               Quals ", new class[] {class.forname (" Java.lang.Object ")});               M0 = Class.forName ("Java.lang.Object"). GetMethod ("Hashcode", new Class[0]); M3 = Class.forName("Subject"). GetMethod ("DoSomething", new Class[0]);           M2 = Class.forName ("Java.lang.Object"). GetMethod ("ToString", new Class[0]); } catch (Nosuchmethodexception nosuchmethodexception) {throw new Nosuchmethoderror (nosuc           Hmethodexception.getmessage ()); } catch (ClassNotFoundException classnotfoundexception) {throw new Noclassdeffounderror (           Classnotfoundexception.getmessage ());   }       }   }

proxygenerator internal is how to generate class binary data, you can refer to the source code.

Private byte[] Generateclassfile () {/* * Record that proxy methods is needed for the hashcode, equals, * and  ToString methods of Java.lang.Object. This is do before * the methods from the proxy interfaces So, the methods from * Java.lang.Object take prece     Dence over duplicate methods in the * Proxy interfaces.     */Addproxymethod (Hashcodemethod, Object.class);     Addproxymethod (Equalsmethod, Object.class);     Addproxymethod (Tostringmethod, Object.class); /* * Now record all of the methods from the proxy interfaces, giving * earlier interfaces precedence over later on     Es with Duplicate * methods.         */for (int i = 0; i < interfaces.length; i++) {method[] methods = Interfaces[i].getmethods ();         for (int j = 0; J < Methods.length; J + +) {Addproxymethod (methods[j], interfaces[i]); }}/* * For each set of proxy methods with the same signature, * Verify that the methods ' return typeS is compatible.     */For (list<proxymethod> sigmethods:proxyMethods.values ()) {checkreturntypes (sigmethods); }/* ============================================================ * Step 2:assemble FieldInfo and MethodInfo Stru     CTS for all of * fields and methods in the class we are generating.         */try {Methods.add (Generateconstructor ()); For (list<proxymethod> sigmethods:proxyMethods.values ()) {for (Proxymethod pm:sigmethods) {// Add static field for method ' s method Object Fields.Add (New FieldInfo (Pm.methodfieldname, "ljava/lang/ref Lect/method; ", Acc_private |           acc_static));       Generate code for Proxy method and add it Methods.add (Pm.generatemethod ());     }} methods.add (Generatestaticinitializer ());     } catch (IOException e) {throw new Internalerror ("Unexpected I/O Exception"); }     /* ============================================================ * Step 3:write the final class file. */* * Make sure constant pool indexes is reserved for the * following items before starting to write th     E final class file.     */Cp.getclass (Dottoslash (className));     Cp.getclass (Superclassname);     for (int i = 0; i < interfaces.length; i++) {Cp.getclass (Dottoslash (Interfaces[i].getname ())); }/* * Disallow new constant Pool additions beyond this point, since * we is about to write the final Constan     T pool table.     */cp.setreadonly ();     Bytearrayoutputstream bout = new Bytearrayoutputstream ();     DataOutputStream dout = new DataOutputStream (bout);         try {/* * Write all the items of the "classfile" structure.         * See JVMS section 4.1.         *///U4 magic;             Dout.writeint (0xCAFEBABE);         U2 minor_version;             Dout.writeshort (classfile_minor_version);         U2 major_version; DoUt.writeshort (classfile_major_version);   Cp.write (dout);         (write constant pool)//U2 access_flags; Dout.writeshort (Acc_public | acc_final |             Acc_super);         U2 This_class;             Dout.writeshort (Cp.getclass (Dottoslash (ClassName)));         U2 Super_class;             Dout.writeshort (Cp.getclass (superclassname));         U2 Interfaces_count;             Dout.writeshort (interfaces.length);         U2 Interfaces[interfaces_count]; for (int i = 0; i < interfaces.length; i++) {Dout.writeshort (Cp.getclass (Dottoslash) (interfaces[i].get         Name ())));         }//U2 fields_count;             Dout.writeshort (Fields.size ());         Field_info Fields[fields_count];         for (FieldInfo f:fields) {f.write (dout);         }//U2 methods_count;             Dout.writeshort (Methods.size ());         Method_info Methods[methods_count]; for (MethodInfo m:methods) {M.WRite (dout);         }//U2 attributes_count; Dout.writeshort (0); (No Classfile attributes for proxy classes)} catch (IOException e) {throw new Internalerror ("Unexpected I     /O Exception ");  } return Bout.tobytearray ();
Summary

A typical dynamic agent creation process can be divided into the following four steps:
1. Create your own call processor by implementing the Invocationhandler interface Ivocationhandler handler = new Invocationhandlerimpl (...);
2. Create a dynamic proxy class by specifying a ClassLoader object and a set of interface for the proxy class
Class clazz = Proxy.getproxyclass (classloader,new class[]{...});
3. Obtain the constructor of the dynamic proxy class through the reflection mechanism, whose parameter type is the calling processor interface type
Constructor Constructor = clazz.getconstructor (New Class[]{invocationhandler.class});
4, create the proxy class instance through the constructor function, at this time the call processor object should be passed as a parameter
Interface Proxy = (Interface) constructor.newinstance (new object[] (handler));
In order to simplify the object creation process, the Newinstance method in the proxy class encapsulates two steps to complete the creation of the proxy object.
The generated proxysubject inherits the proxy class implementation of the subject interface, and the implementation of the subject method actually invokes the handler's Invoke method, whereas the Invoke method uses reflection to invoke the method of the Proxied object (object result= Method.invoke (Proxied,args))

Ointment

Admittedly, theproxy has been designed to be very graceful, but there is a little bit of regret, that is, it has always been unable to get rid of the shackles only support interface Agent, because its design doomed this regret. Recall the inheritance diagram of dynamically generated proxy classes, which are already destined to have a common parent class called proxy. Java's inheritance mechanism is doomed to these dynamic proxy classes can not implement the dynamic proxy class, because the multi-inheritance in Java is inherently unworkable. There are a number of reasons why people can negate the need for class proxies, but there are also some reasons to believe that supporting a class dynamic agent will be better. Interface and class division, this is not very obvious, but in Java only to become so refined. If you only consider the declaration of a method and whether it is defined, there is a mixture of the two, its name is abstract class. The realization of the dynamic agent of the abstract class, believe also has its intrinsic value. In addition, there are some legacy classes that will never ever be associated with dynamic proxies because they do not implement any interfaces. So many, have to say is a small regret. However, imperfect is not equal to not great, great is an essence, Java Dynamic Agent is an example.

Thoroughly understand the Java dynamic Agent

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.