Java-动态代理使用及源码分析

248 阅读11分钟

前言

代理的概念在项目中广泛使用,如如雷贯耳的Retrofit就是(这个后续文章会进行讲解),这个知识面试也是必问的

代理的思想 (定义)

代理的思想:目的是通过引用代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性。而对于动态代理而言 当需要对多个目标对象访问的时候,实现用同一个代理父类实现。
代理还可以调用实际对象的过程中 在前后提供服务

代理的分类

代理模式:分为静态代理动态代理

模式组成

1.先说下静态代理

静态代理实例:

/**
 * 公共接口 抽象主题类:是代理类跟被代理类共同的接口方法 (可以是抽象类,也可以是接口)
 */
public interface PublicInterface {


    //第一家目标对象卖零食
    void buyFood1();
    void buyFood2();

    //如果第二家目标对象卖水果
}
-------------------------------------
/**
 * 代理:也就是使用者不直接对目标对象进行访问,通过第三方的形式去访问,防止直接访问目标对象给系统带来的不必要复杂性。
 * 静态代理:违背了开闭原则,对修改关闭,对新增开放 导致扩展能力差 可维护差
 * 静态代理类
 */
public class StaticProxyDemo implements PublicInterface{
    //我要去买目标对象1中的辣条 需要有目标对象的引用

    private Target1 target1;
    public StaticProxyDemo(Target1 target1) {
        this.target1 = target1;
    }

    //如果直接这样自己去命名方法名 会导致最后不知道这个真实对象(目标对象)的哪个方法
    //所以该代理类跟真实对象需要使用一个公共接口
    //public void buy() {
    //    if (target1 != null) {
    //        target1.buyFood();
    //    }
    //}

    @Override
    public void buyFood1() {
        if (target1 != null) {
            target1.buyFood1();
        }
    }

    @Override
    public void buyFood2() {
        if (target1 != null) {
            target1.buyFood2();
        }
    }
}
------------------------------
/**
 * 目标对象1 比如这个是一间产生零食的作坊
 */
public class Target1 implements PublicInterface {
    //辣条
    private String food1 = "辣条";

    //糖果
    private String food2 = "糖果";

    //买50包辣条
    @Override
    public void buyFood1() {
        System.out.println("买50包" + food1);
    }

    //买一箱糖果
    @Override
    public void buyFood2() {
        System.out.println("买一箱果" + food2);
    }
}

-------------------------
调用

//静态代理实例
PublicInterface target1 = new Target1();
StaticProxyDemo staticProxyDemo = new StaticProxyDemo(target1);
staticProxyDemo.buyFood1();
staticProxyDemo.buyFood2();

上面这个就是静态代理的实例,但是如果新来一个客户说我不想吃零食了 我想吃水果




/**
 * 目标对象2:这是一家卖水果的店
 */
public class Target2{

    //苹果
    private String apple = "苹果";

    //橘子
    private String orange = "橘子";


    //买50斤橘子 水果
    public void buyFruit1() {
        System.out.println("买50斤" + apple);
    }

    //买50斤橘子
    public void buyFruit2() {
        System.out.println("买50斤" + orange);
    }
}

那我们是难道又写一个水果的静态代理类吗?或许在静态代理类里面新增水果的方法,但是这2个的对象不一样 我们是不是又要传入一个水果的实例进来,那么这个代理类是不是非常难以维护 而且不符合单一原则 ,如果还有其他用户又需要其他的东西呢? 对不对,也或者我们可以新增新的静态代理类 虽然保证了单一原则,但是这样我们的代码是不是越来越庞大呢?那有没有什么代理类能满足所有客户的需要呢?有的 那就是动态代理类

静态代理优点

  • 1.代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)
  • 2.业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。

静态代理缺点

  • 1.代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
  • 2.代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了 静态代理小结:如果都用同一个代理类去实现 那就导致每新增一个需求 代理类就需要更改(不符合开闭原则 对修改关闭,对新增开放 导致扩展能力差 可维护差)

2.动态代理

核心概念:动态代理类 代表的是所有的代理类 也就是减免了代码里存在多个代理类,但是其他代码是一点省不了的!!!! 比如目标对象上面的接口 多个目标对象 还是存在多个接口

定义

