美文网首页
Java之动态代理

Java之动态代理

作者: Llianhua | 来源:发表于2019-08-08 17:24 被阅读0次

    静态代理

    先看一个例子,有个汽车记录功能,我们既要记录行驶的时间,又要记录其它日志,如果这些事全部交给Car这个对象来做,那么它要处理的事情就太多了,既要跑还有写,所以为了给Car减轻负担,代理类就诞生了,代码如下:

    //接口类
    public interface MoveAble {
        void move();
    }
    
    //Car类
    public class Car implements MoveAble {
        @Override
        public void move() {
            System.out.println("car move中");
        }
    }
    
    //记录时间代理类
    public class TimeProxy implements MoveAble{
        private MoveAble m;
        public TimeProxy(MoveAble m){
            this.m = m;
        }
    
        @Override
        public void move() {
            System.out.println("time开始");
            m.move();
            System.out.println("time结束");
        }
    }
    
    //记录日志代理类
    public class LogProxy implements MoveAble {
        private MoveAble m;
        public LogProxy(MoveAble m) {
            this.m = m;
        }
    
        @Override
        public void move() {
            System.out.println("log开始");
            m.move();
            System.out.println("log结束");
        }
    }
    

    从以上的代码中可以看出我们创造了两个新的类去继承和Car一样的接口,这样做本质上来说它们三个就都有跑的方法了。那么我们可以像下面的代码那样调用它们:

    public static void main(String[] args) {
            Car car = new Car();
            LogProxy logProxy = new LogProxy(car);
            TimeProxy timeProxy = new TimeProxy(logProxy);
            timeProxy.move();
    }
    

    上面这段代码中把Car先放进了LogProxy里,又把LogProxy放进了TimeProxy里,接着调用了TimeProxy对象的move方法,这时候会一层一层的调用move方法,从TimeProxy到LogProxy再到Car,这样子就把记录时间和日志的功能给完成了。
    那么这种代理模式有什么好处呢,可以让不同的功能做不同的事,也就是单一职责,拆分了代码逻辑,使逻辑更加的清晰了。
    但是这种静态的代理有个问题,就是我们需要自己去写代理类,如果功能少还好说,要是功能多的话就会很麻烦,所以,动态代理就开始登场了。

    动态代理

    jdk中为我们提供了创建动态代理对象的方式,即Proxy类。
    Proxy类位于java.lang.reflect包中,包含有一个静态的创建方法newProxyInstance,代码如下:

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException{
           ......//暂时可以忽略的逻辑
    }
    

    在上面的创建Proxy类代码中需要接口三个参数:

    • ClassLoader loader
      类加载器
    • Class<?>[] interfaces
      类实现的接口
    • InvocationHandler h 处理器

    我们重点看一下第三个参数InvocationHandler,这个类是个接口,里面只有一个invoke方法,我们所要做的处理逻辑都会在这个方法里执行。代码如下:

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    

    invoke方法里也有三个参数:

    • Object proxy 调用invoke方法的对象实例
    • Method method 对象的方法
    • Object[] args 参数

    那么我们应该怎么使用动态代理创建我们的代理类呢,基于上面Car记录时间和日志的例子,我们可以这样写:

    public static void main(String[] args) {
            Car car = new Car();
            MoveAble m = (MoveAble) Proxy.newProxyInstance(car.getClass().getClassLoader(), car.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                    System.out.println("log开始");
                    System.out.println("time开始");
    
                    method.invoke(car);
    
                    System.out.println("time结束");
                    System.out.println("log结束");
    
                    return null;
                }
            });
            m.move();
    }
    

    是不是很简单,有个动态代理,我们就不用自己去创建LogProxy,TimeProxy等等代理类了。

    动态代理原理

    知道了通过动态代理的方式可以帮我们自动的生成一些代理类,那么Proxy究竟是怎么办到的呢,下面就开始分析一下Proxy的内部原理。首先,看一下newProxyInstance这个静态方法,代码如下:

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
    
            final Class<?>[] intfs = interfaces.clone();
            
            Class<?> cl = getProxyClass0(loader, intfs); //1
    
            try {
                final Constructor<?> cons = cl.getConstructor(constructorParams);//2
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                    cons.setAccessible(true);
                    AccessController.doPrivileged call.
                }
                return cons.newInstance(new Object[]{h});//3
            } 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);
            }
        }
    

    为了逻辑清晰我删除了注释,这段代码的主要逻辑就是在1,2,3处,这三步分别是:

    • 1.得到Proxy的Class对象
    • 2.通过Class对象得到Constructor对象
    • 3.通过Constructor对象的newInstance方法获得实例对象

    下面我们主要分析Class<?> cl = getProxyClass0(loader, intfs); //1这行代码,来看看这个方法是怎么生成的Class类对象的。
    这个方法的代码很简单:

    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
            return proxyClassCache.get(loader, interfaces);
    }
    

    主要就是看最后一行代码,返回的就是Class对象

    public V get(K key, P parameter) {
    
           ......
    
            Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
            Supplier<V> supplier = valuesMap.get(subKey);
            Factory factory = null;
    
            while (true) {
                if (supplier != null) {
                    // supplier might be a Factory or a CacheValue<V> instance
                    V value = supplier.get();
                    if (value != null) {
                        return value;//1
                    }
                }
    
                // lazily construct a Factory
                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);
                    }
                }
            }
        }
    

    这段代码我删除了一些注释和与主要逻辑关系不大的代码。
    首先来看几个比较的对象:

    1. Supplier<V> supplier
    2. Factory factory

    先看最后返回的value是通过supplier.get()的,也就是代码中1处的逻辑,那么这个supplier是什么呢,它是个接口,下面的factory是它的实现类,下面的while循环中就是给supplier赋值的过程。也就是说value的最终获取是通过factory里的get方法取得,那么我们再看一下这个get方法逻辑:

    public synchronized V get() { // serialize access
                ......
    
                // create new value
                V value = null;
                try {
                    value = Objects.requireNonNull(valueFactory.apply(key, parameter));//1
                } finally {
                    if (value == null) { // remove us on failure
                        valuesMap.remove(subKey, this);
                    }
                }
    
                return value;
    }
    

    这里最重要的逻辑是代码1处,从valueFactory的apply里得到了value,也就是我们最终要得到的Class对象。那么我们再来看看这个valueFactory是什么。

     public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                         BiFunction<K, P, V> valueFactory) {
            this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
            this.valueFactory = Objects.requireNonNull(valueFactory);
        }
    

    valueFactory是BiFunction接口的实现类对象,WeakCache初始化的时候被传进来

    public class Proxy implements java.io.Serializable {
    
        private static final long serialVersionUID = -2222568056686623797L;
    
        /** parameter types of a proxy class constructor */
        private static final Class<?>[] constructorParams =
            { InvocationHandler.class };
    
        /**
         * a cache of proxy classes
         */
        private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
            proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    
            ......
    }
    

    可以看出来是在Proxy类中被初始化的,也就是ProxyClassFactory类对象。这个ProxyClassFactory也实现了BiFunction,那么上面的apply方法最终的实现逻辑就是在这个类中:

    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
               ......
                    
                    long num = nextUniqueNumber.getAndIncrement();
                    String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                    return generateProxy(proxyName, interfaces, loader, methodsArray,
                                         exceptionsArray);
                }
    }
    

    这个方法代码很长,我们只需要关注这几行就行了,可以看出,这个方法设定了一个规则,生成一个字符串proxyName也就是我们的代理类的类名,最后的generateProxy方法实际上是调用了本地的一个方法,就是生成Class对象的方法:

    @FastNative
        private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
                                                     ClassLoader loader, Method[] methods,
                                                     Class<?>[][] exceptions);
    

    那么到现在为止就把动态代理怎么生成代理对象的机制分析完了。

    相关文章

      网友评论

          本文标题:Java之动态代理

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