【代理】【二】代理源码解析-JDK动态代理使用及源码分析

1  前言

本节我们讲一下动态代理的实现过程,并且从源码分析下产生过程。看之前先简单看几个基础知识:

  • 函数接口BiFunction<T, U, R> : R apply(T t, U u); 就是参数是T、U返回一个结果R    比如: (s1, s2) -> s1.toString() + s2.toString();
  • 函数接口Supplier<T> : T get(); 就是参数空返回一个结果T                                         比如:() -> "1"
  • Map res = map.putIfAbsent(key, val)    当key存在,返回对应的值,当key不存在将键值对key->val放进集合,并返回val
  • ReferenceQueue 引用队列跟GC相关的一个队列

2  基础使用

JDK的动态代理中有两个主要的类是:InvocationHandler(接口)和Proxy(类):

  • InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。
  • Proxy类就是用来创建一个代理对象的类,它提供了很多方法,比如newProxyInstance。

JDK动态代理步骤:

  1. 创建被代理的接口和类 也就是我们第一节里的UserService、UserServiceImpl;
  2. 创建InvocationHandler接口的实现类,在invoke方法中实现代理逻辑;
  3. 通过Proxy的静态方法newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理对象;
  4. 使用代理对象,完成业务功能。

我们先从一个Demo入手,看一下JDK动态代理的基础用法:

public class MyInvocationHandler implements InvocationHandler {
   // 被代理的对象
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    /**
     * proxy:  代理类代理的真实代理对象com.sun.proxy.$Proxy0
     * method: 我们所要调用某个对象真实的方法的Method对象
     * args:   指代代理对象方法传递的参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我是前");
        Object res = method.invoke(target, args);
        System.out.println("我是后");
        return res;
    }
}
public class Client {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService);
        /*
         * newProxyInstance需要的三个参数
         * 类加载器、接口数组、InvocationHandler实现
         */
        UserService proxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), myInvocationHandler);
        proxy.addUser();
    }
}

JDK动态代理测试结果:

3  源码解析

首先我们先了解一下整体的大概执行过程:

整体上分三步:

(1)基础参数校验,比如你的增强有没有传 你的接口存在不存在等

(2)生成你的代理类的 class 二进制信息

(3)获取生成的类的构造器,创建代理对象

那么接下来我们就看看代理的创建过程,我们就从Proxy.newProxyInstance出发看起。

3.1  Proxy.newProxyInstance创建代理入口方法

/**
 * 三个参数
 * 类加载器 jdk代理会生成字节码文件 需要类加载器加载进jvm 个人理解哈
 * 接口数组 jdk代理需要接口 以便知道你类中都有哪些方法  来生成代理
 * InvocationHandler 调用处理器 也就是增强的具体内容
 */
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);
    }
    // 这个是核心  从缓存中获取代理对象 没有的话会创建出来
    Class<?> cl = getProxyClass0(loader, intfs);
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        // 获取代理对象的构造函数 参数constructorParames为常量值:private static final Class<?>[] constructorParams = { InvocationHandler.class };
        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;
                }
            });
        }
        // 构造函数创建代理对象 至于这个参数new Object[]{h} 当你把每个代理对象的class文件反编译出来看一下会知道的
        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);
    }
}

我们可以看到该方法的执行步骤大致是:

  1. 基础校验
  2. 从缓存中获取代理对象,没有的话会进行创建
  3. 获取代理对象的构造函数
  4. 创建代理对象

那么我们接下来要着重看下getProxyClass0这个方法。

3.2  getProxyClass0()获取代理对象

/*
 * 这个就是Proxy的缓存
 * 注意一下他的参数KeyFactory、ProxyClassFactory我们后续会讲解
 */
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    // 接口的大小不能大于65535 65535是2的几次方 快速回答:16?没毛病 两个字节
    // 我记得class文件解析中实现接口数量是用两个字节长度表示的
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }
    // proxyClassCache从缓存中获取代理对象
    return proxyClassCache.get(loader, interfaces);
}

3.3  proxyClassCache.get(loader, interfaces)缓存中获取代理对象

接下来可能就有点绕了,他的数据是嵌套的并且还套着一层函数接口,所以看不懂的要多看几遍。

get会进到WeakCache里的get方法,看的过程中我以提问的方式带着你看哈,(源码不知道怎么加注释?简单方法直接把类拷贝出来加不就行了= =):

private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>();
private final ConcurrentMap<Supplier<V>, Boolean> reverseMap = new ConcurrentHashMap<>();
private final BiFunction<K, P, ?> subKeyFactory;
private final BiFunction<K, P, V> valueFactory;
private final ReferenceQueue<K> refQueue = new ReferenceQueue<>();
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                 BiFunction<K, P, V> valueFactory) {
    this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
    this.valueFactory = Objects.requireNonNull(valueFactory);
}
/**
 * 问:这里的K、P是什么类型的
 * @param key   答:参数传过来的类加载器
 * @param parameter  答:接口数组
 * @return
 */
