• jdk动态代理原理


    上篇主要说明了jdk动态代理的基本使用,这篇文章主要说说jdk底层是怎么实现的

    这里源码版本是1.8.0-b132

    首先来看看它是如何生成代理类的:

     @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
    
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
            }
    
            /*
             *查找或生成指定的代理类
             */
            Class<?> cl = getProxyClass0(loader, interfaces);
    
        
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
    
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
                //使用带有InvocationHandler 的构造函数生成代理类的实例  
                return cons.newInstance(new Object[]{h});
            } catch (IllegalAccessException|InstantiationException e) {
                throw new InternalError(e.toString(), e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else {
                    throw new InternalError(t.toString(), t);
                }
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
        }
    

      接下里我们看看是怎么生成代理类的 也就是

    Class<?> cl = getProxyClass0(loader, interfaces); 这个getProxyClass0方法
       private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
            if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
    
      // 如果已经存在相应的代理类,则直接返回,否则才会通过ProxyClassFactory
      //  来创建代理
            return proxyClassCache.get(loader, interfaces);
        }
    

      

    接下来我们看看proxyClassCache是怎么实现的

    源代码里面有

     private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
            proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    

      

    具体的缓存逻辑这里我们暂时不关心

    这里主要关注ProxyClassFactory的实现

    ProxyClassFactoryProxy的一个静态内部类,实现了WeakCache的内部接口BiFunctionapply方法,主要作用是 根据给定的接口数组以及类加载器 生成代理类

     private static final class ProxyClassFactory
            implements BiFunction<ClassLoader, Class<?>[], Class<?>>
        {
            // 代理类前缀
            private static final String proxyClassNamePrefix = "$Proxy";
    
            // next number to use for generation of unique proxy class names
            private static final AtomicLong nextUniqueNumber = new AtomicLong();
            //返回该代理类的class实例
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
                Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
                for (Class<?> intf : interfaces) {
               
                    Class<?> interfaceClass = null;
                    try {
                        interfaceClass = Class.forName(intf.getName(), false, loader);
                    } catch (ClassNotFoundException e) {
                    }
                    if (interfaceClass != intf) {
                        throw new IllegalArgumentException(
                            intf + " is not visible from class loader");
                    }
                
                    if (!interfaceClass.isInterface()) {
                        throw new IllegalArgumentException(
                            interfaceClass.getName() + " is not an interface");
                    }
                
                    if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                        throw new IllegalArgumentException(
                            "repeated interface: " + interfaceClass.getName());
                    }
                }
    
                String proxyPkg = null;     // package to define proxy class in
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
                for (Class<?> intf : interfaces) {
                    int flags = intf.getModifiers();
                    if (!Modifier.isPublic(flags)) {
                        accessFlags = Modifier.FINAL;
                        String name = intf.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 + ".";
                }
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                /*
                 * 生成代理类的字节码 
                 */
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
                try {
                   //根据字节码生成Class实例  
                    return defineClass0(loader, proxyName,
                                        proxyClassFile, 0, proxyClassFile.length);
                } catch (ClassFormatError e) {
                 
                    throw new IllegalArgumentException(e.toString());
                }
            }
        }
    

      

    默认情况 生成的代理没保存在本地

    我们可以通过 在添加以下代码 保存动态代理类生成到本地 

     System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  

    接下来我们来分析下生成的代理类 

    package com.sun.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    import proxyAop.UserService;
    
    public final class $Proxy0 extends Proxy
      implements UserService
    {
      private static Method m1;
      private static Method m2;
      private static Method m3;
      private static Method m0;
    
      public $Proxy0(InvocationHandler paramInvocationHandler)
        throws 
      {
        super(paramInvocationHandler);
      }
    
      public final boolean equals(Object paramObject)
        throws 
      {
        try
        {
          return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        }
        catch (RuntimeException localRuntimeException)
        {
          throw localRuntimeException;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
    
      public final String toString()
        throws 
      {
        try
        {
          return ((String)this.h.invoke(this, m2, null));
        }
        catch (RuntimeException localRuntimeException)
        {
          throw localRuntimeException;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
    
      public final void add()
        throws 
      {
        try
        {
          this.h.invoke(this, m3, null);
          return;
        }
        catch (RuntimeException localRuntimeException)
        {
          throw localRuntimeException;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
    
      public final int hashCode()
        throws 
      {
        try
        {
          return ((Integer)this.h.invoke(this, m0, null)).intValue();
        }
        catch (RuntimeException localRuntimeException)
        {
          throw localRuntimeException;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
    
      static
      {
        try
        {
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          m3 = Class.forName("proxyAop.UserService").getMethod("add", new Class[0]);
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
          return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
          throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
          throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
      }
    }
    

    可以看到:

    该代理类继承了Proxy类,实现了代理的接口,由于java是单继承,这里已经继承了Proxy类了,不能再继承其他的类,

    所以JDK的动态代理不支持对实现类的代理,只支持对接口的代理。

    并提供了一个使用InvocationHandler作为参数的构造方法。

    通过静态代码块来初始化接口中的Method对象,以及Object类的equalshashCodetoString方法。

    当代理类调用相关方法的时候 会执行生成该代理类所实例化的InvocationHandler的对象的 invoke方法。

  • 相关阅读:
    Keep at Most 100 Characters
    Larry and Inversions
    计算指数
    简单题
    重要的话说三遍
    I Love GPLT
    猜数字
    打印沙漏
    多态性(polymorphism),封装性(encapsulation),内聚(cohesion)以及耦合(coupling)的基本概念
    Hibernate面试题
  • 原文地址:https://www.cnblogs.com/javabigdata/p/7518163.html
Copyright © 2020-2023  润新知