美文网首页
代理之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方法是由谁来调用的???


“知其然,知其所以然”


相关文章

  • 代理模式

    1.概念 2.静态代理 3.动态代理 3.1 JDK 动态代理 原理 手工模拟JDK动态代理 3.2cglib动态...

  • JDK动态代理实践与原理

    本篇内容 介绍JDK动态代理的基本概念 一些JDK动态代理的疑问 JDK动态代理的Demo JDK动态代理的原理 ...

  • JDK和CGLIB动态代理区别

    JDK和CGLIB动态代理区别 一 JDK和CGLIB动态代理原理1、JDK动态代理利用拦截器(拦截器必须实现In...

  • Spring之使用XML配置Spring AOP

    1.aop的原理 Spring AOP底层主要使用了JDK动态代理和cglib动态代理。具体可看文章设计模式之代理...

  • 代理之JDK动态代理原理(2)2018-07-28

    上一篇代理之JDK动态代理原理(1)我们明白了代理对象是怎么生成的,那么InvocationHandler的inv...

  • 动态代理-jdk代理实现原理

    动态代理-jdk代理实现原理 JDK中提供了一个Proxy类用于实现动态代理,JDK的动态代理是基于接口实现的,被...

  • 设计模式~代理模式

    学习代理模式内容: ★ 静态代理、 ★ 动态代理(JDK动态代理、CGLIB动态代理)、 ★ 拦截器的原理和日志记...

  • Java动态代理

    参考来源: Java动态代理视频 JDK动态代理实现原理 JDK Dynamic Proxies Building...

  • 面试系列~动态代理实现与原理

    动态代理有JDK动态代理, CGLIB动态代理, SpringAOP动态代理 一,JDK动态代理  jdk动态代理...

  • AOP——cglib动态代理源码解析

    上一篇分析了使用JDK动态代理的低层实现原理,这次再来看看cglib实现动态代理的原理。 关于JDK动态代理的实现...

网友评论

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

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