标签:des   blog   http   io   os   ar   java   for   strong   
之前虽然会用JDK的动态代理,但是有些问题却一直没有搞明白。比如说:InvocationHandler的invoke方法是由谁来调用的,代理对象是怎么生成的,直到前几个星期才把这些问题全部搞明白了。 
    废话不多说了,先来看一下JDK的动态是怎么用的。 
执行结果如下: 
------------------before------------------ 
--------------------add--------------- 
-------------------after------------------ 
   用起来是很简单吧,其实这里基本上就是AOP的一个简单实现了,在目标对象的方法执行之前和执行之后进行了增强。Spring的AOP实现其实也是用了Proxy和InvocationHandler这两个东西的。 
    用起来是比较简单,但是如果能知道它背后做了些什么手脚,那就更好不过了。首先来看一下JDK是怎样生成代理对象的。既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么? 
- public static Object newProxyInstance(ClassLoader loader,  
-                       Class<?>[] interfaces,  
-                       InvocationHandler h)  
-     throws IllegalArgumentException  
-     {  
-     if (h == null) {  
-         throw new NullPointerException();  
-     }  
-   
-     
-     Class cl = getProxyClass(loader, interfaces);  
-   
-     
-     try {  
-             
-         Constructor cons = cl.getConstructor(constructorParams);  
-             
-         return (Object) cons.newInstance(new Object[] { h });  
-     } catch (NoSuchMethodException e) {  
-         throw new InternalError(e.toString());  
-     } catch (IllegalAccessException e) {  
-         throw new InternalError(e.toString());  
-     } catch (InstantiationException e) {  
-         throw new InternalError(e.toString());  
-     } catch (InvocationTargetException e) {  
-         throw new InternalError(e.toString());  
-     }  
-     }  
 
   我们再进去getProxyClass方法看一下 
- public static Class<?> getProxyClass(ClassLoader loader,   
-                                          Class<?>... interfaces)  
-     throws IllegalArgumentException  
-     {  
-     
-     if (interfaces.length > 65535) {  
-         throw new IllegalArgumentException("interface limit exceeded");  
-     }  
-   
-     
-     Class proxyClass = null;  
-   
-     String[] interfaceNames = new String[interfaces.length];  
-   
-     Set interfaceSet = new HashSet();   
-   
-     
-     for (int i = 0; i < interfaces.length; i++) {  
-           
-         
-         String interfaceName = interfaces[i].getName();  
-         Class interfaceClass = null;  
-         try {  
-         
-         interfaceClass = Class.forName(interfaceName, false, loader);  
-         } catch (ClassNotFoundException e) {  
-         }  
-         if (interfaceClass != interfaces[i]) {  
-         throw new IllegalArgumentException(  
-             interfaces[i] + " is not visible from class loader");  
-         }  
-   
-         
-           
-         
-         interfaceSet.add(interfaceClass);  
-   
-         interfaceNames[i] = interfaceName;  
-     }  
-   
-     
-     Object key = Arrays.asList(interfaceNames);  
-   
-     Map cache;  
-       
-     synchronized (loaderToCache) {  
-         
-         cache = (Map) loaderToCache.get(loader);  
-         if (cache == null) {  
-         
-         cache = new HashMap();  
-         
-         loaderToCache.put(loader, cache);  
-         }  
-   
-     }  
-   
-     synchronized (cache) {  
-   
-         do {  
-         
-         Object value = cache.get(key);  
-         if (value instanceof Reference) {  
-             proxyClass = (Class) ((Reference) value).get();  
-         }  
-         if (proxyClass != null) {  
-             
-             return proxyClass;  
-         } else if (value == pendingGenerationMarker) {  
-             try {  
-             cache.wait();  
-             } catch (InterruptedException e) {  
-             }  
-             continue;  
-         } else {  
-             cache.put(key, pendingGenerationMarker);  
-             break;  
-         }  
-         } while (true);  
-     }  
-   
-     try {  
-         
-           
-         
-         byte[] proxyClassFile = ProxyGenerator.generateProxyClass(  
-             proxyName, interfaces);  
-         try {  
-             
-             proxyClass = defineClass0(loader, proxyName,  
-             proxyClassFile, 0, proxyClassFile.length);  
-         } catch (ClassFormatError e) {  
-             throw new IllegalArgumentException(e.toString());  
-         }  
-         }  
-         
-         proxyClasses.put(proxyClass, null);  
-   
-     }   
-     
-       
-     return proxyClass;  
-     }  
 
进去ProxyGenerator类的静态方法generateProxyClass,这里是真正生成代理类class字节码的地方。 
- public static byte[] generateProxyClass(final String name,  
-                                            Class[] interfaces)  
-    {  
-        ProxyGenerator gen = new ProxyGenerator(name, interfaces);  
-     
-        final byte[] classFile = gen.generateClassFile();  
-   
-     
-        if (saveGeneratedFiles) {  
-            java.security.AccessController.doPrivileged(  
-            new java.security.PrivilegedAction<Void>() {  
-                public Void run() {  
-                    try {  
-                        FileOutputStream file =  
-                            new FileOutputStream(dotToSlash(name) + ".class");  
-                        file.write(classFile);  
-                        file.close();  
-                        return null;  
-                    } catch (IOException e) {  
-                        throw new InternalError(  
-                            "I/O exception saving generated file: " + e);  
-                    }  
-                }  
-            });  
-        }  
-   
-     
-        return classFile;  
-    }  
 
