JAVA动态代理(proxy)实现和源码剖析

JDK动态代理实例

(1)动态代理首先提供一个调度处理器接口(Invocationhandler),该接口实例封装了我们要代理的对象实例的数据。

    public class TranceHander implements InvocationHandler{  
        private Object tObject;  
        public TranceHander(Object t){  
            tObject=t;  
        }  
        @Override  
        public Object invoke(Object proxy, Method method, Object[] args)  
                throws Throwable {  
            // TODO Auto-generated method stub  
            System.out.println("被代理对象:"+tObject);  
            System.out.println("方法:"+method.getName());  
            return method.invoke(tObject,args);//方法反射  
        }  
    }  

(2)使用Proxy类的newProxyInstance方法创建代理对象或getProxyClass方法获得代理类Class。

测试mian方法中,写了一个代理类,从1-1000的整数数组中使用二分查找随机查找一个整数,实现对象比较和toString接口代理

    public class ProxyTest {  

        /** 
         * @param args 
         */  
        public static void main(String[] args) {  
            // TODO Auto-generated method stub  
            Object[] elements=new Object[1000];  
            for(int i=0;i<elements.length;i++){  
                Integer value=i+1;//被代理对象  
                InvocationHandler handler=new TranceHander(value);//构建调度处理器  
                Object proxy=Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);  
                elements[i]=proxy;  
            }  
            Integer key=new Random().nextInt(1000)+1;  
            int res=Arrays.binarySearch(elements, key);  
            if(res>=0){  
                System.out.println(elements[res].toString());  
            }  
            System.out.println("查找Key:"+key);  
        }  
    }  

JDK源码实现原理分析

(1)代理对象生成:

    Object proxy=Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);  

(2)查看Proxy类的newProxyInstance方法
从生成对象方法中,我们看到三个关键的地方:

Class<?> cl = getProxyClass0(loader, interfaces);//得到代理类
final Constructor<?> cons = cl.getConstructor(constructorParams);   
newInstance(cons, ih);//将InvocationHandler h传入代理对象中
    public static Object newProxyInstance(ClassLoader loader,  
                                          Class<?>[] interfaces,  
                                          InvocationHandler h)  
        throws IllegalArgumentException  
    {  
        if (h == null) {  
            throw new NullPointerException();  
        }  

        final SecurityManager sm = System.getSecurityManager();  
        if (sm != null) {  
            checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);  
        }  

        /* 
         * Look up or generate the designated proxy class. 
         */  
        Class<?> cl = getProxyClass0(loader, interfaces);  

        /* 
         * Invoke its constructor with the designated invocation handler. 
         */  
        try {  
            final Constructor<?> cons = cl.getConstructor(constructorParams);  
            final InvocationHandler ih = h;  
            if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {  
                // create proxy instance with doPrivilege as the proxy class may  
                // implement non-public interfaces that requires a special permission  
                return AccessController.doPrivileged(new PrivilegedAction<Object>() {  
                    public Object run() {  
                        return newInstance(cons, ih);  
                    }  
                });  
            } else {  
                return newInstance(cons, ih);  
            }  
        } catch (NoSuchMethodException e) {  
            throw new InternalError(e.toString());  
        }  
    }  

(3)生成Proxy类,查看getProxyClass0方法,

这个方法有点长,抽取关键的地方:
1.先抽取被代理类实现的接口Interface,检测是否符合要求

    /* collect interface names to use as key for proxy class cache */  
    String[] interfaceNames = new String[interfaces.length];  

    // for detecting duplicates  
    Set<Class<?>> interfaceSet = new HashSet<>();  

    for (int i = 0; i < interfaces.length; i++) {  
        /* 
         * Verify that the class loader resolves the name of this 
         * interface to the same Class object. 
         */  
        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");  
        }  

        /* 
         * Verify that the Class object actually represents an 
         * interface. 
         */  
        if (!interfaceClass.isInterface()) {  
            throw new IllegalArgumentException(  
                interfaceClass.getName() + " is not an interface");  
        }  

        /* 
         * Verify that this interface is not a duplicate. 
         */  
        if (interfaceSet.contains(interfaceClass)) {  
            throw new IllegalArgumentException(  
                "repeated interface: " + interfaceClass.getName());  
        }  
        interfaceSet.add(interfaceClass);  

        interfaceNames[i] = interfaceName;  
    }  

查看代理对象缓存中是否有我们要创建的代理类,如果有,直接获取;没有则创建
如果有则: return proxyClassCache.get(loader, interfaces);
没有则创建,先定义代理类的包名,如果所有的接口都是公共的,则默认将创建的类放在String PROXY_PACKAGE = “com.sun.proxy”;中,若果存在
非public接口则所有的非public接口必须在同一包下,代理类也放在此包下,否则系统抛异常。

    <span style="white-space:pre">    </span>   for (int i = 0; i < interfaces.length; i++) {  
                   int flags = interfaces[i].getModifiers();  
                   if (!Modifier.isPublic(flags)) {  
                       String name = interfaces[i].getName();  
                       int n = name.lastIndexOf('.');  
                       String pkg = ((n == -1) ? "" : name.substring(0, n + 1));  
                       if (proxyPkg == null) {  
                           proxyPkg = pkg;  
                       } else if (!pkg.equals(proxyPkg)) {  
                           throw new IllegalArgumentException(  
                               "non-public interfaces from different packages");  
                       }  
                   }  
               }  

               if (proxyPkg == null) {  
                   // if no non-public proxy interfaces, use com.sun.proxy package  
                   proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";  
               }  