利用反射机制在运行时创建代理类. 接口、被代理类不能变,一定得保留接口存在。

模式组成

跟静态代理一致,只是代理类不再局限于只代理一个具体类接口。

动态代理底层实现

动态代理具体步骤:

1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

动态代理的实例

//核心类
/**
 * 动态代理:目标就是保证只有一个代理类满足所有需求,当然也需要一个公共的接口 这个接口就是InvocationHandler
 */
public class DynamicProxyDemo {


    //获取真实对象的代理类的实例 核心的核心方法!!!!!!
    public Object getProxy(final Object object) {
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                new InvocationHandler() {
                    //切记proxy 是真实的代理类的实例 不是真实对象
                    //method 触发的方法
                    //args 方法中带的参数
                    //返回值是调用方法后 方法的返回值
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //可以自己添加一些前置逻辑
                        doSthBefore();
                        method.setAccessible(true);
                        //方法的返回值
                        Object result = method.invoke(object, args);
                        //可以自己添加一些后置逻辑
                        doSthAfter();
                        //所以不能返回代理类实例 而是应该是方法的返回值
                        //return proxy;
                        return result;
                    }
                });
    }

    /*后置处理器*/
    private void doSthAfter() {
        System.out.println("精美包装,快递一条龙服务");
    }
    /*前置处理器*/

    private void doSthBefore() {
        System.out.println("根据需求,进行市场调研和产品分析");
    }
}

---------------------------------------------

//目标对象1
/**
 * 动态代理的时候 目标对象1 比如这个是一间产生零食的作坊
 */
public class DynamicTarget1 implements PublicInterface {
    //辣条
    private String food1 = "辣条";

    //糖果
    private String food2 = "糖果";

    //买50包辣条
    @Override
    public String buyFood1() {
        System.out.println("买50包" + food1);
        return "买50包" + food1;
    }

    //买一箱糖果
    @Override
    public void buyFood2() {
        System.out.println("买一箱果" + food2);
    }
}


//目标1对象的对应接口
/**
 * 公共接口 抽象主题类:是代理类跟被代理类共同的接口方法
 */
public interface PublicInterface {

    //第一家目标对象卖零食
    String buyFood1();
    void buyFood2();

    //如果第二家目标对象卖水果
}

---------------------------------------

//目标对象2
/**
 * 目标对象2:这是一家卖水果的店
 */
public class DynamicTarget2 implements PublicInterface2{

    //苹果
    private String apple = "苹果";

    //橘子
    private String orange = "橘子";


    //买50斤橘子 水果
    @Override
    public void buyFruit1() {
        System.out.println("买50斤" + apple);
    }

    //买50斤橘子
    @Override
    public void buyFruit2() {
        System.out.println("买50斤" + orange);
    }
}

//目标对象2的接口
/**
 * 公共接口 抽象主题类:是代理类跟被代理类共同的接口方法
 */
public interface PublicInterface2 {
    //第二家目标对象卖水果
    void buyFruit1();
    void buyFruit2();
}

-------------------------------------------
 //获取动态代理类的实例
PublicInterface proxy1 = (PublicInterface) dynamicProxyDemo.getProxy(new DynamicTarget1());
String food1 = proxy1.buyFood1();
PublicInterface2 proxy2 = (PublicInterface2) dynamicProxyDemo.getProxy(new DynamicTarget2());
proxy2.buyFruit1();

至此 静态代理类跟动态代理类的实例到此为止,我们正常使用的还是动态代理类居多,实例讲完了,那我们剩下的就是针对动态代理类源码分析

动态代理源码分析

1.通过proxy获取动态代理对象

从上面的实例我们就知道 通过Proxy.newProxyInstance(...)就获取到了代理对象,所以很显然点击newProxyInstance这个方法查看就好了

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
       //校验调用处理程序不为空,也就是InvocationHandler不为空
        Objects.requireNonNull(h);
        //拷贝对象(浅拷贝/深拷贝https://www.jianshu.com/p/94dbef2de298) 
        //https://www.jianshu.com/p/7034e9a8c2df
        final Class<?>[] intfs = interfaces.clone();
       
        Class<?> cl = getProxyClass0(loader, intfs);
        try {
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) { 
                cons.setAccessible(true);
              }
            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);就是这个代码,后续的是基于类通过反射获取对象就完事了。

