zoukankan      html  css  js  c++  java
  • Spring源码分析-JDK动态代理原理

    一、JDK动态代理实现

    接口

    public interface UserService {
        void findAll();
    }

    实现类

    public class UserServiceImpl implements UserService {
    
        public void findAll() {
            System.out.println("findAll。。。");
        }
    }

    定义一个代理类,并实现 InvocationHandler 接口

    public class MyJdkProxy implements InvocationHandler {
        private Object target;
    
        /**
         * 绑定业务对象并返回一个代理类
         */
        public Object createProxy(Object target) {
            this.target = target;
            // 通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
            // 创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
            return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    
        /**
         * 包装调用方法:进行预处理、调用后处理
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = null;
            System.out.println("预处理操作——————");
            // 调用真正的业务方法
            result = method.invoke(target, args);
    
            System.out.println("调用后处理——————");
            return result;
        }
    
    }

    测试类

    public class Test {
        public static void main(String[] args) {
            MyJdkProxy jdkProxy = new MyJdkProxy();
            UserService userService = (UserService) jdkProxy.createProxy(new UserServiceImpl());
            userService.findAll();
        }
    }

     

    二、JDK动态代理,在什么时候执行invoke 方法?

    我们再来一个测试,通过生成的代理类直接执行toString() 方法,发现invoke 方法也被调用了一次。那么这是为什么?是什么时候调用了invoke?

    public static void main(String[] args) {
        MyJdkProxy jdkProxy = new MyJdkProxy();
        UserService userService = (UserService) jdkProxy.createProxy(new UserServiceImpl());
        userService.toString(); 
    }

    在MyJdkProxy 类中,生成代理类有一个核心方法 Proxy.newProxyInstance 方法

    public Object createProxy(Object target) {
        this.target = target;
        // 通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
        // 创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    我们再来看一下这个 newProxyInstance 方法

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException  {
        // 如果目标代理类为空,抛出异常
        if (h == null) {
            throw new NullPointerException();
        }
    
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
    
        /*
         * Look up or generate the designated proxy class.
         */
        // 关键代码:生成接口的代理类的字节码文件
        Class<?> cl = getProxyClass0(loader, intfs);
    
        /*
         * Invoke its constructor with the designated invocation handler.
         * 通过反射获取构造函数对象并生成代理类实例
         */
        try {
            // 获取代理对象的构造方法(也就是$Proxy0(InvocationHandler h))
            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());
        }
    }

    找到关键代码:Class<?> cl = getProxyClass0(loader, intfs);

    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        // 限定代理的接口不能超过65535个
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
    
        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        // 关键代码:如果缓存中已经存在相应接口的代理类,直接返回;否则,使用ProxyClassFactory创建代理类
        return proxyClassCache.get(loader, interfaces);
    }

    这里 proxyClassCache 中一个 WeakCache 类型

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

    再来看一下这个WeakCache 中的 get 方法

    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);
    
        expungeStaleEntries();
    
        Object cacheKey = CacheKey.valueOf(key, refQueue);
    
        // lazily install the 2nd level valuesMap for the particular cacheKey
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }
    
        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        // 核心代码:当WeakCache中没有缓存相应接口的代理类,则会调用ProxyClassFactory类的apply方法来创建代理类
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;
    
        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)
    
            // lazily construct a Factory
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }
    
            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

    ProxyClassFactory 是Proxy的一个内部类,主要有一个apply 方法

        private static final class ProxyClassFactory
            implements BiFunction<ClassLoader, Class<?>[], Class<?>>
        {
            // 代理类前缀
            private static final String proxyClassNamePrefix = "$Proxy";
    
            // 生成代理类名称的计数器
            private static final AtomicLong nextUniqueNumber = new AtomicLong();
    
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
                Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
                for (Class<?> intf : interfaces) {
                    /*
                     * Verify that the class loader resolves the name of this
                     * interface to the same Class object.
                     * 校验类加载器是否能通过接口名称加载该类
                     */
                    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");
                    }
                    /*
                     * 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.put(interfaceClass, Boolean.TRUE) != null) {
                        throw new IllegalArgumentException(
                            "repeated interface: " + interfaceClass.getName());
                    }
                }
                // 代理类包名
                String proxyPkg = null;     // package to define proxy class in
    
                /*
                 * Record the package of a non-public proxy interface so that the
                 * proxy class will be defined in the same package.  Verify that
                 * all non-public proxy interfaces are in the same package.
                 * 非public接口,代理类的包名与接口的包名相同
                 */
                for (Class<?> intf : interfaces) {
                    int flags = intf.getModifiers();
                    if (!Modifier.isPublic(flags)) {
                        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
                    // public代理接口,使用com.sun.proxy包名
                    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                }
    
                /*
                 * Choose a name for the proxy class to generate.
                 * 为代理类生成名字
                 */
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                /*
                 * Generate the specified proxy class.
                 */
                 // 核心代码:真正生成代理类的字节码文件的地方
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
                try {
                    // 使用类加载器将代理类的字节码文件加载到JVM中
                    return defineClass0(loader, proxyName,
                                        proxyClassFile, 0, proxyClassFile.length);
                } catch (ClassFormatError e) {
                    /*
                     * A ClassFormatError here means that (barring bugs in the
                     * proxy class generation code) there was some other
                     * invalid aspect of the arguments supplied to the proxy
                     * class creation (such as virtual machine limitations
                     * exceeded).
                     */
                    throw new IllegalArgumentException(e.toString());
                }
            }
        }

    仔细看这段代码,终于找到了其最核心的代码:

    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);  // 生成字节码文件
    

      

    编写测试类,并生成一个代理类的class文件

    public class Test {
        public static void main(String[] args) {
            jdkTest();
            createProxyClassFile();
        }
    
        public static void jdkTest() {
            MyJdkProxy jdkProxy = new MyJdkProxy();
            UserService userService = (UserService) jdkProxy.createProxy(new UserServiceImpl());
            userService.hashCode();
        }
        /**
         * 生成代理类.class文件
         */
        private static void createProxyClassFile() {
            // 设置生成.class文件名称
            String name = "UserServiceProxy";
            byte[] data = ProxyGenerator.generateProxyClass(name, new Class[] { UserService.class });
            FileOutputStream out = null;
            try {
                out = new FileOutputStream(name + ".class");
                // 打印hello文件所在目录,方便找到生成的 UserServiceProxy.class 文件
                System.out.println((new File("hello")).getAbsolutePath());
                out.write(data);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (null != out)
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            }
        }
    }

    用jd-jui 工具将生成的字节码反编译:

    import com.service.UserService;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class UserServiceProxy extends Proxy implements UserService {
      private static Method m3;
      
      private static Method m1;
      
      private static Method m0;
      
      private static Method m2;
      
      public ProxySubject(InvocationHandler paramInvocationHandler) {
        super(paramInvocationHandler);
      }
      // UserService 中的 findAll() 方法
      public final void findAll() {
        try {
          this.h.invoke(this, m3, null);
          return;
        } catch (Error|RuntimeException error) {
          throw null;
        } catch (Throwable throwable) {
          throw new UndeclaredThrowableException(throwable);
        } 
      }
      
      public final boolean equals(Object paramObject) {
        try {
          return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        } catch (Error|RuntimeException error) {
          throw null;
        } catch (Throwable throwable) {
          throw new UndeclaredThrowableException(throwable);
        } 
      }
      
      public final int hashCode() {
        try {
          return ((Integer)this.h.invoke(this, m0, null)).intValue();
        } catch (Error|RuntimeException error) {
          throw null;
        } catch (Throwable throwable) {
          throw new UndeclaredThrowableException(throwable);
        } 
      }
      
      public final String toString() {
        try {
          return (String)this.h.invoke(this, m2, null);
        } catch (Error|RuntimeException error) {
          throw null;
        } catch (Throwable throwable) {
          throw new UndeclaredThrowableException(throwable);
        } 
      }
      
      static {
        try {
          m3 = Class.forName("com.service.UserService").getMethod("findAll", new Class[0]);
          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 noSuchMethodException) {
          throw new NoSuchMethodError(noSuchMethodException.getMessage());
        } catch (ClassNotFoundException classNotFoundException) {
          throw new NoClassDefFoundError(classNotFoundException.getMessage());
        } 
      }
    }

    我们发现这个类的 toString()、hashCode()、equals 以及 findAll() 方法都是通过  this.h.invoke(this, m1, null) 调用。其中 h 为 InvocationHandler 类型。

    由此可总结:在使用jdk动态代理时,相当于会生成一个代理类 ***Proxy.class 文件(实际上并不生成文件,而是以字节码的形式直接加载到JVM中)

  • 相关阅读:
    CSS常见兼容性问题
    Ubuntu系统下创建python数据挖掘虚拟环境
    Django 模板中引用静态资源(js,css等)
    Django auth 登陆后页面跳转至/account/profile,修改跳转至其他页面
    Ubuntu14.04安装配置SVN及Trac
    禁止Chrome浏览器缓存的方法
    windows下安装配置Xampp
    Linux系统下用C语言获取MAC地址
    使用axios+formdata+vue上传图片遇到后台接受不到图片的值的问题
    使用vee-validate表单插件是如何设置中文提示?
  • 原文地址:https://www.cnblogs.com/caoxb/p/12405866.html
Copyright © 2011-2022 走看看