接下来创建类,和将字节码写入类文件中:

    byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);  
    proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);  
    return proxyClass;  

(4)创建代理实例,将

newInstance(cons, ih);//将InvocationHandler h传入代理对象中

看完源码,我还是有点困惑,直到我看到生成的代理类文件源码后,豁然开朗。其实主要一步就在于生成类
的过程,类文件中建立被代理对象接口的invoke调用,话不多说看源码(我直接在测试用例调用的ProxyGenerator.generateProxyClass( proxyName, interfaces)接口生成的)

    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        Integer value=1;  
        InvocationHandler handler=new TranceHander(value);//构建调度处理器  
        Object proxy=Proxy.newProxyInstance(null, Integer.class.getInterfaces(), handler);  
        String path = "D://aaa.class";    
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0",Integer.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();    
               }    
           }    
    }  

接着看class文件的反编译源码吧,直接用的Method的反射机制实现的代理,equal、hascode、toString方法是所有类都有的,compareTo则是被代理对象的实现接口:

    import java.lang.reflect.InvocationHandler;  
    import java.lang.reflect.Method;  
    import java.lang.reflect.Proxy;  
    import java.lang.reflect.UndeclaredThrowableException;  

    public final class $Proxy0 extends Proxy  
      implements Comparable  
    {  
      private static Method m3;  
      private static Method m1;  
      private static Method m0;  
      private static Method m2;  

      public $Proxy0(InvocationHandler paramInvocationHandler)  
        throws   
      {  
        super(paramInvocationHandler);  
      }  

      public final int compareTo(Object paramObject)  
        throws   
      {  
        try  
        {  
          return ((Integer)this.h.invoke(this, m3, new Object[] { paramObject })).intValue();  
        }  
        catch (Error|RuntimeException localError)  
        {  
          throw localError;  
        }  
        catch (Throwable localThrowable)  
        {  
          throw new UndeclaredThrowableException(localThrowable);  
        }  
      }  

      public final boolean equals(Object paramObject)  
        throws   
      {  
        try  
        {  
          return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();  
        }  
        catch (Error|RuntimeException localError)  
        {  
          throw localError;  
        }  
        catch (Throwable localThrowable)  
        {  
          throw new UndeclaredThrowableException(localThrowable);  
        }  
      }  

      public final int hashCode()  
        throws   
      {  
        try  
        {  
          return ((Integer)this.h.invoke(this, m0, null)).intValue();  
        }  
        catch (Error|RuntimeException localError)  
        {  
          throw localError;  
        }  
        catch (Throwable localThrowable)  
        {  
          throw new UndeclaredThrowableException(localThrowable);  
        }  
      }  

      public final String toString()  
        throws   
      {  
        try  
        {  
          return (String)this.h.invoke(this, m2, null);  
        }  
        catch (Error|RuntimeException localError)  
        {  
          throw localError;  
        }  
        catch (Throwable localThrowable)  
        {  
          throw new UndeclaredThrowableException(localThrowable);  
        }  
      }  

      static  
      {  
        try  
        {  
          m3 = Class.forName("java.lang.Comparable").getMethod("compareTo", new Class[] { Class.forName("java.lang.Object") });  
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });  
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);  
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);  
          return;  
        }  
        catch (NoSuchMethodException localNoSuchMethodException)  
        {  
          throw new NoSuchMethodError(localNoSuchMethodException.getMessage());  
        }  
        catch (ClassNotFoundException localClassNotFoundException)  
        {  
          throw new NoClassDefFoundError(localClassNotFoundException.getMessage());  
        }  
      }  
    }  
首先声明,这段源代码不是我编写的,让我们感谢这位名叫Carl Harris的大虾,是他编写了这段代码并将其散播到网上供大家学习讨论。这段代码虽然只是描述了最简单的proxy操作,但它的确是经典,它不仅清晰地描述了客户机/服务器系统的概念,而且几乎包括了Linux网络编程的方方面面,非常适合Linux网络编程的初学者学习。   这段Proxy程序的用法是这样的,我们可以使用这个proxy登录其它主机的服务端口。假如编译后生成了名为Proxy的可执行文件,那么命令及其参数的描述为:    ./Proxy   其中参数proxy_port是指由我们指定的代理服务器端口。参数remote_host是指我们希望连接的远程主机的主机名,IP地址也同样有效。这个主机名在网络上应该是唯一的,如果您不确定的话,可以在远程主机上使用uname -n命令查看一下。参数service_port是远程主机可提供的服务名,也可直接键入服务对应的端口号。这个命令的相应操作是将代理服务器的proxy_port端口绑定到remote_host的service_port端口。然后我们就可以通过代理服务器的proxy_port端口访问remote_host了。例如一台计算机,网络主机名是legends,IP地址为10.10.8.221,如果在我的计算机上执行:    [root@lee /root]#./proxy 8000 legends telnet   那么我们就可以通过下面这条命令访问legends的telnet端口。 ----------------------------------------------------------------- [root@lee /root]#telnet legends 8000 Trying 10.10.8.221... Connected to legends(10.10.8.221). Escape character is '^]' Red Hat Linux release 6.2(Zoot) Kernel 2.2.14-5.0 on an i686 Login: -----------------------------------------------------------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值