【代理】【二】代理源码解析-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动态代理步骤:
- 创建被代理的接口和类 也就是我们第一节里的UserService、UserServiceImpl;
- 创建InvocationHandler接口的实现类,在invoke方法中实现代理逻辑;
- 通过Proxy的静态方法newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理对象;
- 使用代理对象,完成业务功能。
我们先从一个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); } }
我们可以看到该方法的执行步骤大致是:
- 基础校验
- 从缓存中获取代理对象,没有的话会进行创建
- 获取代理对象的构造函数
- 创建代理对象
那么我们接下来要着重看下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 小结
中间看着还是有点小晕,结构嵌套还有函数接口表达式,慢慢梳理,带着困惑看你是可以的,如果有哪里没理解到的欢迎指正哈。