本文共 21414 字,大约阅读时间需要 71 分钟。
前言
java动态代理主要有2种,Jdk动态代理、Cglib动态代理,本文主要讲解Jdk动态代理的使用、运行机制、以及源码分析。当spring没有手动开启Cglib动态代理,即:<aop:aspectj-autoproxy proxy-target-class=“true”/>或@EnableAspectJAutoProxy(proxyTargetClass = true),默认使用的就是Jdk动态代理。动态代理的应用范围很广,例如:日志、事务管理、缓存等。本文将模拟@Cacheable,即缓存在动态代理中的应用进行讲解。需要注意的是,Jdk动态代理相比起cglib动态代理,Jdk动态代理的对象必须实现接口,否则将报错。我们也将带着这个问题在源码分析中寻找答案当@Cacheable注解在方法上时
在方法执行前,将调用Jdk动态代理优先查找Redis(或其他缓存)
当缓存不存在时,执行方法,例如查询数据库 在方法执行后,再次调用Jdk动态代理,将结果缓存到Redis中步骤
创建接口UserService 创建接口实现类UserServiceImpl 创建Jdk动态代理JdkCacheHandler,用于增强UserServiceImpl方法前后的缓存逻辑 代码 创建接口UserServicepublic interface UserService { public String getUserByName(String name);}
创建实现类UserServiceImpl
public class UserServiceImpl implements UserService { @Override public String getUserByName(String name) { System.out.println("从数据库中查询到:" + name); return name; }}
创建Jdk动态代理JdkCacheHandler
public class JdkCacheHandler implements InvocationHandler { // 目标类对象 private Object target; // 获取目标类对象 public JdkCacheHandler(Object target) { this.target = target; } // 创建JDK代理 public Object createJDKProxy() { Class clazz = target.getClass(); // 创建JDK代理需要3个参数,目标类加载器、目标类接口、代理类对象(即本身) return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("查找数据库前,在缓存中查找是否存在:" + args[0]); // 触发目标类方法 Object result = method.invoke(target, args); System.out.printf("查找数据库后,将%s加入到缓存中\r\n", result); return result; }}
创建测试类
public class JdkTest { @Test public void test() { UserService userService = new UserServiceImpl(); JdkCacheHandler jdkCacheHandler = new JdkCacheHandler(userService); UserService proxy = (UserService) jdkCacheHandler.createJDKProxy(); System.out.println("=========================="); proxy.getUserByName("bugpool"); System.out.println("=========================="); System.out.println(proxy.getClass()); }}
输出
==========================查找数据库前,在缓存中查找是否存在:bugpool从数据库中查询到:bugpool查找数据库后,将bugpool加入到缓存中==========================class com.sun.proxy.$Proxy4
查看$ Proxy代码
可以看到当经过Jdk动态代理以后,生产的proxy已经不再是UserService类型了,而是$Proxy4类型,想要了解其调用机制,得先获取到proxy类的代码System.out.println(proxy.getClass());class com.sun.proxy.$Proxy4
修改JVM运行参数,添加-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
添加JVM运行参数.png 运行test即可在com.sun.proxy查看代码,此时生产的是class,idea打开会自动反编译 Proxy代码.png 在上方输出中可以看到代理类是 P r o x y 4 , 至 此 获 取 到 Proxy4,至此获取到 Proxy4,至此获取到Proxy4的源代码,接下去分析代理类的调用机制public final class $Proxy4 extends Proxy implements UserService { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy4(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 getUserByName(String var1) throws { try { return (String)super.h.invoke(this, m3, 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); } } 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")); m3 = Class.forName("proxy.jdk.UserService").getMethod("getUserByName", Class.forName("java.lang.String")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }}
调用机制
从proxy调用开始// JdkTest.javaproxy.getUserByName("bugpool");
proxy是 P r o x y 4 类 型 , 因 此 进 入 Proxy4类型,因此进入 Proxy4类型,因此进入Proxy4的getUserByName方法
// $Proxy4.classpublic final class $Proxy4 extends Proxy implements UserService { ... // 构造器,传入JdkCacheHandler类的对象,正是下方调用的super.h属性 public $Proxy4(InvocationHandler var1) throws { super(var1); } public final String getUserByName(String var1) throws { try { /** * 调用父类的h属性的invoke方法 * 在下面的源码分析中,会发现h属性正是JdkCacheHandler类createJDKProxy方法中所传入的this * Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); * 而this指代的正是JdkCacheHandler类的对象,因此最后调用的是JdkCacheHandler的invoke方法 */ return (String)super.h.invoke(this, m3, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } ... static { ... m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("proxy.jdk.UserService").getMethod("getUserByName", Class.forName("java.lang.String")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); ... }}
因此h.invok实际调用的正是JdkCacheHandler类的invoke方法
// JdkCacheHandler.javapublic class JdkCacheHandler implements InvocationHandler { ... @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("查找数据库前,在缓存中查找是否存在:" + args[0]); // 触发目标类方法 Object result = method.invoke(target, args); System.out.printf("查找数据库后,将%s加入到缓存中\r\n", result); return result; }}
而method.invoke(target, args)中的method = getUserByName,target = 构造函数传进来的UserServiceImpl对象,args = “bugpool”
// UserServiceImpl.javapublic class UserServiceImpl implements UserService { @Override public String getUserByName(String name) { System.out.println("从数据库中查询到:" + name); return name; }}
原理
了解完Jdk动态代理的调用机制,所有核心问题都落在了$Proxy4类的对象proxy是如何生成的上面?即下面这句代码上,这里先给出概述,有利于宏观上看源码。在开始之前先复习一下java的运行机制:1. 所有.java文件经过编译生成.class文件 2. 通过类加载器classLoad将.class中的字节码加载到JVM中 3. 运行// 创建JDK代理public Object createJDKProxy() { Class clazz = target.getClass(); // 创建JDK代理需要3个参数 // 目标类加载器:用于加载生成的字节码 // 目标类接口:用于生成字节码,也就是说$Proxy的生产仅仅需要接口数组就可以完成 // 代理类对象(即本身):用于回调invoke方法,实现方法的增强 return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);}
通过clazz.getInterfaces()获取到所有接口,通过接口可以生成类似以下字节码(注意以下给出的是代码),细细观察会发现其实各个接口方法生成的代码都是一样的,只有(String)super.h.invoke(this, m3, new Object[]{var1}的m3和参数有可能是不同的。所以其实想生成$Proxy字节码,只需要接口数组就已经完全足够了
public final String getUserByName(String var1) throws { try { return (String)super.h.invoke(this, m3, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } }
此时已经获取到 P r o x y 4. c l a s s 的 字 节 码 , 但 是 此 处 的 字 节 码 还 未 加 载 到 J V M 中 , 因 此 需 要 调 用 c l a z z . g e t C l a s s L o a d e r ( ) 传 进 来 的 类 加 载 器 进 行 加 载 , 并 得 到 对 应 的 c l a s s , 也 就 是 Proxy4.class的字节码,但是此处的字节码还未加载到JVM中,因此需要调用clazz.getClassLoader()传进来的类加载器进行加载,并得到对应的class,也就是 Proxy4.class的字节码,但是此处的字节码还未加载到JVM中,因此需要调用clazz.getClassLoader()传进来的类加载器进行加载,并得到对应的class,也就是Proxy类
获取 P r o x y 类 的 构 造 函 数 , 该 构 造 函 数 有 一 个 重 要 的 参 数 h 通 过 反 射 调 用 Proxy类的构造函数,该构造函数有一个重要的参数h 通过反射调用 Proxy类的构造函数,该构造函数有一个重要的参数h通过反射调用Proxy类的构造函数,cons.newInstance(new Object[]{h});构造函数的h正是传入的this,也就是JdkCacheHandler类的对象 将反射获取到的$Proxy对象放回 源码分析 从Proxy.newProxyInstance开始跟踪代码(注:①代表上方概述的步骤1)// JdkCacheHandler.java// 创建JDK代理public Object createJDKProxy() { Class clazz = target.getClass(); // 创建JDK代理需要3个参数,目标类加载器、目标类接口、代理类对象(即本身) return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);}
跟踪代码newProxyInstance,这里需要注意在①②过程结束后,③④过程调用前,即Class<?> cl = getProxyClass0(loader, intfs);结束后,cl变量一直都只是class,即$Proxy4类,并未生成对应的对象,这里不要混淆类和对象
// Proxy.java// loader类加载器,interfaces目标类实现的所有接口,h即InvocationHandler类的对象public static Object newProxyInstance(ClassLoader loader, Class [] interfaces, InvocationHandler h) throws IllegalArgumentException { // 校验InvocationHandler是否为空 Objects.requireNonNull(h); // 该目标类实现的接口数组 final Class [] intfs = interfaces.clone(); // 安全检查 final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ // 当缓存中存在代理类则直接获取,否则生成代理类 // ①②步骤,核心代码,即生成代理类字节码以及加载都在这里进行 Class cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } // ③ 从生成的代理类中获取构造函数 // constructorParams = { InvocationHandler.class }; final Constructor cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction() { public Void run() { cons.setAccessible(true); return null; } }); } // ④ 调用构造函数,将InvocationHandler作为参数实例化代理对象 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);
// Proxy.javaprivate 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 // 如果在类加载器中已经存在实现了对应接口的代理类,则直接返回缓存中的代理类 // 否则,通过ProxyClassFactory新建代理类 return proxyClassCache.get(loader, interfaces);}
跟踪proxyClassCache.get(loader, interfaces);(注:Jdk动态代理对已经生成加载过的代理类进行了缓存以提高性能,缓存的相关代码不是我们关心的重点,可以跳过相关代码)本段代码我们主要关心V value = supplier.get();其中supplier本质是factory,通过new Factory(key, parameter, subKey, valuesMap)创建
// WeakCache.java//K和P就是WeakCache定义中的泛型,key是类加载器,parameter是接口类数组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
跟踪V value = supplier.get();即Factory类的get方法,这里大部分的工作还是在做校验和缓存,我们只关心核心逻辑valueFactory.apply(key, parameter);其中valueFactory是上一个步骤传入的ProxyClassFactory
// Factory.java public synchronized V get() { // serialize access // re-check // 再次检查,supplier是否是当前对象 Suppliersupplier = 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 { // valueFactory 是前序传进来的 new ProxyClassFactory() // ①②步骤,核心逻辑,调用valueFactory.apply生成对应代理类并加载 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) CacheValue cacheValue = new CacheValue<>(value); // put into reverseMap reverseMap.put(cacheValue, Boolean.TRUE); // try replacing us with CacheValue (this should always succeed) if (!valuesMap.replace(subKey, this, cacheValue)) { throw new AssertionError("Should not reach here"); } // successfully replaced us with new CacheValue -> return the value // wrapped by it return value; }
跟踪核心逻辑
// ProxyClassFactory.javaprivate static final class ProxyClassFactory implements BiFunction[], 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 , 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. */ // 当接口修饰符是public,则所有包都可以使用 // 当接口是非public,则生成的代理类必须和接口在与非public接口同一个包下 // 如果非public的接口均在同一个包下,则生成的代理类放在非public接口同一个包下 // 而如果非public的接口存在多个,且在不同包下,则抛出异常 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 // 如果都是公有的接口,则代理类默认放在com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ // 生成计数器,例如$proxy0~n long num = nextUniqueNumber.getAndIncrement(); // 代理类名,com.sun.proxy.$proxy0.class String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ // ③生成代理类字节码 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { // ④使用传进来的classLoader将代理类字节码加载到JVM中 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()); } } }
转载地址:http://ckqub.baihongyu.com/