Analysis of proxy dynamic agent principle in JDK

Source: Internet
Author: User
Tags getmessage modifier throwable

The main API classes are:

Proxy.newproxyinstance

public static Object newproxyinstance (ClassLoader loader,
Class<?>[] interfaces,
Invocationhandler h)
Throws IllegalArgumentException
Returns a proxy class instance of the specified interface that can assign a method call to the specified call handler. This method is equivalent to:
Proxy.getproxyclass (loader, interfaces).
GetConstructor (new class[] {invocationhandler.class}).
Newinstance (new object[] {handler});

Proxy.newproxyinstance throws illegalargumentexception for the same reason as Proxy.getproxyclass.

Parameters:

Loader-Class loader for defining proxy classes

Interfaces-List of interfaces to be implemented by the proxy class

H-Assign a call handler to a method call

Return:

A proxy instance of a specified invocation handler with a proxy class that is defined by the specified class loader and implements the specified interface

Thrown:

IllegalArgumentException-If any restrictions on the arguments passed to Getproxyclass are violated

NullPointerException-If the interfaces array argument or any of its elements is null, or if call handler h is null

Declare an interface first

Package com.czq.proxy;


Public interface Ipackagemanager {
     String getpackageinfo ();
}

Implement this interface

Package com.czq.proxy;

public class Packagemanagerimpl implements Ipackagemanager {

    @Override public
    String getpackageinfo () {
        String s = "Com.czq.proxy";        System.out.println (s);
        return s;
    }
   
    @Override public
    String toString () {return
        "Packagemanagerimpl";
    }

}

Implementation of the Invocationhandler interface, the key to this

Package com.czq.proxy;

Import Java.lang.reflect.InvocationHandler;
Import Java.lang.reflect.Method;

public class Packagemanagerwoker implements Invocationhandler {
    private Object mtarget = null;

    Public Packagemanagerwoker (Object target) {
        super ();
        This.mtarget = target;
    }

    @Override Public
    object Invoke (Object proxy, Method method, object[] args) throws Throwable {
              
        System. out.printl N ("1");
        System. Out.println ("Method:" +method);
        if (args!= null) {for
            (int i = 0; i < args.length i++) {
                System. Out.println ("args[" + i + "]:" + args[i]) ;
            }
        }
        Object result = Method.invoke (Mtarget, args);
        System. Out.println ("2");
        return result;       
    }

Test:

Package com.czq.proxy;

Import Java.lang.reflect.Field;
Import Java.lang.reflect.Method;
Import Java.lang.reflect.Modifier;
Import Java.lang.reflect.Proxy;

public class Test {public