现在,JDK是怎样动态生成代理类的字节的原理已经一目了然了。 
好了,再来解决另外一个问题,那就是由谁来调用InvocationHandler的invoke方法的。要解决这个问题就要看一下JDK到底为我们生成了一个什么东西。用以下代码可以获取到JDK为我们生成的字节码并写到硬盘中。 
- package dynamic.proxy;   
-   
- import java.io.FileOutputStream;  
- import java.io.IOException;  
-   
- import sun.misc.ProxyGenerator;  
-   
- public class ProxyGeneratorUtils {  
-   
-     
-     public static void writeProxyClassToHardDisk(String path) {  
-         
-         
-           
-         
-           
-         
-         byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", UserServiceImpl.class.getInterfaces());  
-           
-         FileOutputStream out = null;  
-           
-         try {  
-             out = new FileOutputStream(path);  
-             out.write(classFile);  
-             out.flush();  
-         } catch (Exception e) {  
-             e.printStackTrace();  
-         } finally {  
-             try {  
-                 out.close();  
-             } catch (IOException e) {  
-                 e.printStackTrace();  
-             }  
-         }  
-     }  
- }  
-   
- package dynamic.proxy;   
-   
- import org.junit.Test;  
-   
- public class ProxyTest {  
-   
-     @Test  
-     public void testProxy() throws Throwable {  
-         
-         UserService userService = new UserServiceImpl();  
-           
-         
-         MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);  
-           
-         
-         UserService proxy = (UserService) invocationHandler.getProxy();  
-           
-         
-         proxy.add();  
-           
-     }  
-       
-     @Test  
-     public void testGenerateProxyClass() {  
-         ProxyGeneratorUtils.writeProxyClassToHardDisk("F:/$Proxy11.class");  
-     }  
- }  
 
通过以上代码,就可以在F盘上生成一个$Proxy.class文件了,现在用反编译工具来看一下这个class文件里面的内容。 
-   
- import dynamic.proxy.UserService;  
- import java.lang.reflect.*;  
-   
- public final class $Proxy11 extends Proxy  
-     implements UserService  
- {  
-   
-     
-     public $Proxy11(InvocationHandler invocationhandler)  
-     {  
-         super(invocationhandler);  
-     }  
-   
-     public final boolean equals(Object obj)  
-     {  
-         try  
-         {  
-             return ((Boolean)super.h.invoke(this, m1, new Object[] {  
-                 obj  
-             })).booleanValue();  
-         }  
-         catch(Error _ex) { }  
-         catch(Throwable throwable)  
-         {  
-             throw new UndeclaredThrowableException(throwable);  
-         }  
-     }  
-   
-     
-     public final void add()  
-     {  
-         try  
-         {  
-             
-             super.h.invoke(this, m3, null);  
-             return;  
-         }  
-         catch(Error _ex) { }  
-         catch(Throwable throwable)  
-         {  
-             throw new UndeclaredThrowableException(throwable);  
-         }  
-     }  
-   
-     public final int hashCode()  
-     {  
-         try  
-         {  
-             return ((Integer)super.h.invoke(this, m0, null)).intValue();  
-         }  
-         catch(Error _ex) { }  
-         catch(Throwable throwable)  
-         {  
-             throw new UndeclaredThrowableException(throwable);  
-         }  
-     }  
-   
-     public final String toString()  
-     {  
-         try  
-         {  
-             return (String)super.h.invoke(this, m2, null);  
-         }  
-         catch(Error _ex) { }  
-         catch(Throwable throwable)  
-         {  
-             throw new UndeclaredThrowableException(throwable);  
-         }  
-     }  
-   
-     private static Method m1;  
-     private static Method m3;  
-     private static Method m0;  
-     private static Method m2;  
-   
-     
-     static   
-     {  
-         try  
-         {  
-             m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {  
-                 Class.forName("java.lang.Object")  
-             });  
-             m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", new Class[0]);  
-             m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);  
-             m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);  
-         }  
-         catch(NoSuchMethodException nosuchmethodexception)  
-         {  
-             throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
-         }  
-         catch(ClassNotFoundException classnotfoundexception)  
-         {  
-             throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
-         }  
-     }  
- }  
 
好了,到目前为止,前面 的两个问题都已经知道回事了,现在再用JDK动态代理的时候就不只会用而已了,真正的达到了“知其然,知其所以然”的目的。。。 
  
  
 
就写到这了,累死了。。 
  
 
原文地址:http://rejoy.iteye.com/blog/1627405
JDK动态代理实现原理--转载
标签:des   blog   http   io   os   ar   java   for   strong   
原文地址:http://www.cnblogs.com/davidwang456/p/4045412.html