Java JDK 动态代理使用及实现原理分析

http://blog.csdn.net/jiankunking/article/details/52143504

版权声明:作者:jiankunking 出处:http://blog.csdn.net/jiankunking 本文版权归作者和CSDN共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

一、什么是代理?

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

代理模式UML图:


简单结构示意图:


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

二、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. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

作者:jiankunking 出处:http://blog.csdn.net/jiankunking

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JDK动态代理Java提供的一种代理模式实现方式,它允许在运行时动态地创建代理类和代理对象。JDK动态代理的底层实现原理主要涉及两个核心类:Proxy和InvocationHandler。 1. Proxy类:Proxy是JDK提供的用于创建动态代理类和对象的工具类。它通过调用Proxy.newProxyInstance()方法来创建代理对象。该方法接收三个参数:ClassLoader、Interface和InvocationHandler。ClassLoader用于加载代理类的字节码,Interface是被代理类实现的接口列表,InvocationHandler是一个接口,用于处理代理对象的方法调用。 2. InvocationHandler接口:InvocationHandler接口是JDK动态代理的核心接口,它定义了一个invoke()方法,用于处理代理对象的方法调用。在invoke()方法中,我们可以通过反射机制来调用被代理对象的方法,并在方法调用前后进行一些额外的操作。 当我们调用Proxy.newProxyInstance()方法创建代理对象时,JDK会动态生成一个继承Proxy类并实现了被代理接口的代理类。该代理类会在运行时通过字节码生成技术生成,并加载到内存中。当我们通过代理对象调用方法时,实际上是调用了InvocationHandler接口的invoke()方法。在invoke()方法中,我们可以根据需要进行一些额外的操作,比如记录日志、权限验证等,然后再通过反射机制调用被代理对象的方法。 总结一下JDK动态代理的底层实现原理: 1. 创建代理对象时,通过Proxy类动态生成一个继承Proxy类并实现了被代理接口的代理类。 2. 代理类在运行时通过字节码生成技术生成,并加载到内存中。 3. 代理对象调用方法时,实际上是调用了InvocationHandler接口的invoke()方法。 4. 在invoke()方法中,可以根据需要进行一些额外的操作,然后再通过反射机制调用被代理对象的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值