zoukankan      html  css  js  c++  java
  • Java JDK 动态代理使用及实现原理分析

    http://blog.csdn.net/jiankunking 

    【原创】自己动手实现JDK动态代理 (可以自己完全手写一个)

     

    一、什么是代理?

    代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

    代理模式UML图:


    简单结构示意图:

    为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

    二、Java 动态代理类 

    Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

    (1)Interface InvocationHandler:该接口中仅定义了一个方法

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. publicobject invoke(Object obj,Method method, Object[] args)  

    在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

    (2)Proxy:该类即为动态代理类,其中主要包含以下内容:

    protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。

    static Class getProxyClass (ClassLoaderloader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

    static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

    所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

    在使用动态代理类时,我们必须实现InvocationHandler接口

    通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

    动态代理步骤
    1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
    2.创建被代理的类以及接口
    3.通过Proxy的静态方法
    newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
    4.通过代理调用方法

    三、JDK的动态代理怎么使用?

    1、需要动态代理的接口:
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. package jiankunking;  
    2.   
    3. /** 
    4.  * 需要动态代理的接口 
    5.  */  
    6. public interface Subject  
    7. {  
    8.     /** 
    9.      * 你好 
    10.      * 
    11.      * @param name 
    12.      * @return 
    13.      */  
    14.     public String SayHello(String name);  
    15.   
    16.     /** 
    17.      * 再见 
    18.      * 
    19.      * @return 
    20.      */  
    21.     public String SayGoodBye();  
    22. }  

    2、需要代理的实际对象
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. package jiankunking;  
    2.   
    3. /** 
    4.  * 实际对象 
    5.  */  
    6. public class RealSubject implements Subject  
    7. {  
    8.   
    9.     /** 
    10.      * 你好 
    11.      * 
    12.      * @param name 
    13.      * @return 
    14.      */  
    15.     public String SayHello(String name)  
    16.     {  
    17.         return "hello " + name;  
    18.     }  
    19.   
    20.     /** 
    21.      * 再见 
    22.      * 
    23.      * @return 
    24.      */  
    25.     public String SayGoodBye()  
    26.     {  
    27.         return " good bye ";  
    28.     }  
    29. }  

    3、调用处理器实现类(有木有感觉这里就是传说中的AOP啊)
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. package jiankunking;  
    2.   
    3. import java.lang.reflect.InvocationHandler;  
    4. import java.lang.reflect.Method;  
    5.   
    6.   
    7. /** 
    8.  * 调用处理器实现类 
    9.  * 每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象 
    10.  */  
    11. public class InvocationHandlerImpl implements InvocationHandler  
    12. {  
    13.   
    14.     /** 
    15.      * 这个就是我们要代理的真实对象 
    16.      */  
    17.     private Object subject;  
    18.   
    19.     /** 
    20.      * 构造方法,给我们要代理的真实对象赋初值 
    21.      * 
    22.      * @param subject 
    23.      */  
    24.     public InvocationHandlerImpl(Object subject)  
    25.     {  
    26.         this.subject = subject;  
    27.     }  
    28.   
    29.     /** 
    30.      * 该方法负责集中处理动态代理类上的所有方法调用。 
    31.      * 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行 
    32.      * 
    33.      * @param proxy  代理类实例 
    34.      * @param method 被调用的方法对象 
    35.      * @param args   调用参数 
    36.      * @return 
    37.      * @throws Throwable 
    38.      */  
    39.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
    40.     {  
    41.         //在代理真实对象前我们可以添加一些自己的操作  
    42.         System.out.println("在调用之前,我要干点啥呢?");  
    43.   
    44.         System.out.println("Method:" + method);  
    45.   
    46.         //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用  
    47.         Object returnValue = method.invoke(subject, args);  
    48.   
    49.         //在代理真实对象后我们也可以添加一些自己的操作  
    50.         System.out.println("在调用之后,我要干点啥呢?");  
    51.   
    52.         return returnValue;  
    53.     }  
    54. }  
    4、测试
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. package jiankunking;  
    2.   
    3. import java.lang.reflect.InvocationHandler;  
    4. import java.lang.reflect.Proxy;  
    5.   
    6. /** 
    7.  * 动态代理演示 
    8.  */  
    9. public class DynamicProxyDemonstration  
    10. {  
    11.     public static void main(String[] args)  
    12.     {  
    13.         //代理的真实对象  
    14.         Subject realSubject = new RealSubject();  
    15.           
    16.         /** 
    17.          * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发 
    18.          * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用. 
    19.          * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法 
    20.          */  
    21.         InvocationHandler handler = new InvocationHandlerImpl(realSubject);  
    22.   
    23.   
    24.         ClassLoader loader = handler.getClass().getClassLoader();  
    25.         Class[] interfaces = realSubject.getClass().getInterfaces();  
    26.         /** 
    27.          * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 
    28.          */  
    29.         Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);  
    30.   
    31.         System.out.println("动态代理对象的类型:"+subject.getClass().getName());  
    32.   
    33.         String hello = subject.SayHello("jiankunking");  
    34.         System.out.println(hello);  
    35. //        String goodbye = subject.SayGoodBye();  
    36. //        System.out.println(goodbye);  
    37.     }  
    38.   
    39. }  

    5、输出结果如下:

    演示demo下载地址:http://download.csdn.net/detail/xunzaosiyecao/9597388

    四、动态代理怎么实现的?

    从使用代码中可以看出,关键点在:
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);  
    通过跟踪提示代码可以看出:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用。
    也就是说,当代码执行到:
    subject.SayHello("jiankunking")这句话时,会自动调用InvocationHandlerImpl的invoke方法。这是为啥呢?
     
    ======================横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论=====================================
    以下代码来自:JDK1.8.0_92
    既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么? 
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. public static Object newProxyInstance(ClassLoader loader,  
    2.                                          Class<?>[] interfaces,  
    3.                                          InvocationHandler h)  
    4.        throws IllegalArgumentException  
    5.    {  
    6.     //检查h 不为空,否则抛异常  
    7.        Objects.requireNonNull(h);  
    8.   
    9.        final Class<?>[] intfs = interfaces.clone();  
    10.        final SecurityManager sm = System.getSecurityManager();  
    11.        if (sm != null) {  
    12.            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);  
    13.        }  
    14.   
    15.        /* 
    16.         * 获得与指定类装载器和一组接口相关的代理类类型对象 
    17.         */  
    18.        Class<?> cl = getProxyClass0(loader, intfs);  
    19.   
    20.        /* 
    21.         * 通过反射获取构造函数对象并生成代理类实例 
    22.         */  
    23.        try {  
    24.            if (sm != null) {  
    25.                checkNewProxyPermission(Reflection.getCallerClass(), cl);  
    26.            }  
    27.         //获取代理对象的构造方法(也就是$Proxy0(InvocationHandler h))   
    28.            final Constructor<?> cons = cl.getConstructor(constructorParams);  
    29.            final InvocationHandler ih = h;  
    30.            if (!Modifier.isPublic(cl.getModifiers())) {  
    31.                AccessController.doPrivileged(new PrivilegedAction<Void>() {  
    32.                    public Void run() {  
    33.                        cons.setAccessible(true);  
    34.                        return null;  
    35.                    }  
    36.                });  
    37.            }  
    38.         //生成代理类的实例并把InvocationHandlerImpl的实例传给它的构造方法  
    39.            return cons.newInstance(new Object[]{h});  
    40.        } catch (IllegalAccessException|InstantiationException e) {  
    41.            throw new InternalError(e.toString(), e);  
    42.        } catch (InvocationTargetException e) {  
    43.            Throwable t = e.getCause();  
    44.            if (t instanceof RuntimeException) {  
    45.                throw (RuntimeException) t;  
    46.            } else {  
    47.                throw new InternalError(t.toString(), t);  
    48.            }  
    49.        } catch (NoSuchMethodException e) {  
    50.            throw new InternalError(e.toString(), e);  
    51.        }  
    52.    }  
    我们再进去getProxyClass0方法看一下:
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. /** 
    2.     * Generate a proxy class.  Must call the checkProxyAccess method 
    3.     * to perform permission checks before calling this. 
    4.     */  
    5.    private static Class<?> getProxyClass0(ClassLoader loader,  
    6.                                           Class<?>... interfaces) {  
    7.        if (interfaces.length > 65535) {  
    8.            throw new IllegalArgumentException("interface limit exceeded");  
    9.        }  
    10.   
    11.        // If the proxy class defined by the given loader implementing  
    12.        // the given interfaces exists, this will simply return the cached copy;  
    13.        // otherwise, it will create the proxy class via the ProxyClassFactory  
    14.        return proxyClassCache.get(loader, interfaces);  
    15.    }  
    真相还是没有来到,继续,看一下proxyClassCache
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. /** 
    2.      * a cache of proxy classes 
    3.      */  
    4.     private static final WeakCache<ClassLoader, Class<?>[], Class<?>>  
    5.         proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());  
    奥,原来用了一下缓存啊
    那么它对应的get方法啥样呢?
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. /** 
    2.     * Look-up the value through the cache. This always evaluates the 
    3.     * {@code subKeyFactory} function and optionally evaluates 
    4.     * {@code valueFactory} function if there is no entry in the cache for given 
    5.     * pair of (key, subKey) or the entry has already been cleared. 
    6.     * 
    7.     * @param key       possibly null key 
    8.     * @param parameter parameter used together with key to create sub-key and 
    9.     *                  value (should not be null) 
    10.     * @return the cached value (never null) 
    11.     * @throws NullPointerException if {@code parameter} passed in or 
    12.     *                              {@code sub-key} calculated by 
    13.     *                              {@code subKeyFactory} or {@code value} 
    14.     *                              calculated by {@code valueFactory} is null. 
    15.     */  
    16.    public V get(K key, P parameter) {  
    17.        Objects.requireNonNull(parameter);  
    18.   
    19.        expungeStaleEntries();  
    20.   
    21.        Object cacheKey = CacheKey.valueOf(key, refQueue);  
    22.   
    23.        // lazily install the 2nd level valuesMap for the particular cacheKey  
    24.        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);  
    25.        if (valuesMap == null) {  
    26.         //putIfAbsent这个方法在key不存在的时候加入一个值,如果key存在就不放入  
    27.            ConcurrentMap<Object, Supplier<V>> oldValuesMap  
    28.                = map.putIfAbsent(cacheKey,  
    29.                                  valuesMap = new ConcurrentHashMap<>());  
    30.            if (oldValuesMap != null) {  
    31.                valuesMap = oldValuesMap;  
    32.            }  
    33.        }  
    34.   
    35.        // create subKey and retrieve the possible Supplier<V> stored by that  
    36.        // subKey from valuesMap  
    37.        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));  
    38.        Supplier<V> supplier = valuesMap.get(subKey);  
    39.        Factory factory = null;  
    40.   
    41.        while (true) {  
    42.            if (supplier != null) {  
    43.                // supplier might be a Factory or a CacheValue<V> instance  
    44.                V value = supplier.get();  
    45.                if (value != null) {  
    46.                    return value;  
    47.                }  
    48.            }  
    49.            // else no supplier in cache  
    50.            // or a supplier that returned null (could be a cleared CacheValue  
    51.            // or a Factory that wasn't successful in installing the CacheValue)  
    52.   
    53.            // lazily construct a Factory  
    54.            if (factory == null) {  
    55.                factory = new Factory(key, parameter, subKey, valuesMap);  
    56.            }  
    57.   
    58.            if (supplier == null) {                
    59.                supplier = valuesMap.putIfAbsent(subKey, factory);  
    60.                if (supplier == null) {  
    61.                    // successfully installed Factory  
    62.                    supplier = factory;  
    63.                }  
    64.                // else retry with winning supplier  
    65.            } else {  
    66.                if (valuesMap.replace(subKey, supplier, factory)) {  
    67.                    // successfully replaced  
    68.                    // cleared CacheEntry / unsuccessful Factory  
    69.                    // with our Factory  
    70.                    supplier = factory;  
    71.                } else {  
    72.                    // retry with current supplier  
    73.                    supplier = valuesMap.get(subKey);  
    74.                }  
    75.            }  
    76.        }  
    77.    }  

    我们可以看到它调用了 supplier.get(); 获取动态代理类,其中supplier是Factory,这个类定义在WeakCach的内部。
    来瞅瞅,get里面又做了什么?
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. public synchronized V get() { // serialize access  
    2.            // re-check  
    3.            Supplier<V> supplier = valuesMap.get(subKey);  
    4.            if (supplier != this) {  
    5.                // something changed while we were waiting:  
    6.                // might be that we were replaced by a CacheValue  
    7.                // or were removed because of failure ->  
    8.                // return null to signal WeakCache.get() to retry  
    9.                // the loop  
    10.                return null;  
    11.            }  
    12.            // else still us (supplier == this)  
    13.   
    14.            // create new value  
    15.            V value = null;  
    16.            try {  
    17.                value = Objects.requireNonNull(valueFactory.apply(key, parameter));  
    18.            } finally {  
    19.                if (value == null) { // remove us on failure  
    20.                    valuesMap.remove(subKey, this);  
    21.                }  
    22.            }  
    23.            // the only path to reach here is with non-null value  
    24.            assert value != null;  
    25.   
    26.            // wrap value with CacheValue (WeakReference)  
    27.            CacheValue<V> cacheValue = new CacheValue<>(value);  
    28.   
    29.            // try replacing us with CacheValue (this should always succeed)  
    30.            if (valuesMap.replace(subKey, this, cacheValue)) {  
    31.                // put also in reverseMap  
    32.                reverseMap.put(cacheValue, Boolean.TRUE);  
    33.            } else {  
    34.                throw new AssertionError("Should not reach here");  
    35.            }  
    36.   
    37.            // successfully replaced us with new CacheValue -> return the value  
    38.            // wrapped by it  
    39.            return value;  
    40.        }  
    41.    }  

    发现重点还是木有出现,但我们可以看到它调用了valueFactory.apply(key, parameter)方法:
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. /** 
    2.     * A factory function that generates, defines and returns the proxy class given 
    3.     * the ClassLoader and array of interfaces. 
    4.     */  
    5.    private static final class ProxyClassFactory  
    6.        implements BiFunction<ClassLoader, Class<?>[], Class<?>>  
    7.    {  
    8.        // prefix for all proxy class names  
    9.        private static final String proxyClassNamePrefix = "$Proxy";  
    10.   
    11.        // next number to use for generation of unique proxy class names  
    12.        private static final AtomicLong nextUniqueNumber = new AtomicLong();  
    13.   
    14.        @Override  
    15.        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {  
    16.   
    17.            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);  
    18.            for (Class<?> intf : interfaces) {  
    19.                /* 
    20.                 * Verify that the class loader resolves the name of this 
    21.                 * interface to the same Class object. 
    22.                 */  
    23.                Class<?> interfaceClass = null;  
    24.                try {  
    25.                    interfaceClass = Class.forName(intf.getName(), false, loader);  
    26.                } catch (ClassNotFoundException e) {  
    27.                }  
    28.                if (interfaceClass != intf) {  
    29.                    throw new IllegalArgumentException(  
    30.                        intf + " is not visible from class loader");  
    31.                }  
    32.                /* 
    33.                 * Verify that the Class object actually represents an 
    34.                 * interface. 
    35.                 */  
    36.                if (!interfaceClass.isInterface()) {  
    37.                    throw new IllegalArgumentException(  
    38.                        interfaceClass.getName() + " is not an interface");  
    39.                }  
    40.                /* 
    41.                 * Verify that this interface is not a duplicate. 
    42.                 */  
    43.                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {  
    44.                    throw new IllegalArgumentException(  
    45.                        "repeated interface: " + interfaceClass.getName());  
    46.                }  
    47.            }  
    48.   
    49.            String proxyPkg = null;     // package to define proxy class in  
    50.            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;  
    51.   
    52.            /* 
    53.             * Record the package of a non-public proxy interface so that the 
    54.             * proxy class will be defined in the same package.  Verify that 
    55.             * all non-public proxy interfaces are in the same package. 
    56.             */  
    57.            for (Class<?> intf : interfaces) {  
    58.                int flags = intf.getModifiers();  
    59.                if (!Modifier.isPublic(flags)) {  
    60.                    accessFlags = Modifier.FINAL;  
    61.                    String name = intf.getName();  
    62.                    int n = name.lastIndexOf('.');  
    63.                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));  
    64.                    if (proxyPkg == null) {  
    65.                        proxyPkg = pkg;  
    66.                    } else if (!pkg.equals(proxyPkg)) {  
    67.                        throw new IllegalArgumentException(  
    68.                            "non-public interfaces from different packages");  
    69.                    }  
    70.                }  
    71.            }  
    72.   
    73.            if (proxyPkg == null) {  
    74.                // if no non-public proxy interfaces, use com.sun.proxy package  
    75.                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";  
    76.            }  
    77.   
    78.            /* 
    79.             * Choose a name for the proxy class to generate. 
    80.             */  
    81.            long num = nextUniqueNumber.getAndIncrement();  
    82.            String proxyName = proxyPkg + proxyClassNamePrefix + num;  
    83.   
    84.            /* 
    85.             * Generate the specified proxy class. 
    86.             */  
    87.            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(  
    88.                proxyName, interfaces, accessFlags);  
    89.            try {  
    90.                return defineClass0(loader, proxyName,  
    91.                                    proxyClassFile, 0, proxyClassFile.length);  
    92.            } catch (ClassFormatError e) {  
    93.                /* 
    94.                 * A ClassFormatError here means that (barring bugs in the 
    95.                 * proxy class generation code) there was some other 
    96.                 * invalid aspect of the arguments supplied to the proxy 
    97.                 * class creation (such as virtual machine limitations 
    98.                 * exceeded). 
    99.                 */  
    100.                throw new IllegalArgumentException(e.toString());  
    101.            }  
    102.        }  
    103.    }  
    通过看代码终于找到了重点:
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. //生成字节码  
    2. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);  
    那么接下来我们也使用测试一下,使用这个方法生成的字节码是个什么样子:
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. package jiankunking;  
    2.   
    3. import sun.misc.ProxyGenerator;  
    4.   
    5. import java.io.File;  
    6. import java.io.FileNotFoundException;  
    7. import java.io.FileOutputStream;  
    8. import java.io.IOException;  
    9. import java.lang.reflect.InvocationHandler;  
    10. import java.lang.reflect.Proxy;  
    11.   
    12. /** 
    13.  * 动态代理演示 
    14.  */  
    15. public class DynamicProxyDemonstration  
    16. {  
    17.     public static void main(String[] args)  
    18.     {  
    19.         //代理的真实对象  
    20.         Subject realSubject = new RealSubject();  
    21.   
    22.         /** 
    23.          * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发 
    24.          * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用. 
    25.          * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法 
    26.          */  
    27.         InvocationHandler handler = new InvocationHandlerImpl(realSubject);  
    28.   
    29.         ClassLoader loader = handler.getClass().getClassLoader();  
    30.         Class[] interfaces = realSubject.getClass().getInterfaces();  
    31.         /** 
    32.          * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 
    33.          */  
    34.         Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);  
    35.   
    36.         System.out.println("动态代理对象的类型:"+subject.getClass().getName());  
    37.   
    38.         String hello = subject.SayHello("jiankunking");  
    39.         System.out.println(hello);  
    40.         // 将生成的字节码保存到本地,  
    41.         createProxyClassFile();  
    42.     }  
    43.     private static void createProxyClassFile(){  
    44.         String name = "ProxySubject";  
    45.         byte[] data = ProxyGenerator.generateProxyClass(name,new Class[]{Subject.class});  
    46.         FileOutputStream out =null;  
    47.         try {  
    48.             out = new FileOutputStream(name+".class");  
    49.             System.out.println((new File("hello")).getAbsolutePath());  
    50.             out.write(data);  
    51.         } catch (FileNotFoundException e) {  
    52.             e.printStackTrace();  
    53.         } catch (IOException e) {  
    54.             e.printStackTrace();  
    55.         }finally {  
    56.             if(null!=out) try {  
    57.                 out.close();  
    58.             } catch (IOException e) {  
    59.                 e.printStackTrace();  
    60.             }  
    61.         }  
    62.     }  
    63.   
    64. }  
    我们用jd-jui 工具将生成的字节码反编译:
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. import java.lang.reflect.InvocationHandler;  
    2. import java.lang.reflect.Method;  
    3. import java.lang.reflect.Proxy;  
    4. import java.lang.reflect.UndeclaredThrowableException;  
    5. import jiankunking.Subject;  
    6.   
    7. public final class ProxySubject  
    8.   extends Proxy  
    9.   implements Subject  
    10. {  
    11.   private static Method m1;  
    12.   private static Method m3;  
    13.   private static Method m4;  
    14.   private static Method m2;  
    15.   private static Method m0;  
    16.     
    17.   public ProxySubject(InvocationHandler paramInvocationHandler)  
    18.   {  
    19.     super(paramInvocationHandler);  
    20.   }  
    21.     
    22.   public final boolean equals(Object paramObject)  
    23.   {  
    24.     try  
    25.     {  
    26.       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();  
    27.     }  
    28.     catch (Error|RuntimeException localError)  
    29.     {  
    30.       throw localError;  
    31.     }  
    32.     catch (Throwable localThrowable)  
    33.     {  
    34.       throw new UndeclaredThrowableException(localThrowable);  
    35.     }  
    36.   }  
    37.     
    38.   public final String SayGoodBye()  
    39.   {  
    40.     try  
    41.     {  
    42.       return (String)this.h.invoke(this, m3, null);  
    43.     }  
    44.     catch (Error|RuntimeException localError)  
    45.     {  
    46.       throw localError;  
    47.     }  
    48.     catch (Throwable localThrowable)  
    49.     {  
    50.       throw new UndeclaredThrowableException(localThrowable);  
    51.     }  
    52.   }  
    53.     
    54.   public final String SayHello(String paramString)  
    55.   {  
    56.     try  
    57.     {  
    58.       return (String)this.h.invoke(this, m4, new Object[] { paramString });  
    59.     }  
    60.     catch (Error|RuntimeException localError)  
    61.     {  
    62.       throw localError;  
    63.     }  
    64.     catch (Throwable localThrowable)  
    65.     {  
    66.       throw new UndeclaredThrowableException(localThrowable);  
    67.     }  
    68.   }  
    69.     
    70.   public final String toString()  
    71.   {  
    72.     try  
    73.     {  
    74.       return (String)this.h.invoke(this, m2, null);  
    75.     }  
    76.     catch (Error|RuntimeException localError)  
    77.     {  
    78.       throw localError;  
    79.     }  
    80.     catch (Throwable localThrowable)  
    81.     {  
    82.       throw new UndeclaredThrowableException(localThrowable);  
    83.     }  
    84.   }  
    85.     
    86.   public final int hashCode()  
    87.   {  
    88.     try  
    89.     {  
    90.       return ((Integer)this.h.invoke(this, m0, null)).intValue();  
    91.     }  
    92.     catch (Error|RuntimeException localError)  
    93.     {  
    94.       throw localError;  
    95.     }  
    96.     catch (Throwable localThrowable)  
    97.     {  
    98.       throw new UndeclaredThrowableException(localThrowable);  
    99.     }  
    100.   }  
    101.     
    102.   static  
    103.   {  
    104.     try  
    105.     {  
    106.       m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });  
    107.       m3 = Class.forName("jiankunking.Subject").getMethod("SayGoodBye", new Class[0]);  
    108.       m4 = Class.forName("jiankunking.Subject").getMethod("SayHello", new Class[] { Class.forName("java.lang.String") });  
    109.       m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);  
    110.       m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);  
    111.       return;  
    112.     }  
    113.     catch (NoSuchMethodException localNoSuchMethodException)  
    114.     {  
    115.       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());  
    116.     }  
    117.     catch (ClassNotFoundException localClassNotFoundException)  
    118.     {  
    119.       throw new NoClassDefFoundError(localClassNotFoundException.getMessage());  
    120.     }  
    121.   }  
    122. }  

    这就是最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口
    也就是说:
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);  
    这里的subject实际是这个类的一个实例,那么我们调用它的:
    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. public final String SayHello(String paramString)  
    就是调用我们定义的InvocationHandlerImpl的 invoke方法:
    ======================横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论=====================================

    五、结论

    到了这里,终于解答了:
    subject.SayHello("jiankunking")这句话时,为什么会自动调用InvocationHandlerImpl的invoke方法?
    
    
    
    因为JDK生成的最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口,在实现Subject接口方法的内部,通过反射调用了
    InvocationHandlerImpl的invoke方法。
    
    
    包含生成本地class文件的demo:http://download.csdn.net/detail/xunzaosiyecao/9597474
    通过分析代码可以看出Java 动态代理,具体有如下四步骤:
    1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
    2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
    3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
    4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
     
    本文参考过:
  • 相关阅读:
    CSS基础(二)-- CSS选择器之ID选择器
    CSS基础(一)-- CSS的存在形式以及优先级
    HTML--Boby部分之fieldset标签
    HTML--Boby部分之label标签
    HTML--Boby部分之表格
    HTML--Boby部分之<img>标签
    rpm和yum的用法
    网络模型
    内存扩容
    磁盘介绍
  • 原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/5881645.html
Copyright © 2011-2022 走看看