深入理解Java动态代理

深入理解Java动态代理

Android小彩虹2021-07-14 16:10:28230A+A-

前言

代理模式(Proxy design pattern)可以分为静态代理和动态代理,两种代理模式本质都是对外隔离真实的业务类,并且对外通过代理类,引入代理类的附加功能。对于动态代理的理解,其动态性并不是表现在省去了编写代理类的代码的工作量,而是表现在当真实的业务类、接口类还未知的时候,就可以确定了代理类的行为。

源码分析

// IFractory 接口
public interface IFractory {
    void createProduct();
}


public class ToyFractory implements IFractory {
    @Override
    public void createProduct() {
        System.out.println("生产玩具的厂家");
    }
}


public class DynamicProxy implements InvocationHandler {

    private IFractory mIFractory;

    public IFractory getIFractory() {
        return mIFractory;
    }

    public void setIFractory(IFractory pIFractory) {
        mIFractory = pIFractory;
    }

    public Object createProxyInstance(){
        return Proxy.newProxyInstance(mIFractory.getClass().getClassLoader(),
                mIFractory.getClass().getInterfaces(),
                this);  // 注释 1
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object lInvoke = method.invoke(mIFractory, args);
        return lInvoke;
    }
}

public class TestDynamicProxy {

    public static void main(String[] args) {

        ToyFractory lToyFractory = new ToyFractory();
        DynamicProxy lDynamicProxy = new DynamicProxy();
        lDynamicProxy.setIFractory(lToyFractory);

        IFractory lProxyInstance = (IFractory) lDynamicProxy.createProxyInstance();

        lProxyInstance.createProduct();

    }
}

上面代码简单创建了 DynamicProxy 类继承了 InvocationHandler 类,并重写 InvocationHandler#invoke() 方法,然后在 TestDynamicProxy 类中创建真正的业务类,并通过 lDynamicProxy#createProxyInstance()生成代理类对象,代理类对象通过调用 createProduct() 方法,间接地调用真正的业务类的真实业务,如上述代码。

我们需要分析动态代理是如何为我们创建代理(Proxy)类的,我们查看[注释 1 ]处的代码细节:

// Proxy.java#newProxyInstance()
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
    Objects.requireNonNull(h);

    // 克隆出一份class<?>[] 数组,避免后续的操作干扰到 interfaces数组;(Java 语言是值传递)
    final Class<?>[] intfs = interfaces.clone();
    
    ....
    
    /* * Look up or generate the designated proxy class. */
    // 注释 2
    // 根据参数生成指定的代理类对象
    Class<?> cl = getProxyClass0(loader, intfs);

    /* * Invoke its constructor with the designated invocation handler. */
    try {
        
        ...

        final Constructor<?> cons = cl.getConstructor(constructorParams);
        
        ...

        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) {
        ...
    } catch (InvocationTargetException e) {
        ...
    } catch (NoSuchMethodException e) {
        ...
    }
}

方法 newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 主要的作用是根据指定的接口返回对应的代理类对象。

在上面的 Proxy#newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 方法中,我去掉了一些不重要的代码逻辑,这个方法主要的作用是通过 Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) 生成一个代理类的 Class 类,然后通过反射运行时获取到该代理类的实例,具体代码如上。

在 [注释 2]处,通过查看 Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) 方法的具体实现,可以发现返回的 Class 代理类是通过给定的类加载器、指定的类接口而生成的,在程序运行期间会存储在内存中,在再次需要的时候,直接返回,具体代码如下:


...

/** * a cache of proxy classes */
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

...

/** * Generate a proxy class. Must call the checkProxyAccess method * to perform permission checks before calling this. */
private static Class<?> getProxyClass0(ClassLoader loader,
                                        Class<?>... interfaces) {
    // 接口数量不可以超过 65535 
    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
    // 注释 3
    return proxyClassCache.get(loader, interfaces);
}

通过解读上面 Proxy#getProxyClass0(ClassLoader loader, Class<?>... interfaces) 的注释,可以知道:如果代理类的 Class 存在,则直接从内存中把 Class 返回,如果代理类不存在通过则通过 ProxyClassFactory 创建代理类。

那么,这时候我们心里面会有疑问,ProxyClassFactory 是如何创建代理类 Class 的呢?

