美文网首页
【原理】:JDK动态代理源码分析

【原理】:JDK动态代理源码分析

作者: Jorgezhong | 来源:发表于2019-06-25 15:14 被阅读0次

    总结】:JDK动态代理的原理是通过目标对象提供的classloader、interfaces的Class对象数组、InvocatiionHandler提供的代理逻辑来重新定义并在内存生成一个代理类的class文件并且通过构造器对象实例化并返回。使得用户使用代理类对象调用业务接口方法的时候,调用的是invocationHandlerinvoke方法,最终完成代理。

    • 都很熟悉的以下这段代码,JDK的动态代理,使用Proxy.newProxyInstance()获得代理对象,并且提供InvocationHandler来设置前置和后置处理的相关代码。今天看看它的源码
    public interface ISinger {
        void sing();
    }
    
    public class Singer implements ISinger {
        @Override
        public void sing() {
            System.out.println("唱一会儿歌");
        }
    }
    
    
    public class Test {
    
        public static void main(String[] args) {
    
            Singer target = new Singer();
    
            Object proxyInstance = Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    (proxy, method, args1) -> {
                        System.out.println("代理前:向观众问好");
                        Object returnValue = method.invoke(target, args1);
                        System.out.println("代理后:向观众问好");
                        return returnValue;
                    });
    
            ISinger singerProxy = (ISinger) proxyInstance;
    
            singerProxy.sing();
        }
    
    }
    
    

    newProxyInstance主要做了三件事情,

    1. 生产制定的代理类
    2. 获取构造器对象
    3. 使用构造器对象实例化代理对象
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            //判空
            Objects.requireNonNull(h);
            
            //克隆该类实现的所有接口
            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.
             * 使用制定的 invocation handler 调用构造器
             */
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
                /**
                 * 常量 constructorParams:
                 * private static final Class<?>[] constructorParams = { InvocationHandler.class };
                 **/
                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;
                        }
                    });
                }
                // 通过构造器对象来实例化代理对象并返回
                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);
            }
        }
    

    getProxyClass0()具体负责生成代理类

        private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
            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);
        }
    

    ProxyClassFactory.apply()完成了代理对象字节码的生成

        private static final class ProxyClassFactory
            implements BiFunction<ClassLoader, Class<?>[], Class<?>>
        {
    
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
              
                //此处省略了一大堆代码……(主要是接口、包和其他一些类文件相关的校验)
    
                /*
                 * Generate the specified proxy class.
                 * 关键在这里,生成了代理对象的字节码
                 */
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
                try {
                    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());
                }
            }
        }
    
    

    由于jdk8的源码到上面的部分就到了native方法了,因此以下内容参考了其他博主的内容[1]进行学习

    public static byte[] generateProxyClass(final String name, Class<?>[] interfaces, int accessFlags) {
            ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
            // 真正生成字节码的方法
            final byte[] classFile = gen.generateClassFile();
            // 如果saveGeneratedFiles为true 则生成字节码文件,所以在开始我们要设置这个参数
            // 当然,也可以通过返回的bytes自己输出
            if (saveGeneratedFiles) {
                java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() {
                            public Void run() {
                                try {
                                    int i = name.lastIndexOf('.');
                                    Path path;
                                    if (i > 0) {
                                        Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
                                        Files.createDirectories(dir);
                                        path = dir.resolve(name.substring(i+1, name.length()) + ".class");
                                    } else {
                                        path = Paths.get(name + ".class");
                                    }
                                    Files.write(path, classFile);
                                    return null;
                                } catch (IOException e) {
                                    throw new InternalError( "I/O exception saving generated file: " + e);
                                }
                            }
                        });
            }
            return classFile;
        }
    

    阅读参考文献法发现生成的代理对象是继承了Proxy类并且会实现用户定义的接口,这里是ISinger接口。因此获得代理对象之后可以进行强转并且进行调用。


    参考文献:


    1. JDK动态代理实现原理(jdk8)

    相关文章

      网友评论

          本文标题:【原理】:JDK动态代理源码分析

          本文链接:https://www.haomeiwen.com/subject/skitcctx.html