public V get(K key, P parameter) {
    // 检查参数是否为空
    Objects.requireNonNull(parameter);
    // 清除无效的缓存
    expungeStaleEntries();
    // 根据你的key和一个refQueue引用队列得到一个缓存的key 引用队列暂时放一放没看过是干啥的不影响我们主体
    Object cacheKey = CacheKey.valueOf(key, refQueue);
    /**
     * map看我们上边的变量map是一个嵌套的map   get得到一个valuesMap ConcurrentMap<Object, Supplier<V>>类型的
     * Supplier 是个函数接口 方法形式是空参返回一个T类型的
     */
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        // putIfAbsent存在就返回map中的值,不存在就先塞进map再返回值
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }
    /**
     * 看这里涉及到subKeyFactory  问:这个哪来的?
     * 答案:实例化参数传进来的 也就是我们的第一个参数BiFunction<K, P, ?> subKeyFactory
     * 也就是我们Proxy类里的 KeyFactory
     * 这又是个函数接口 参数K、P返回你一个对象
     *
     * 问:那么subKeyFactory.apply(key, parameter) 返回的是个啥?
     * 答:也就是Proxy里的Key1或者Key2或者Key0或者KeyX
     */
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;
    while (true) {
        if (supplier != null) {
            /**
             * 问:supplier.get()返回的是个啥?
             * 答:supplier是由valuesMap.get得到的 或者下边赋值的也就是Factory类型的
             * 问:Factory是个啥?
             * 答:也就是实现了Supplier 里边有个get方法 用于根据实例化提供的valueFactory得到一个代理对象Class类型的
             */
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        /**
         * factory为空,第一次进来就是为空 实例化factory
         * 注意这4个参数
         * key 就是类加载器    parameter 接口数组
         * subKey 即Proxy里的Key1或者Key2或者Key0或者KeyX
         * valuesMap  ConcurrentMap<Object, Supplier<V>>类型的 里边存的subKey->Factory
         */
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }
        // 再次确认下 supplier是空,将subKey->Factory塞进valuesMap
        if (supplier == null) {
            
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                supplier = factory;
            }
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                supplier = factory;
            } else {
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
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);
        }
    }
}

问接下来我们该看哪里了?就是刚才上边while(true)里的supplier.get(); supplier是个啥?就是WeakCache里的Factory类里的get方法是不是?问问自己哈,晕了话再梳理梳理上边再继续看:

3.4  调用Factory的get方法获取代理对象

private final class Factory implements Supplier<V> {
    private final K key;
    private final P parameter;
    private final Object subKey;
    private final ConcurrentMap<Object, Supplier<V>> valuesMap;
    // 实例化
    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() {
        Supplier<V> supplier = valuesMap.get(subKey);
        if (supplier != this) {
            return null;
        }
        V value = null;
        try {
            /**
             * 主要就是这里根据WeakCache实例化参数的第二个参数valueFactory 返回一个代理对象Class类型的
             * 我主要看了下这里,其它的放进缓存什么的没细看哈
             */
            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;
        CacheValue<V> cacheValue = new CacheValue<>(value);
        reverseMap.put(cacheValue, Boolean.TRUE);
        if (!valuesMap.replace(subKey, this, cacheValue)) {
            throw new AssertionError("Should not reach here");
        }
        return value;
    }
}

3.5  valueFactory.apply(key, parameter)生成代理对象

最后这里是不是来到了我们Proxy里的ProxyClassFactory的apply方法啦,我们看下怎么生成代理的:

private static final class ProxyClassFactory
    implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
    // 这就是我们代理类的类名的前缀
    private static final String proxyClassNamePrefix = "$Proxy";
    // 这就是我们代理类类名后边的数字累加器 线程安全的
    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) {
            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");
            }
            if (!interfaceClass.isInterface()) {
                throw new IllegalArgumentException(
                    interfaceClass.getName() + " is not an interface");
            }
            if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                throw new IllegalArgumentException(
                    "repeated interface: " + interfaceClass.getName());
            }
        }
        // 生成的代理类的包名
        String proxyPkg = null;     // package to define proxy class in
        // 代理类访问控制符: public ,final
        int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
        /**
         * 验证所有非公共的接口在同一个包内;公共的就无需处理
         * 生成包名和类名的逻辑,包名默认是com.sun.proxy,类名默认是$Proxy 加上一个自增的整数值
         * 如果被代理类是 non-public proxy interface ,则用和被代理类接口一样的包名
         */
        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) {
            proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
        }
        long num = nextUniqueNumber.getAndIncrement();
        // 代理类的完全限定名,如com.sun.proxy.$Proxy0.calss
        String proxyName = proxyPkg + proxyClassNamePrefix + num;
        // 生成代理类的字节码
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
            proxyName, interfaces, accessFlags);
        try {
            // 把代理类加载到JVM中,至此动态代理过程基本结束了 defineClass0是个本地方法
            return defineClass0(loader, proxyName,
                                proxyClassFile, 0, proxyClassFile.length);
        } catch (ClassFormatError e) {
            throw new IllegalArgumentException(e.toString());
        }
    }
}

至此,我们JDK动态代理的生成过程就告一段落了,暂时知道大概是个什么过程就可以了,我没太深究了解即可。

拓展一点想看代理生成的字节码文件可以自己调一下那个ProxyGenerator.generateProxyClass(),然后打开看看:

byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", userService.getClass().getInterfaces(), Modifier.PUBLIC | Modifier.FINAL);
String path = "D:/$Proxy0.class";
FileOutputStream out = null;
try {
    out = new FileOutputStream(path);
    out.write(classFile);
    out.flush();
} catch (Exception e) {
    e.printStackTrace();
} finally {
    try {
        out.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

我生成完长这样:

我这里画了个图,梳理一下思路:

4  小结

中间看着还是有点小晕,结构嵌套还有函数接口表达式,慢慢梳理,带着困惑看你是可以的,如果有哪里没理解到的欢迎指正哈。

posted @ 2023-02-20 19:06  酷酷-  阅读(59)  评论(0编辑  收藏  举报