zoukankan      html  css  js  c++  java
  • Proxy.newProxyInstance源码探究

     JDK动态代理案例实现:实现 InvocationHandler 接口重写 invoke 方法,其中包含一个对象变量和提供一个包含对象的构造方法;

    public class MyInvocationHandler implements InvocationHandler {
        Object target;//目标对象
        public MyInvocationHandler(Object target){
            this.target=target;
        }
        /**
         * @param proxy 代理对象
         * @param method 目标对象的目标方法
         * @param args    目标方法的参数
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("log");
            return method.invoke(target,args);
        }
    }
    public class MyInvocationHandlerTest {
        public static void main(String[] args) {
            //参数: 当前类的classLoader(保证MyInvocationHandlerTest当前类可用)
            //         接口数组:通过接口反射得到接口里面的方法,对接口里面的所有方法都进行代理
            //         实现的InvocationHandler:参数是目标对象
            UserDao jdkproxy = (UserDao) Proxy.newProxyInstance(MyInvocationHandlerTest.class.getClassLoader(),
                    new Class[]{UserDao.class},new MyInvocationHandler(new UserService()));
            jdkproxy.query("query");
            //-----结果------
            //log
            //query
        }
    }

      接下来查看 Proxy.newProxyInstance 源码探究它的实现过程:  

        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {    
            //检查InvocationHandler是否为空,为空抛出空指针异常
            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.
             */
            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;
                        }
                    });
                }
                //new得到代理对象
                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, intfs); 这行代码最重要,它可以得到一个代理对象,下面是 Proxy#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);
        }

      proxyClassCache.get() 的实现在 WeakCache#get() 中:

        public V get(K key, P parameter) {
            Objects.requireNonNull(parameter);
    
            expungeStaleEntries();
            //从缓存中取出代理类的key值,因为代理类的生成需要耗时间和性能,所有缓存起来方便下次直接使用
            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 获取到接口信息
            Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
            Supplier<V> supplier = valuesMap.get(subKey);
            Factory factory = null;
            //开始进来supplier是null,所以执行后面的代码创建一个Factory然后赋值给supplier
            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);//通过接口信息和classLoader创建一个工厂
                }
    
                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;//将工厂赋值给supplier
                    } else {
                        // retry with current supplier
                        supplier = valuesMap.get(subKey);
                    }
                }
            }
        }

      下面查看 supplier.get():WeakCache.Factory#get()

            public synchronized V get() { // serialize access
                // re-check
                Supplier<V> supplier = valuesMap.get(subKey);
                if (supplier != this) {
                    // something changed while we were waiting:
                    // might be that we were replaced by a CacheValue
                    // or were removed because of failure ->
                    // return null to signal WeakCache.get() to retry
                    // the loop
                    return null;
                }
                // else still us (supplier == this)
    
                // create new value
                V value = null;
                try {
                    //创建获取到value
                    value = Objects.requireNonNull(valueFactory.apply(key, parameter));
                } finally {
                    if (value == null) { // remove us on failure
                        valuesMap.remove(subKey, this);
                    }
                }
                // the only path to reach here is with non-null value
                assert value != null;
    
                // wrap value with CacheValue (WeakReference)
                CacheValue<V> cacheValue = new CacheValue<>(value);//根据代理类创建一个缓存对象
    
                // put into reverseMap
                reverseMap.put(cacheValue, Boolean.TRUE);//将代理放入缓存中
    
                // try replacing us with CacheValue (this should always succeed)
                if (!valuesMap.replace(subKey, this, cacheValue)) {
                    throw new AssertionError("Should not reach here");
                }
    
                // successfully replaced us with new CacheValue -> return the value
                // wrapped by it
                return value;
            }

      接下来查看 Objects.requireNonNull() 中的 apply方法:Proxy.ProxyClassFactory#apply()

            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 {
                        //对接口再次装载,相当classLoader.loadClass
                        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
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
    
                /*
                 * 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.
                 */
                for (Class<?> intf : interfaces) {
                    int flags = intf.getModifiers();
                    //判断接口的类型是否是public,如果不是public,将代理类放到目标对象同一目录下
                    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
                    //默认定义包名
                    //public static final String PROXY_PACKAGE = "com.sun.proxy";
                    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                }
    
                /*
                 * Choose a name for the proxy class to generate.
                 */
                long num = nextUniqueNumber.getAndIncrement();
                //标识:private static final String proxyClassNamePrefix = "$Proxy";
                //随机数(防止多线程测试相同的类名):long num = nextUniqueNumber.getAndIncrement();
                //代理类的名字:代理包名+ 标识+ 随机数
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                /*
                 * Generate the specified proxy class.
                 * 产生指定的代理类信息,是二进制信息,可以使用IO流输出代理类的Java文件(可查看前文有介绍)
                 * ProxyGenerator.generateProxyClass()是一个静态方法,所以可以外部直接调用
                 */
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
                try {
                    //产生代理类,返回一个class:将byte字节码转换成class
                    //defineClass0是一个native方法,由JVM实现的:private static native Class<?> defineClass0();
                    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());
                }
            }
    作者:huangrenhui
    欢迎任何形式的转载,但请务必注明出处。
    如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
    如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
    如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【码猿手】。
    限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。
  • 相关阅读:
    HDU4126
    训练赛Day6-The 36th ACMICPC Asia Regional Beijing Site
    弦图
    HDU4821 字符串哈希+尺取
    HDU1854
    HDU1166
    输入输出挂
    LightOj 1027 数学期望
    HDU
    HDU
  • 原文地址:https://www.cnblogs.com/huangrenhui/p/14698331.html
Copyright © 2011-2022 走看看