码迷,mamicode.com
首页 > 编程语言 > 详细

【转载】Java JDK 动态代理(AOP)使用及实现原理分析

时间:2016-12-26 23:53:59      阅读:414      评论:0      收藏:0      [点我收藏+]

标签:反编译   factory   each   访问   相同   top   retrieve   time   objects   

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

版权声明:作者:jiankunking 出处:http://blog.csdn.net/jiankunking 本文版权归作者和CSDN共有

一、什么是代理?

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

代理模式UML图:

技术分享

简单结构示意图:

技术分享

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

二、Java 动态代理类 

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

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

  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、需要动态代理的接口:

 

  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、需要代理的实际对象

 

  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啊)

 

  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、测试

  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.         ClassLoader loader = realSubject.getClass().getClassLoader();  
  24.         Class[] interfaces = realSubject.getClass().getInterfaces();  
  25.         /** 
  26.          * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 
  27.          */  
  28.         Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);  
  29.   
  30.         System.out.println("动态代理对象的类型:"+subject.getClass().getName());  
  31.   
  32.         String hello = subject.SayHello("jiankunking");  
  33.         System.out.println(hello);  
  34. //        String goodbye = subject.SayGoodBye();  
  35. //        System.out.println(goodbye);  
  36.     }  
  37.   
  38. }  

 

 

5、输出结果如下:

技术分享

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

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

从使用代码中可以看出,关键点在:
  1. Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);  
通过跟踪提示代码可以看出:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用。
也就是说,当代码执行到:
subject.SayHello("jiankunking")这句话时,会自动调用InvocationHandlerImpl的invoke方法。这是为啥呢?
 
======================横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论=====================================
以下代码来自:JDK1.8.0_92
既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么? 
  1. /** 
  2.  * Returns an instance of a proxy class for the specified interfaces 
  3.  * that dispatches method invocations to the specified invocation 
  4.  * handler. 
  5.  * 
  6.  * <p>{@code Proxy.newProxyInstance} throws 
  7.  * {@code IllegalArgumentException} for the same reasons that 
  8.  * {@code Proxy.getProxyClass} does. 
  9.  * 
  10.  * @param   loader the class loader to define the proxy class 
  11.  * @param   interfaces the list of interfaces for the proxy class 
  12.  *          to implement 
  13.  * @param   h the invocation handler to dispatch method invocations to 
  14.  * @return  a proxy instance with the specified invocation handler of a 
  15.  *          proxy class that is defined by the specified class loader 
  16.  *          and that implements the specified interfaces 
  17.  * @throws  IllegalArgumentException if any of the restrictions on the 
  18.  *          parameters that may be passed to {@code getProxyClass} 
  19.  *          are violated 
  20.  * @throws  SecurityException if a security manager, <em>s</em>, is present 
  21.  *          and any of the following conditions is met: 
  22.  *          <ul> 
  23.  *          <li> the given {@code loader} is {@code null} and 
  24.  *               the caller‘s class loader is not {@code null} and the 
  25.  *               invocation of {@link SecurityManager#checkPermission 
  26.  *               s.checkPermission} with 
  27.  *               {@code RuntimePermission("getClassLoader")} permission 
  28.  *               denies access;</li> 
  29.  *          <li> for each proxy interface, {@code intf}, 
  30.  *               the caller‘s class loader is not the same as or an 
  31.  *               ancestor of the class loader for {@code intf} and 
  32.  *               invocation of {@link SecurityManager#checkPackageAccess 
  33.  *               s.checkPackageAccess()} denies access to {@code intf};</li> 
  34.  *          <li> any of the given proxy interfaces is non-public and the 
  35.  *               caller class is not in the same {@linkplain Package runtime package} 
  36.  *               as the non-public interface and the invocation of 
  37.  *               {@link SecurityManager#checkPermission s.checkPermission} with 
  38.  *               {@code ReflectPermission("newProxyInPackage.{package name}")} 
  39.  *               permission denies access.</li> 
  40.  *          </ul> 
  41.  * @throws  NullPointerException if the {@code interfaces} array 
  42.  *          argument or any of its elements are {@code null}, or 
  43.  *          if the invocation handler, {@code h}, is 
  44.  *          {@code null} 
  45.  */  
  46. @CallerSensitive   
  47. public static Object newProxyInstance(ClassLoader loader,  
  48.                                           Class<?>[] interfaces,  
  49.                                           InvocationHandler h)  
  50.         throws IllegalArgumentException  
  51.     {  
  52.         //检查h 不为空,否则抛异常  
  53.         Objects.requireNonNull(h);  
  54.   
  55.         final Class<?>[] intfs = interfaces.clone();  
  56.         final SecurityManager sm = System.getSecurityManager();  
  57.         if (sm != null) {  
  58.             checkProxyAccess(Reflection.getCallerClass(), loader, intfs);  
  59.         }  
  60.   
  61.         /* 
  62.          * 获得与指定类装载器和一组接口相关的代理类类型对象 
  63.          */  
  64.         Class<?> cl = getProxyClass0(loader, intfs);  
  65.   
  66.         /* 
  67.          * 通过反射获取构造函数对象并生成代理类实例 
  68.          */  
  69.         try {  
  70.             if (sm != null) {  
  71.                 checkNewProxyPermission(Reflection.getCallerClass(), cl);  
  72.             }  
  73.             //获取代理对象的构造方法(也就是$Proxy0(InvocationHandler h))   
  74.             final Constructor<?> cons = cl.getConstructor(constructorParams);  
  75.             final InvocationHandler ih = h;  
  76.             if (!Modifier.isPublic(cl.getModifiers())) {  
  77.                 AccessController.doPrivileged(new PrivilegedAction<Void>() {  
  78.                     public Void run() {  
  79.                         cons.setAccessible(true);  
  80.                         return null;  
  81.                     }  
  82.                 });  
  83.             }  
  84.             //生成代理类的实例并把InvocationHandlerImpl的实例传给它的构造方法  
  85.             return cons.newInstance(new Object[]{h});  
  86.         } catch (IllegalAccessException|InstantiationException e) {  
  87.             throw new InternalError(e.toString(), e);  
  88.         } catch (InvocationTargetException e) {  
  89.             Throwable t = e.getCause();  
  90.             if (t instanceof RuntimeException) {  
  91.                 throw (RuntimeException) t;  
  92.             } else {  
  93.                 throw new InternalError(t.toString(), t);  
  94.             }  
  95.         } catch (NoSuchMethodException e) {  
  96.             throw new InternalError(e.toString(), e);  
  97.         }  
  98.     }  


我们再进去getProxyClass0方法看一下:
  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
  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方法啥样呢?
  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里面又做了什么?
  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)方法:
  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.    }  
通过看代码终于找到了重点:
  1. //生成字节码  
  2. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);  
那么接下来我们也使用测试一下,使用这个方法生成的字节码是个什么样子:
  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 工具将生成的字节码反编译:
  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接口
也就是说
  1. Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);  
这里的subject实际是这个类的一个实例,那么我们调用它的:
  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. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

【转载】Java JDK 动态代理(AOP)使用及实现原理分析

标签:反编译   factory   each   访问   相同   top   retrieve   time   objects   

原文地址:http://www.cnblogs.com/YangtzeYu/p/6224033.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!