美文网首页
代理之JDK动态代理原理(1)2018-07-27

代理之JDK动态代理原理(1)2018-07-27

作者: Seetheworl_6675 | 来源:发表于2018-07-28 21:31 被阅读0次

    回顾:

        上一篇代理之JDK动态代理我们了解来JDK动态代理的使用。同样也遗留了两个问题:1、代理对象是怎么生成的?2、InvocationHandler的invoke方法是由谁来调用的?

    jdk动态代理源码:

        首先来看一下JDK是怎样生成代理对象的。既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么?

    Java1.8 源码(以下代码代码不全,只截取关键性代码):

    /**  

    * loader:类加载器  

    * interfaces:目标对象实现的接口  

    * h:InvocationHandler的实现类  

    */  

    public static Object newProxyInstance(ClassLoader loader,Class[] interfaces,                  

                                        InvocationHandler h)throws IllegalArgumentException{

        //判断h不能为null。为null 抛出:NullPointerException

         Objects.requireNonNull(h);

        final Class[] intfs = interfaces.clone();

            //查找或生成指定的代理类

           Class cl =getProxyClass0(loader, intfs);

          try {

            //获取构造方法

            final Constructor cons = cl.getConstructor();

            final InvocationHandler ih = h;

            //如果构造方法不是public 设置构造方法为可访问

            if (!Modifier.isPublic(cl.getModifiers())) {

                AccessController.doPrivileged(new PrivilegedAction() {

                    public Void run() {

                        cons.setAccessible(true);

                        return null;

                    }

            });    

            }

            / /放射创建对象

            return cons.newInstance(new Object[]{h});

        }catch (Exception e) {

                throw new InternalError(e.toString(), e);

        }

    }

    以上代码可以看出:通过newProxyInstance方法是getProxyClass0获取Class对象,后通过反射创建对象。那getProxyClass0就看看getProxyClass0是什么获取Class对象的:

    private static ClassgetProxyClass0(ClassLoader loader, Class... interfaces) {

        //这里限制了目标对象实现的接口的个数

         if (interfaces.length >65535) {

                throw new IllegalArgumentException("interface limit exceeded");

        }

       return proxyClassCache.get(loader, interfaces);

    }

    /*

    *如果缓存中有,就直接返回,否则会生成

    *key:类加载器;parameter:接口数组

    */

    public V get(K key, P parameter) {

        //省略部分缓存机制代码

        ...

        Factory factory =null;

        //下面用到了 CAS+重试 实现的多线程安全的 非阻塞算法

        while (true) {

            //最终执行的代码 从supplier.get()中获取返回值

            if (supplier !=null) {

                V value = supplier.get();

                if (value !=null) {

                    return value;

                }

            }

            if (factory ==null) {

                factory =new Factory(key, parameter, subKey, valuesMap);

            }

            if (supplier ==null) {

                supplier = valuesMap.putIfAbsent(subKey, factory);

                if (supplier ==null) {

                    supplier = factory;

                }

            }else {

                if (valuesMap.replace(subKey, supplier, factory)) {

                    supplier = factory;

                }else {

                    supplier = valuesMap.get(subKey);

                }

            }

        }

    }

    以上代码重点是: V value = supplier.get() 获取最终的返回的class对象

    public synchronized V get() {

            Supplier supplier =valuesMap.get(subKey);

            if (supplier !=this) {

                return null;

            }

            V value =null;

            try {

                //这里是创建返回Class对象(valueFactory.apply(key, parameter))

                value = Objects.requireNonNull(valueFactory.apply(key, parameter));

            }finally {

            if (value ==null) {

                    valuesMap.remove(subKey, this);

                }

    }

            assert value !=null;

            CacheValue cacheValue =new CacheValue<>(value);

            reverseMap.put(cacheValue, Boolean.TRUE);

            if (!valuesMap.replace(subKey, this, cacheValue)) {

                throw new AssertionError("Should not reach here");

            }

            return value;

        }

    }

    我们继续关注:valueFactory.apply方法看看是什么创建Class对象的:

        public Classapply(ClassLoader loader, Class[] interfaces) {

            Map, Boolean> interfaceSet =new IdentityHashMap<>(interfaces.length);

            for (Class intf : interfaces) {

                Class interfaceClass =null;

                try {

                    // 加载目标类实现的接口到内存中 

                    interfaceClass = Class.forName(intf.getName(), false,     );

                }catch (ClassNotFoundException e) {

                }

                if (interfaceClass != intf) {

                    throw new IllegalArgumentException(intf +" is not visible from class loader");

                }

                //如果不是接口 就抛IllegalArgumentException

                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;   

            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) {

                proxyPkg = ReflectUtil.PROXY_PACKAGE +".";

            }

            long num =nextUniqueNumber.getAndIncrement();

            String proxyName = proxyPkg +proxyClassNamePrefix + num;

            //这个是重点:生成类字节码的方法

            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(

                    proxyName, interfaces, accessFlags);

            try {

                // 根据代理类的字节码生成代理类的实例  

                return defineClass0(loader, proxyName, proxyClassFile, 0,    

                                                    proxyClassFile.length);

            }catch (ClassFormatError e) {

                throw new IllegalArgumentException(e.toString());

            }

    }

    }

    我们继续跟踪ProxyGenerator.generateProxyClass方法:    

    public static byte[] generateProxyClass(final String var0, Class[] var1, int var2) {

        ProxyGenerator var3 =new ProxyGenerator(var0, var1, var2);

        //真正生成字节码的方法

        final byte[] var4 = var3.generateClassFile();

    //如果saveGeneratedFiles为true 则生成字节码文件,所以在开始我们要设置这个参数

        if (saveGeneratedFiles) {

                AccessController.doPrivileged(new PrivilegedAction() {

                    public Void run() {

                    try {

                        int var1 = var0.lastIndexOf(46);

                        Path var2;

                        if (var1 >0) {

                Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));

                            Files.createDirectories(var3);

                            var2 = var3.resolve(var0.substring(var1 +1, var0.length()) +".class");

                        }else {

                            var2 = Paths.get(var0 +".class");

                        }

                    Files.write(var2, var4, new OpenOption[0]);

                    return null;

                    }catch (IOException var4x) {

                           throw new InternalError("I/O exception saving generated file: " + var4x);

                    }

            }

                });

        }

            return var4;

    }

    var3.generateClassFile为正真创建字节码的方法,涉及字节码文件的语法,在此我们就不在深入的探究。

    总结:代理对象是的创建过程一共分三个步骤:

        1、ProxyGenerator.generateProxyClass方法负责生成代理类的字节码,生成逻辑比较复                    杂,了解原理继续分析源码 sun.misc.ProxyGenerator;

        2、native方法Proxy.defineClass0负责字节码加载的实现,并返回对应的Class对象。

        3、利用clazz.newInstance反射机制生成代理类的对象;

    至此我们明白了代理对象是怎么生成的,那么InvocationHandler的invoke方法是由谁来调用的???


    “知其然,知其所以然”


    相关文章

      网友评论

          本文标题:代理之JDK动态代理原理(1)2018-07-27

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