源码阅读 | 动态代理

简介: 源码阅读 | 动态代理

用法


interface DemoListener {
    fun demo(str: String)
}


class TestDemo : DemoListener {
    override fun demo(str: String) {
        println(str)
    }
}


一个接口,一个实现类,如果使用静态代理还需要创建一个代理类,在代理类中传入实现类,然后进行代理,这样就可以在调用接口方法的前后做一些改变了。


如果是动态代理要怎么做呢?


fun main() {
    val testDemo = TestDemo()
    val proxy = Proxy.newProxyInstance(
        DemoListener::class.java.classLoader,
        arrayOf(DemoListener::class.java),
        CallBack(testDemo)
    ) as DemoListener
    proxy.demo("345")
}
class CallBack(val any: Any?) : InvocationHandler {
    override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
        println("代理前 -------->")
        if (any == null) {
            return null
        }
        val invoke = method?.invoke(any, args?.get(0))
        println("完成代理 -------->")
        return invoke
    }
}


动态代理,这种是 java 已经弄好的,只需要调用方法即可。


需要传入参数:classload ,接口 class 的数组,InvocationHandler 的实现。


最终在使用 proxy 调用 demo 方法的时候会执行到 Callback 中的 invoke 方法中。其实 demo 方法还是你自己调用的,只不过用的是反射,好处就是在代理的前后,可以处理一些必须要处理的逻辑。并且可以进行健壮性的判断,例如被代理类是否为 null 等。


使用场景


有些人会动态代理,但是不知道他的使用场景,经常在代码中不知道如果使用,下面说一个非常典型的案例:


在 mvp 中,p 层 和 v 层需要进行交互。但是有一种情况比较棘手,如果 v 层被销毁了,p 层不知道,然后继续调用对应的方法,这种情况下就会导致空指针异常。


解决:使用动态代理,在调用 v 层方法的前面判断一下 v 层是否为空即可


/**
     * 动态代理,如果 V 层为 null。则取消调用
     *
     * @return
     */
    @Override
    public V getView() {
        if (proxy != null) return proxy;
        return proxy = (V) Proxy.newProxyInstance(
                viewRef.get().getClass().getClassLoader(),
                viewRef.get().getClass().getInterfaces(),
                this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (viewRef.get() != null && isArgs(args)) {
            return method.invoke(viewRef.get(), args);
        }
        return null;
    }


其中 viewRef 为弱引用,里面存放着 v 层接口实例。


源码阅读


1,到底干了什么,怎么实现的。


2,学习一些源码怎么写的。


3,如果不懂的代码没必要深究,发现偏了方向赶紧重新回到原点重新来


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);
    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        //创建代理类 的构造函数
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        //判断如果不是 public 的则设置权限
        if (!Modifier.isPublic(cl.getModifiers())) {
            cons.setAccessible(true);
            // END Android-removed: Excluded AccessController.doPrivileged call.
        }
        //返回代理类的对象,
        return cons.newInstance(new Object[]{h});
    } catch (InvocationTargetException e) {
      //........ 
    }
}


上面首先生成了一个代理类,然后就调用代理类的构造,将 InvocationHandler 传了进去


下面看一下代理类是怎样生成的


//代理缓存
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
//获取代理类
private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }
   //从缓存中获取代理
    return proxyClassCache.get(loader, interfaces);
}
public V get(K key, P parameter) {
  //...
    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) {
        //如果获取的是 null,创建一个新的 valuesMap
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }
    //调用 apply 方法生成代理类,subKey 就是代理类
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    //从 map 中获取
    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;
            }
        }
       //创建工厂
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }
        //supplier 如果为空,则表示从 map 中没有获取到,下面进行保存
        //最终会循环到上面的return ,将 代理类返回出去
        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)) {
                supplier = factory;
            } else {
                supplier = valuesMap.get(subKey);
            }
        }
    }
}


@Override
    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
        Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
        //遍历所有的接口
        for (Class<?> intf : interfaces) {
            Class<?> interfaceClass = null;
            try {
                // 加载一个 class 
                interfaceClass = Class.forName(intf.getName(), false, loader);
            } catch (ClassNotFoundException e) {
            }
           //判断 .....
            //将 加载出来的 class put 进去
            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;
        /*
         * 拿到包名
         */
        for (Class<?> intf : interfaces) {
            //获取修改,判断是否 public
            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 = "";
        }
        {
            //获取所有方法
            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();
            //代理名称,num 是标志,避免生成名字相同的代理名称
            // private static final String proxyClassNamePrefix = "$Proxy";
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
    // 创建代理类
            return generateProxy(proxyName, interfaces, loader, methodsArray,
                                 exceptionsArray);
        }
    }
}


梳理一下流程:


首先调用 getProxyClass0 方法获取代理类,其中,首先会获取缓存,如果缓存不存在,则创建缓存。接着调用 apply 方法区生产一个代理类,在 apply 方法中会获取到包名,包名则是 proxyPak + $proxy+标志。 获取所有的方法,获取异常等,最终 通过 generateProxy 完成代理class 的床,generateProxy 是 native 层的方法。


拿到 代理后将 InvocationHandler 传入到了代理中,由此我们可以推断 我们调用 newProxyInstance 返回代理类的方法的时候其实调用的就是 InvocationHandler 中的 invoke 方法。在 invoke 中 去反射调用我们需要调用的方法。


总结一下:


动态代理无非就是在程序运行的过程中动态的生成了一个 代理类,这个代理类接收一个接口。


我们在调用 newProxyInstance 方法的时候就会传入一个 实现类。并且返回一个代理类


我们在使用 代理类的时候会将其强转为对应的实现接口。然后在调用对应的方法,其实这里调用的是 实现类的 invoke 方法,在这个方法中去反射调用对应的方法。


相关文章
|
设计模式 Java 数据安全/隐私保护
设计模式之代理模式(jdk和cglib、手撕源码、自创动态代理) 1
设计模式之代理模式(jdk和cglib、手撕源码、自创动态代理)
94 0
|
缓存 Java 测试技术
动态代理:JDK动态代理源码学习
动态代理:JDK动态代理源码学习
66 1
|
设计模式 Java Maven
设计模式之代理模式(jdk和cglib、手撕源码、自创动态代理) 2
设计模式之代理模式(jdk和cglib、手撕源码、自创动态代理)
61 0
|
Java Spring
动态代理学习(二)JDK动态代理源码分析
动态代理学习(二)JDK动态代理源码分析
85 0
动态代理学习(二)JDK动态代理源码分析
|
设计模式 监控 Java
《Spring 手撸专栏》第 12 章:炉火纯青,基于JDK和Cglib动态代理,实现AOP核心功能
实现 1. 工程结构 2. 代理方法案例 3. 切点表达式 4. 包装切面通知信息 5. 代理抽象实现(JDK&Cglib) 测试 1. 事先准备 2. 自定义拦截方法 3. 单元测试
191 0
《Spring 手撸专栏》第 12 章:炉火纯青,基于JDK和Cglib动态代理,实现AOP核心功能
|
设计模式 监控 Java
谈谈反射机制,动态代理基于什么原理
谈谈反射机制,动态代理基于什么原理
140 0
|
Java Spring
(十七)关于动态代理,你能说出动态代理的几种方式?
动态代理是指代理类不是写在代码中的,而是在代码运行过程中产生的,Java提供了两种方式来实现动态代理,分别是基于Jdk的动态代理和基于Cglib的动态代理。
|
缓存 安全 Java
彻底搞懂动态代理(上)
彻底搞懂动态代理(上)
|
安全 Java
彻底搞懂动态代理(下)
彻底搞懂动态代理(下)