美文网首页
动态代理

动态代理

作者: 晚上吃什么啊 | 来源:发表于2019-05-13 13:30 被阅读0次

    动态代理理论及Mybatis实战
    动态代理在我们平时编程并不常用,但因为Spring AOP以及大量框架均使用动态代理机制。
    所以必须要掌握。

    动态代理其本质是:PrxoyGenerator.generateProxyClass生成字节码文件,然后通defineClass0加载这个类
    说白了是重生成了一个字节码文件。

    那先看下源码,在来简单实践一下

    @CallerSensitive
    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);
        }
    
        //通过getProxyClass0方法动态生成Class类
        Class<?> cl = getProxyClass0(loader, intfs);
    
        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;
                    }
                });
            }
            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)
    Java通过该方法中proxyClassCache.get()方法拿到生成的字节码

    private static Class<?> getProxyClass0(ClassLoader loader,
                                            Class<?>... interfaces) {
         //首先,限制一个类接口不能多余65535
         if (interfaces.length > 65535) {
             throw new IllegalArgumentException("interface limit exceeded");
         }
    
         // private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
         //  proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
         return proxyClassCache.get(loader, interfaces);
     }
    

    proxyClassCache.get()方法的部分实现

    //最终通过 supplier.get()返回对象
    while (true) {
      if (supplier != null) {
        // supplier might be a Factory or a CacheValue<V> instance
        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) {
            // 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);
        }
      }
    }
    
    //supplier.get()的实现
    public synchronized V get() { // serialize access
        Supplier<V> supplier = valuesMap.get(subKey);
        if (supplier != this) {
            return null;
        }
        // else still us (supplier == this)
    
        // create new value
        V value = null;
        try {
            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;
    }
    

    之后回过头看apply方法(value = Objects.requireNonNull(valueFactory.apply(key, parameter));
    找到类:ProxyClassFactory

    //·········省略部分验证代码
    if (proxyPkg == null) {
        // if no non-public proxy interfaces, use com.sun.proxy package
        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, accessFlags);
        try {
            return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
        } catch (ClassFormatError e) {
            throw new IllegalArgumentException(e.toString());
        }
    

    其关键部分位于PrxoyGenerator.generateProxyClass生成代理类字节码文件。

    之后返回newProxyInstance方法,看这个类如何被实例化,

    private static final Class<?>[] constructorParams = { InvocationHandler.class };
    ····
    final Constructor<?> cons = cl.getConstructor(constructorParams);
    return cons.newInstance(new Object[]{h});
    

    首先,获取了带参数InvocationHandler类的构造器,然后通过构造器,往里看最后通过调用NativeConstructorAccessorImpl的本地方法实例化了这个类,这样就完成了整个代理过程

    接下来看下一个实践,知道原理还是要用一下:

    public interface Subject {
      //先做一个接口,里面只有一个方法
        void sayHello(String str);
    }
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    //实现InvocationHandler接口
    public class Invoke implements InvocationHandler {
        //这个就是我们要代理的真实对象
        private Object subject;
    
        //构造方法,给我们要代理的真实对象赋初值
        public Invoke(Object subject) {
            this.subject = subject;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //doSomeThing
            System.out.println("即将被代理的方法");
            method.invoke(subject, args);
            return null;
        }
    }
    

    以上就完成了代理类的构建,接下倆我们去调用一下

    import java.lang.reflect.Proxy;
    
    public class doMain {
    
        public static void main(String[] args){
            Subject subjectImpl = str -> System.out.println("Hello:" + str);
    
            Invoke invoke = new Invoke(subjectImpl);
    
            Subject subject = (Subject) Proxy.newProxyInstance(subjectImpl.getClass().getClassLoader(),         subjectImpl.getClass().getInterfaces(), invoke);
    
            //并未直接调用subjectImpl,而是调用生成的代理类
            subject.sayHello("test");
        }
    }
    /* 控制台输出:
    * 即将被代理的方法
    * Hello:test
    */
    

    相关文章

      网友评论

          本文标题:动态代理

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