带着疑问,我们继续沿着代码往下面读。通过查阅代码,我们发现 [注释 3] 处的 proxyClassCache 变量是 WeakCache<ClassLoader, Class<?>[], Class<?>> 类型的,并且通过 new WeakCache<>(new KeyFactory(), new ProxyClassFactory()) 初始化了该变量,并在初始化的同时,发现 ProxyClassFactory 这个创建代理类的重要参数,传入 WeakCache 构造方法的第二个参数,那么我们在往下阅读的时候,需要额外关注 WeakCache 的构造方法的第二个参数。通过阅读 WeakCache#get(K key, P parameter) 方法:

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

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

        // lazily install the 2nd level valuesMap for the particular cacheKey
        // map 是 ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> 类型的
        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;

        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                // 注释 4
                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);
            }

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

WeakCache#get(K key, P parameter) 的方法逻辑比较复杂,但比较重要的是在 [注释 4] 处,代码 supplier.get() 中, 可以通过代码知道,supplier 是通过 new Factory(key, parameter, subKey, valuesMap) 初始化的,因此我们可以阅读 Factory#get() 方法,代码如下:

private final class Factory implements Supplier<V> {

    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 {
            // 注释 5
            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)
        // 把创建出的代理类 Class 存储在 CacheValue
        CacheValue<V> cacheValue = new CacheValue<>(value);

        // put into reverseMap
        // cacheValue 继续放进 reverseMap 里面;
        reverseMap.put(cacheValue, Boolean.TRUE);

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

通过阅读代码,我们可以发现 FactoryWeakCache 的普通内部类。Factory 类的代码逻辑比较简单,我们主要看 [注释 5] 处,代码 valueFactory.apply(key, parameter) 返回的值,正是我们需要的代理类 Class 对象,那么 valueFactory 是什么呢?

通过再次阅读代码,我们可以发现,valueFactory 正是源码中 new WeakCache<>(new KeyFactory(), new ProxyClassFactory()) 的第二个参数 new ProxyClassFactory(), 那么我们可以尝试推断:

Class<?> proxy = proxyClassCache.get(loader, interfaces);
// 等价于
Class<?> proxy = new ProxyClassFactory().apply(loader, interfaces);

当然,上面的等价只是抽离了很多相关的代码而推断出的结论,实际上并不可以编译的。那么我们现在只需要专注于 ProxyClassFactory#apply(ClassLoader loader, Class<?>[] interfaces) 方法,通过下面阅读源码:

@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对象
        Class<?> interfaceClass = null;
        try {

            interfaceClass = Class.forName(intf.getName(), false, loader);
        } catch (ClassNotFoundException e) {
        }
        
        ....
    }

    // 代理类的包路径
    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 com.sun.proxy package
        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    }

    /* * Choose a name for the proxy class to generate. */
    // 数字类加操作,从数字 0 开始(原子操作)
    long num = nextUniqueNumber.getAndIncrement();
    // 拼接代理类的名字,如 $Proxy0 ...
    String proxyName = proxyPkg + proxyClassNamePrefix + num;

    /* * Generate the specified proxy class. */
    // 生成指定的代理类,这里是一个 byte 类型的数组
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces, accessFlags);
    try {
        // 注释 6
        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());
    }
}

当我们继续阅读 private static native Class<?> defineClass0(ClassLoader loader, String name, byte[] b, int off, int len) 方法的时候,发现其是一个本地方法,底层如何实现我们在这里就不深究了(主要是我懒)。

ProxyClassFactory#apply(ClassLoader loader, Class<?>[] interfaces) 方法中,主要是准备创建 Proxy 代理类的准备工作,并没有太多复杂难懂的代码。

那么 proxyClassFile 内容是怎样的呢?我们可以通过输入输出流,把 proxyClassFile 输出到 .class 类型的文件中,文件代码如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import cn.xxx.proxy_2.IFractory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements IFractory {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    // 注释 7
    public final void createProduct() throws {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("cn.enjoyedu.proxy_2.IFractory").getMethod("createProduct");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

通过阅读生成的 $proxy0.class 源码,我们可以主要阅读 [注释 7] 处,super.h.invoke(this, m3, new Object[]{var1}) 中,h表示的是 Proxy#InvocationHandler, 那么我们就可以得出:

InvocationHandler#invoke(
    new Proxy(),
    Class.forName("cn.xxx.proxy_2.IFractory").getMethod("saleManTools", Class.forName("java.lang.String")),
    new Object[]{var1})

以上,是动态代理源码分析的主要内容,知道动态代理主要是通过代码在内存中,生成指定类加载器和类接口的代理对象,然后保存在内存中,在需要的时候返回指定的代理实例。

通过上述的代码分析,我们也可以知道,动态代理会占用一定的内存,而且效率相对于静态代理较低,但这样子避免了在未确定真实类、以及对应的接口的时候,就可以确定代理类的行为,从而可以分离代理类和真实业务类的耦合,可以很灵活地应用在不同的场景中。

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1

联系我们