1.分析Class<?> cl = getProxyClass0(loader, intfs);

    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);      (1)
    }

2.上面代码先是对接口数做了一个判断,随后通过缓存方式去获取被代理类的class对象,接下来对proxyClassCache.get(loader, interfaces);的分析,贴上源码

   public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        //ConcurrentMap讲解:https://blog.csdn.net/qq_38023748/article/details/89188337
        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));   (2)
        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();    (6)
                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);  (3)
            }

            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);      (4)
                }
            }
        }
    } 

第(2)、(3)、(4)处是核心代码,先分析第(2)处,subKeyFactory.apply(key, parameter),subKeyFactory的初始化是在proxy.newInstance(xxx)的时候赋值的,是proxy类中的静态成员变量。

  private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
 -------------------------------------------------------------------------
  
      private static final class KeyFactory
        implements BiFunction<ClassLoader, Class<?>[], Object>
    {
        @Override
        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
            switch (interfaces.length) {
                case 1: return new Key1(interfaces[0]); // the most frequent
                case 2: return new Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new KeyX(interfaces);
            }
        }
    }
    
  --------------------
   private static final class KeyX {
        private final int hash;
        private final WeakReference<Class<?>>[] refs;

        @SuppressWarnings("unchecked")
        KeyX(Class<?>[] interfaces) {
            hash = Arrays.hashCode(interfaces);
            refs = (WeakReference<Class<?>>[])new WeakReference<?>[interfaces.length];
            for (int i = 0; i < interfaces.length; i++) {
                refs[i] = new WeakReference<>(interfaces[i]);
            }
        }
    

4.通过调用了KeyFactory类中的apply方法 返回带有被代理类实现了接口的集合的对象。我们再回到第(2)处,然后继续往后走,因为第一次进来基本上数据源都为空,所以走到第(3)处。

 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
} 
 -------------------
      Factory(K key, P parameter, Object subKey,
                ConcurrentMap<Object, Supplier<V>> valuesMap) {
            this.key = key;
            this.parameter = parameter;
            this.subKey = subKey;
            this.valuesMap = valuesMap;
        }

5.上面第一次就factory存起来了同时会走到第(4处)代码 ,这就相当于先 存后拿了,下次进来就会走到第(6)处代码调用存下来的factory的get()方法

 V value = supplier.get();    (6)
 ------------------
 还是这个工厂
      Factory(K key, P parameter, Object subKey,
                ConcurrentMap<Object, Supplier<V>> valuesMap) {
            this.key = key;
            this.parameter = parameter;
            this.subKey = subKey;
            this.valuesMap = valuesMap;
        }
        
         @Override
        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 = Objects.requireNonNull(valueFactory.apply(key, parameter));  (7)
            } 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);

            // try replacing us with CacheValue (this should always succeed)
            if (valuesMap.replace(subKey, this, cacheValue)) {
                // put also in reverseMap
                reverseMap.put(cacheValue, Boolean.TRUE);
            } else {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            return value;
        }
 

我们就会走到第(7)处代码 此时对象是成员变量的ProxyClassFactory工厂,进入这个工厂进去看看

  private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
 -------------------------------------------------------------------------
 
  private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        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 {
                    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();
                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 the default package.
                proxyPkg = "";
            }

            {
                // Android-changed: Generate the proxy directly instead of calling
                // through to ProxyGenerator.
                List<Method> methods = getMethods(interfaces);
                Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
                validateReturnTypes(methods);
                List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);

                Method[] methodsArray = methods.toArray(new Method[methods.size()]);
                Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);

                /*
                 * Choose a name for the proxy class to generate.
                 */
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;

                return generateProxy(proxyName, interfaces, loader, methodsArray,
                                     exceptionsArray);   (8)
            }
        }
    }

我们继续分析这个工厂类里面的apply方法,前面都是一系列的校验 最终会走到第 (8) 处,该方法是native的 ,当然你通过idea 还能继续看到里面的源码,后续的分析可参考以下的文章 ,大体流程基本上就到这里为止了

文章参考:
JDK动态代理-超详细源码分析
设计模式--代理模式--深入理解动态代理