    static void Main (string[] args) {
        //from source, set this value, you can generate the proxy class, output.
        system.getproperties (). Put ("Sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

       
        Ipackagemanager Pkgmanger = new Packagemanagerimpl ();        System.out.println ("pkgmanger.tostring:" +pkgmanger.tostring ());
        Packagemanagerwoker Woker = new Packagemanagerwoker (Pkgmanger);
        Ipackagemanager pm = (ipackagemanager) proxy.newproxyinstance (Pkgmanger.getclass (). getClassLoader (), PkgManger
                . GetClass (). Getinterfaces (), woker);  System.out.println ("Pm.getname:" +pm.getclass (). GetName ())
    
        System. Out.println ("pm.tostring:" +pm.tostring ());
        System.out.println (Pm.getpackageinfo ());
    } 

The output results are as follows:
1
method:public java.lang.String java.lang.Object.toString ()
2
pm.toString:PackageManagerImpl
1
Method:public abstract java.lang.String com.czq.proxy.IPackageManager.getPackageInfo ()
2
Com.czq.proxy
Come to the conclusion that:
The Pm.getpackageinfo () method goes to the Packagemanagerwoker invoke method.
Thinking Questions:
Packagemanagerwoker does not inherit Ipackagemanager. Can not be strong turn into Ipackagemanager.
That is, the PM object is not a Packagemanagerwoker object.
That PM is which object, what is the class. Why is it better to turn into a ipackagemanager?

Print PM's classname
System.out.println ("Pm.getname:" +pm.getclass (). GetName ())
The results obtained:
Pm.getName:com.sun.proxy. $Proxy 0
That is, the PM object is a new object of the class Com.sun.proxy $Proxy 0. This class is just proxy.newproxyinstance automatically generated class
What is written in this class?
View Source: Proxy.java
/** * A factory function that generates, defines and returns the proxy class given * The ClassLoader and array o
     F interfaces. * Private static Final class Proxyclassfactory implements Bifunction<classloader, class<?>[], class& lt;? >> {//prefix for all proxy class names private static final String Proxyclassnameprefix = "$Pr

        Oxy "; Next number to use for generation of the unique proxy class names private static final Atomiclong Nextuniquenumber

        = new Atomiclong (); @Override public class<?> Apply (ClassLoader loader, class<?>[] interfaces) {Map<class
            <?&gt, boolean> interfaceset = new identityhashmap<> (interfaces.length); for (class<?> intf:interfaces) {/* * Verify that Class loader resolves the n
                 Ame of this * interface to the same Class object.
               */ Class<?> interfaceclass = null;
                try {interfaceclass = Class.forName (Intf.getname (), false, loader); catch (ClassNotFoundException e) {} if (Interfaceclass!= intf) {T
                Hrow New IllegalArgumentException (intf + "is not visible from class loader");
                 } * * Verify that Class object actually represents a * interface. */if (!interfaceclass.isinterface ()) {throw new Illegalargumentexce
                Ption (Interfaceclass.getname () + "is isn't an interface");
                 } * * Verify that this interface are not a duplicate. */if (Interfaceset.put (Interfaceclass, boolean.true)!= null) {throw new Illegalarg
             Umentexception (           "Repeated interface:" + interfaceclass.getname ());     } String proxypkg = null; Package to define proxy class in/* record the package of a non-public proxy interface so t  Hat the * proxy class is defined in the same package.
             Verify that * All Non-public proxy interfaces are the same package.
                * * for (class<?> intf:interfaces) {int flags = Intf.getmodifiers (); if (!
                    Modifier.ispublic (Flags)) {String name = Intf.getname ();
                    int n = name.lastindexof ('. '); String pkg = ((n = = 1)?
                    "": name.substring (0, n + 1));
                    if (proxypkg = = null) {proxypkg = pkg;
                            else if (!pkg.equals (proxypkg)) {throw new IllegalArgumentException ( "Non-public Interfaces from different packages "); }} if (proxypkg = null) {//If no Non-public proxy interface s, use Com.sun.proxy package proxypkg = Reflectutil.
            Proxy_package + ".";
             }/* Choose a name for the proxy class to generate.
            */Long num = Nextuniquenumber.getandincrement ();

            String proxyname = proxypkg + proxyclassnameprefix + num;
             * * Generate the specified proxy class.
            * * byte[] proxyclassfile = Proxygenerator.generateproxyclass (proxyname, interfaces); try {return DefineClass0 (loader, proxyname, Proxyclassfile, 0, p
            Roxyclassfile.length); The catch (Classformaterror e) {* * * A classformaterror here means this (barring bugs in t
        He         * Proxy class generation code) there is some other * invalid aspect of the arguments supplied T
                 o the Proxy * class creation (such as virtual machine limitations * exceeded).
            * * Throw new IllegalArgumentException (e.tostring ());
 }
        }
    }

This class was generated by Proxygenerator. View Proxygenerator Source:
/** * Generate a proxy class given a name and a list of proxy interfaces. * * @param name the class name of the proxy class * @param interfaces Proxy interfaces * @param acc
                                            Essflags Access Flags of the proxy class */public static byte[] Generateproxyclass (final String name, 
    Class<?>[] interfaces, int accessflags)
        {Proxygenerator Gen = new Proxygenerator (name, interfaces, AccessFlags);

        Final byte[] Classfile = Gen.generateclassfile (); if (savegeneratedfiles) {java.security.AccessController.doPrivileged (new Java.security.Privilege Daction<void> () {public Void run () {try {int i = name
                        . LastIndexOf ('. ');
                        Path path; if (i > 0) {Path dir = paths.get (name.subsTring (0, I). replace ('. ', File.separatorchar));
                            Files.createdirectories (dir);
                        Path = Dir.resolve (Name.substring (i+1, Name.length ()) + ". Class");
                        else {path = Paths.get (name +. Class);
                        } files.write (path, classfile);
                    return null; catch (IOException e) {throw new Internalerror ("I/O exception Savi
                    Ng generated file: "+ E);
        }
                }
            });
    return classfile;
 }

Found that Savegeneratedfiles is the true error generated class source code.
How can this savegeneratedfiles be assigned a value?
/** debugging flag for saving generated class files/
    private final static Boolean savegeneratedfiles =
        Java.secu Rity. Accesscontroller.doprivileged (
            new Getbooleanaction (
                "Sun.misc.ProxyGenerator.saveGeneratedFiles")). Booleanvalue ();

That is, to change the sun.misc.ProxyGenerator.saveGeneratedFiles to True, you can output the result.
        From the source to know, set this value, you can generate the proxy class, output out.
        system.getproperties (). Put ("Sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

Note that you need to re-engineering the root directory, add Com/sun/proxy directory, or you will be the following error:
Exception in thread "main" java.lang.internalerror:i/o Exception saving generated file:java.io.filenotfoundexception:c Om\sun\proxy\ $Proxy 0.class (the system cannot find the specified path.) ) at
     Sun.misc.proxygenerator$1.run (proxygenerator.java:336) at
     Sun.misc.proxygenerator$1.run ( proxygenerator.java:327) at
     java.security.AccessController.doPrivileged (Native method)
     at Sun.misc.ProxyGenerator.generateProxyClass (proxygenerator.java:326) at
     java.lang.reflect.proxy$ Proxyclassfactory.apply (proxy.java:672) at
     java.lang.reflect.proxy$proxyclassfactory.apply (Proxy.java:592) At
     Java.lang.reflect.weakcache$factory.get (weakcache.java:244) at
     Java.lang.reflect.WeakCache.get ( weakcache.java:141) at
     java.lang.reflect.Proxy.getProxyClass0 (proxy.java:455)
     at Java.lang.reflect.Proxy.newProxyInstance (proxy.java:738) at
     Com.czq.proxy.Test.main (test.java:18)

The results of the PROXY0 output are as follows: Decompile to see what Proxy0 is, what's the secret?
Package com.sun.proxy;
Import Com.czq.proxy.IPackageManager;
Import Java.lang.reflect.InvocationHandler;
Import Java.lang.reflect.Method;
Import Java.lang.reflect.Proxy;

Import java.lang.reflect.UndeclaredThrowableException;  Public final class $Proxy 0 extends Proxy implements Ipackagemanager {private static methods M3;//Generate corresponding Method object private
  static method M1;
  private static method M0;
private static method m2;
Proxy0 inherits the proxy, implements the Ipackagemanager interface, needs to pass in the Invocationhandler, initializes the corresponding H object.
Our H object is packagemanagerwoker, so we'll call the Invoke method to Packagemanagerwoker. So it's proxy0, call the Invocationhandler invoke method, and pass in the corresponding method.
  Invocationhandler radiation calls the method in the corresponding Tagret.
  Public $Proxy 0 (Invocationhandler Paraminvocationhandler) throws {super (Paraminvocationhandler); 
    Public final String Getpackageinfo () throws {try {return (String) This.h.invoke (this, M3, null);
    catch (RuntimeException localruntimeexception) {throw localruntimeexception; } CATCH (Throwable localthrowable) {} throw new Undeclaredthrowableexception (localthrowable); Public final Boolean equals (Object Paramobject) throws {try {return (Boolean) This.h.invoke (thi
    S, M1, new object[] {paramobject})). Booleanvalue ();
    catch (RuntimeException localruntimeexception) {throw localruntimeexception;
  The catch (Throwable localthrowable) {} throw new Undeclaredthrowableexception (localthrowable); Public final int Hashcode () throws {try {return ((Integer) This.h.invoke (this, M0, null). intval
    UE ();
    catch (RuntimeException localruntimeexception) {throw localruntimeexception;
  The catch (Throwable localthrowable) {} throw new Undeclaredthrowableexception (localthrowable);
    Public final String toString () throws {try {return (String) This.h.invoke (this, M2, null); catch (RuntimeException LocalruntiMeexception) {throw localruntimeexception;
  The catch (Throwable localthrowable) {} throw new Undeclaredthrowableexception (localthrowable); static {try {///put each method, corresponding to the member variable m3 = class.forname ("Com.czq.proxy.IPackageManager"). GetMethod ("
      Getpackageinfo ", new Class[0]);
      M1 = Class.forName ("Java.lang.Object"). GetMethod ("equals", new class[] {class.forname ("Java.lang.Object")});
      M0 = Class.forName ("Java.lang.Object"). GetMethod ("Hashcode", new class[0);
      M2 = Class.forName ("Java.lang.Object"). GetMethod ("ToString", new Class[0]);
    Return catch (Nosuchmethodexception localnosuchmethodexception) {throw new Nosuchmethoderror (Localnosuchmethodex
    Ception.getmessage ()); The catch (ClassNotFoundException localclassnotfoundexception) {} throw new Noclassdeffounderror (Localclass
  Notfoundexception.getmessage ());
 }
}

The conclusions are as follows:
1. Proxy0 inherits proxy, implements Ipackagemanager interface, needs to pass in Invocationhandler, initialize corresponding H object.
2. Our H object is packagemanagerwoker, so we call the Invoke method to Packagemanagerwoker.
3. So it's proxy0, call the Invocationhandler invoke method, and pass in the corresponding method. Invocationhandler radiation calls the method in the corresponding Tagret. It's a 2-story set.



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.