动态代理
关于动态代理在之前的反射部分有过介绍。
InvocationHandler
关键接口。
每个代理实例都会关联一个 invocation handler,当一个代理实例的方法被调用 ,方法调用会被编码并分发到其的 invocation handler 的 invoke 方法。
@param proxy 调用方法的代理实例
@param method 代理实例上调用的接口方法对应的{@code Method}实例。 {@code Method} 对象的声明类将是该方法声明所在的接口,该接口可以是代理类继承该方法所使用的代理接口的超接口。
@param args 包含在代理实例的方法中传递的参数值的对象数组,如果接口方法不接受参数则为{@code null}。基本数据类型的参数应为包装类的实例。
@return 返回从代理实例上的方法调用返回的值。
1. 如果接口方法声明的返回类型是基本数据类型,则该方法返回的值必须是对应包装类的实例;否则,它必须是可指派的声明的返回类型。
2. 如果此方法返回的值为 {@code null} 且接口方法的返回类型为基本数据类型,则代理实例上的方法调用将抛出 {@code NullPointerException}。如果此方法返回的值与上述接口方法声明的返回类型不兼容,则代理实例上的方法调用将抛出{@code ClassCastException}。
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
Proxy.newProxyInstance()
//入参包括ClassLoader、泛型Class集合、InvocationHandler public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { //检测 Invocation Handler 不为null Objects.requireNonNull(h); //拷贝Class集合 final Class<?>[] intfs = interfaces.clone(); /** * 获取系统安全管理器,安全管理器是一个允许应用程序实现安全策略的类 * 它允许应用程序在执行可能不安全的操作之前确定该操作是什么,以及是否在允许执行该操作的安全上下文中尝试该操作 * 应用程序可以允许或禁止该操作 */ final SecurityManager sm = System.getSecurityManager(); /** * 如果安全管理器不为空,检查创建代理类所需的权限 * 要定义一个代理类,它执行 Class.forName 中的访问检查(VM 将调用 ClassLoader.checkPackageAccess): * 1. "getClassLoader" 权限检查是否 loader == null * 2. checkPackageAccess 在它实现的接口上 */ if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } //查找或生成指定的代理类 Class<?> cl = getProxyClass0(loader, intfs); //使用指定的调用处理程序调用其构造函数 try { /** * 进行一个 newProxy 权限的查 * 如果调用者在代理类的不同运行时包中,则进行权限检查 */ if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } //通过Class cl来获取 Constructor,constructorParams 是Proxy类中静态规定的 InvocationHandler.class final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; //如果 cl.getModifiers()获取修饰符非public,通过 setAccessible() 使其可修改 if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } //传入 InvocationHandler 实例去构造一个代理类的实例,通过cons.newInstance()创建实例并返回 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); } }
newProxyInstance() 方法包括进行权限、合法性检测,调用 getProxyClass0(loader, intfs) 获取 Class<?> cl ,再通过 cl 对实例进行创建,主要还是通过反射机制。
intfs = interfaces
intfs + loader ==> Class<?> cl ==> Constructor<?> cons + InvocationHandler h ==> Object
/** * 生成代理类。在调用此方法之前,必须调用 checkProxyAccess 方法来执行权限检查 */ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } /** * 如果由 实现给定接口的加载器 定义的代理类存在,将简单地返回缓存副本 * 否则,它将通过 ProxyClassFactory 创建代理类 */ return proxyClassCache.get(loader, interfaces); }
/** * 此方法存在于 java.lang.reflect.WeakCache 类中 * 通过缓存查找值。总是评估 {@code subKeyFactory} 函数 * 如果缓存中没有给定 (key, subKey) 对的条目或者条目已经被清除,则可选地评估 {@code valueFactory} 函数。 */ public V get(K key, P parameter) { //判定 parameter 不为null Objects.requireNonNull(parameter); /** * 删除陈旧的条目,持续从 ReferenceQueue<K> refQueue 中取出 cacheKey * 将 key 为对应 CacheKey 的条目从 map 中移除 (map 的结构为 ConcurrentMap<?, ? extends ConcurrentMap<?, ?>> ) * map 中 通过 key 可以获取对应的 valuesMap * 遍历 valuesMap 所包含的 values() 集合,cacheValue 若为 reverseMap 中的 key * 则将其k-v对从 reverseMap 中移除 (reverseMap 的结构为 ConcurrentMap<?, Boolean> ) */ expungeStaleEntries(); //若 key 不为 null,通过 new CacheKey(key, refQueue) 创建新的 CacheKey 实例 Object cacheKey = CacheKey.valueOf(key, refQueue); //为特定的 cacheKey 懒加载第二级 valuesMap ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); //如果一级 map 中不存在相应的 cacheKey - valuesMap 条目 if (valuesMap == null) { //如果传入 cacheKey 已经存在,就返回。如果不存在,就添加键值对 ,返回null ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); //map 中已存在 cacheKey 的情况,将 valuesMap 置为获取到的 oldValuesMap if (oldValuesMap != null) { valuesMap = oldValuesMap; } } //创建 subKey 并从 valuesMap 中检索该 subKey 存储的可能的 Supplier<V> Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; /** * 循环部分的整体思路为: * 1.supplier 判空,或获取value失败 * 2.懒构建 factory * 3.supplier 为空:将subKey-factory传入 valuesMap * 4.supplier 不为空:将 subKey 对应的 supplier 替换成 factory 或 再次尝试获取 supplier */ while (true) { if (supplier != null) { //supplier 可能是 Factory 或 CacheValue<V> 实例 V value = supplier.get(); if (value != null) { return value; } } //否则,缓存中没有 supplier //或返回的 supplier 为 null (可能是清除的 CacheValue 或未成功安装 CacheValue 的工厂) //懒构建工厂,一个工厂 {@link Supplier},它实现了值的延迟同步构造并将其安装到缓存中。 if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } //supplier 为空时,将 subKey-factory作为键值对传入 valuesMap,成功则将 factory 赋值给 supplier if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { //成功配置工厂 supplier = factory; } //supplier 不为空,说明 valuesMap 中 subKey 已有对应的 supplier,将 subKey 对应的 supplier 替换 } else { if (valuesMap.replace(subKey, supplier, factory)) { //成功地用我们的工厂替换了清除的 缓存条目/不成功的工厂 supplier = factory; } else { //再次获取 supplier supplier = valuesMap.get(subKey); } } } }
CGLib使用和源码
学习用例
先给出使用 CGLib 实现动态代理的 Examples。
public class TargetObject { public String method1(String string) { System.out.println(string); return string; } public int method2(int i1) { System.out.println(i1); return i1; } public int method3(int i2) { System.out.println(i2); return i2; } @Override public String toString() { return "CglibInterceptor.TargetObject : "+ getClass(); } }
/** * @description: 自定义继承 MethodInterceptor 创建拦截器 * 调用目标函数时,CGLib 回调 Interceptor 实现自定义代理逻辑 * * invokeSuper: * 1. init() * <!-- 使用 volatile 不变量允许我们以原子方式初始化 FastClass 和方法索引对 --!> * 1.1. 创建 CreateInfo * CreateInfo: * Class c1; * Class c2; * * 1.2. 创建 FastClassInfo * 内部静态类 FastClassInfo: * FastClass f1; * FastClass f2; * int i1; f1 的 index * int i2; f2 的 index * 抽象类 FastClass: * Class type; * getIndex(): 返回匹配方法的索引。(之后可以使用该索引以较少的开销调用该方法) * invoke(): 调用 Method (用指定 Index) * * 1.3. 调用 helper() 给 f1、f2 赋值 * helper(CreateInfo ci, Class type) 方法会将 ClassLoader 都设置为 ci.c2.getClassLoader() * 设置对应参数,创建 FastClass.Generator,再调用 create() 方法创建 FastClass 返回 * * 2. 获得 FastClassInfo * 3. 调用 FastClassInfo.f2.invoke() 并返回结果 */ public class TargetInterceptor implements MethodInterceptor { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("调用前..."); Object result = methodProxy.invokeSuper(o, objects); System.out.println("调用后..."); return result; } }
/** * @description: 表示锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值 * 该类实现FixedValue接口,同时锁定回调值为999 * (整型,CallbackFilter 中定义的使用 FixedValue 型回调的方法为 getConcreteMethodFixedValue * 该方法返回值为整型) */ public class TargetResultFixed implements FixedValue { public Object loadObject() throws Exception { System.out.println("锁定结果"); Object obj = 999; return obj; } }
/** * @description: 在CGLib回调时可以设置对不同方法执行不同的回调逻辑,或者根本不执行回调。 */ public class TargetMethodCallbackFilter implements CallbackFilter { public int accept(Method method) { if(method.getName().equals("method1")){ System.out.println("Filter method1 index == 0"); return 0; } if(method.getName().equals("method2")){ System.out.println("Filter method2 index == 1"); return 1; } if(method.getName().equals("method3")){ System.out.println("Filter method3 index == 2"); return 2; } return 0; } }
public class TestCglib { public static void main(String[] args) { //Enhancer CGLib中的一个字节码增强器 Enhancer enhancer =new Enhancer(); enhancer.setSuperclass(TargetObject.class); //例1 //enhancer.setCallback(new CglibInterceptor.TargetInterceptor()); //例2 /** * (1)callback1: 方法拦截器 * (2)NoOp.INSTANCE: NoOp表示 No Operation,代理类直接调用被代理的方法不进行拦截。 * (3)FixedValue: 表示锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值。 */ CallbackFilter callbackFilter = new TargetMethodCallbackFilter(); Callback noopCb = NoOp.INSTANCE; Callback callback1 = new TargetInterceptor(); Callback fixedValue = new TargetResultFixed(); //这里 0代表 callback1,1代表直接调用方法不拦截,2代表过滤器强制修改返回值 Callback[] cbarray = new Callback[]{callback1,noopCb,fixedValue}; enhancer.setCallbacks(cbarray); enhancer.setCallbackFilter(callbackFilter); TargetObject targetObject=(TargetObject)enhancer.create(); //System.out.println(targetObject); System.out.println("<--------->"); System.out.println(targetObject.method1("method1")); System.out.println("<--------->"); System.out.println(targetObject.method2(222)); System.out.println("<--------->"); System.out.println(targetObject.method3(333)); } }
CGLib源码分析
上面列出了 FastClass 和对应的 FastClassInfo,并且 FastClassInfo 内部包含了两个 FastClass,源码中 MethodProxy 的 create(…) 中也包含了 c1 和 c2 两个 Class 实例。 MethodProxy 中 invoke 方法如下:
public Object invoke(Object obj, Object[] args) throws Throwable {
......
init();
FastClassInfo fci = fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
......
}
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
......
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
......
}
其中,f1 为动态代理类FastClass,f2 为被代理类的FastClass。i1, i2 则为 method 对应的 index。
首先要了解的是,CGLib 设计了 ClassGenerator 接口作为最基础的接口之一,放在 cglib.core 下。
ClassGenerator 中仅声明了一个方法:
public interface ClassGenerator {
void generateClass(ClassVisitor v) throws Exception;
}
其中,入参 ClassVisitor v 为 ASM 定义的接口(CGLib 是基于 ASM 对字节码进行操作),暂不引申。
抽象类 AbstractClassGenerator 是对 ClassGenerator 接口进一步细化,它定义了一些较为关键的属性,比如 GeneratorStrategy、ClassLoader、类名、Source(内部类,核心属性为 WeakHashMap,用作缓存)等。
FastClass 中声明了静态内部类 Generator,继承了 AbstractClassGenerator。
//AbstractClassGenerator
abstract public class AbstractClassGenerator implements ClassGenerator {
private static final Object NAME_KEY = new Object();
private static final ThreadLocal CURRENT = new ThreadLocal();
private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE;
private NamingPolicy namingPolicy = DefaultNamingPolicy.INSTANCE;
private net.sf.cglib.core.AbstractClassGenerator.Source source;
private ClassLoader classLoader;
private String namePrefix;
private Object key;
private boolean useCache = true;
private String className;
private boolean attemptLoad;
......
protected static class Source {
String name;
Map cache = new WeakHashMap();
public Source(String name) {
this.name = name;
}
}
......
}
//FastClass 静态内部类 Generator
public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(FastClass.class.getName());
private Class type;
public Generator() {
super(SOURCE);
}
......
protected ClassLoader getDefaultClassLoader() {
return type.getClassLoader();
}
public void generateClass(ClassVisitor v) throws Exception {
new FastClassEmitter(v, getClassName(), type);
}
......
}
FastClass 的 create() 方法调用内部类 Generator 的父类 AbstractClassGenerator 中的 create(Object key) 方法。
protected Object create(Object key) { try { Class gen = null; //Source 内部是一个名为 cache 的 WeakHashMap() 和名为 name 的String synchronized (source) { //获取当前类加载器,$AppClassLoader ClassLoader loader = getClassLoader(); //建立二级缓存,并尝试获取 source 中是否还有二级缓存 Map cache2 = null; cache2 = (Map)source.cache.get(loader); /** * 如果二级缓存为空,创建新的 HashMap,将 NAME_KEY 和 HashSet 的键值对存入 * 并将二级缓存放入以 loader 为 key 的缓存中 */ if (cache2 == null) { cache2 = new HashMap(); cache2.put(NAME_KEY, new HashSet()); source.cache.put(loader, cache2); //useCache: 针对具有相同属性的类,是否使用和更新生成类的静态缓存。 } else if (useCache) { //获取二级缓存中 key 对应的 Reference Reference ref = (Reference)cache2.get(key); //如果 ref 不为空,则把 T类型赋给 gen,再转 Class gen = (Class) (( ref == null ) ? null : ref.get()); } //通过 ThreadLocal CURRENT 规避多线程访问出现线程不安全 if (gen == null) { //从 CURRENT 中获取此线程局部变量的当前线程副本中的值 Object save = CURRENT.get(); //将当前类设置为线程局部变量的当前线程副本中的值 CURRENT.set(this); try { //将入参 key 赋值给类中的 key this.key = key; /** * attemptLoad 如果设置,CGLIB 将在生成 Classes 之前 * 尝试从指定的 ClassLoader 加载这些 Classes * 因为不能保证生成的类名是唯一的,所以默认为 false */ if (attemptLoad) { try { //尝试加载指定类 gen = loader.loadClass(getClassName()); } catch (ClassNotFoundException e) { // ignore } } //如果 attemptLoad 为 false 或 尝试加载失败,gen 依然为 null if (gen == null) { /** * GeneratorStrategy 负责获取 ClassGenerator 并生成一个字节数组,包含生成的 Class 的数据 * 通过提供自定义策略可以在加载之前检查或修改生成的类 * 通常将通过子类化 DefaultGeneratorStrategy 并覆盖适当的受保护方法来实现 */ byte[] b = strategy.generate(this); /** * 从字节数组中读取 className * 获取 className ,并添加 className 到二级缓存中 NAME_KEY 对应的 HashSet */ String className = ClassNameReader.getClassName(new ClassReader(b)); getClassNameCache(loader).add(className); /** * ReflectUtils.defineClass() 方法内部调用 DEFINE_CLASS.invoke() * 且 DEFINE_CLASS 由 ClassLoader.getDeclaredMethod("defineClass"...) 获取 * 即将字节码传入,调用 ClassLoader.defineClass() 方法动态生成 Class */ gen = ReflectUtils.defineClass(className, b, loader); } //将 key 和创建实例的弱引用放入二级缓存 if (useCache) { cache2.put(key, new WeakReference(gen)); } //调用 firstInstance(),传入 Class,通过反射获取该 Class 的实例 return firstInstance(gen); } finally { CURRENT.set(save); } } } return firstInstance(gen); } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new CodeGenerationException(e); } }
关于缓存部分,一级缓存中的键 loader 为 AppClassLoader,二级缓存中的键为 Object。
如果二级缓存不存在,则创建二级缓存,放入一组新键值对{以 private static final Object 为键,new HashSet() 为值}。二级缓存中存放的 HashSet 用作存储 className。
如果允许使用缓存(useCache 为 true),则 Class gen 从二级缓存中取出,通过 reference.get() 获取 T(Class)。主要通过通过 firstInstance(gen) 创建实例。
调试调用方法
注释掉 TestCglib 中对 method2 和 method3 的调用,给最底层的 create() 方法打一个断点,观察 gen 值的变化。

1
进行到 Enhancer enhancer = new Enhancer(); 时,会产生第一次调用。
是由 EnhancerKey 中的 KEY_FACTORY 在初始化时调用的。
传入的 Object key: "net.sf.cglib.proxy.Enhancer$EnhancerKey"
第一次调用结束前,gen 为 "net.sf.cglib.proxy.Enhancer$EnhancerKey$$KeyFactoryByCGLIB$$7fb24d72"
并且,在二级缓存中创建 HashSet 并将生成的 EnhancerKey$$KeyFactoryByCGLIB 全名记录,在二级缓存中存入 EnhancerKey 的弱引用依赖。

2
进行到 TargetObject targetObject=(TargetObject)enhancer.create(); 时,会产生多次 create() 方法调用。
本次路径为:
Enhancer.create() -> createHelper() -> super.create() -> {create()}
传入的 Object key 为上面产生的 "EnhancerKey$$KeyFactoryByCGLIB$$7fb24d72"
可以在它的 FIELD_3 中观察到,与DEMO中定义的过滤器顺序相同
Callback[] cbarray = new Callback[]{callback1,noopCb,fixedValue};

3
进行到 TargetObject targetObject=(TargetObject)enhancer.create(); 时,会产生多次 create() 方法调用。
本次路径为:
Enhancer.create() -> createHelper() -> super.create() -> {create()} -> strategy.generate() ->
transform() -> getMethod() -> MethodWrapper.createSet(interfaceMethods) ->
MethodWrapperKey KEY_FACTORY 初始化 -> {create()}
传入的 Object key 为 "net.sf.cglib.core.MethodWrapper$MethodWrapperKey"
调用结束前,gen 为
"class net.sf.cglib.core.MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7"
可以看到二级缓存中已经按顺序存放了 CGLib 生成的 EnhancerKey$$KeyFactoryByCGLIB 和 MethodWrapperKey$$KeyFactoryByCGLIB,且在二级缓存中存放的 HashSet 中储存了其对象名,用于之后判重。

3 是嵌套在 2 中的,当 3 返回 MethodWrapper 对象后退出,Enhancer 对象被放入ThreadLocal CURRENT 中。这时程序由如下代码后继续运行:
byte[] b = strategy.generate(this);
即由字节码创建 Class 类并返回。
注意,这里 cache 和 3 中的 HashMap 并不是同一个。调用一次完全顺序执行,记录值如下{key,this,cache2}:
1 Enhance$EnhancerKey this {KeyFactory$Generator@510} cache2 {HashMap@520}
2 EnhancerKey$$KeyFactoryByCGLIB this {Enhancer@591} cache2 {HashMap@605}
3 MethodWrapper$$MethodWrapperKey this {KeyFactory$Generator@612} cache2 {HashMap@520}
OUT EnhancerKey$$KeyFactoryByCGLIB this {Enhancer@591} cache2 {HashMap@605}
4 CglibInterceptor.TargetObject this {FastClass$Generator@657} cache2 {HashMap@662}
5 TargetObject$$EnhancerByCGLIB this {FastClass$Generator@677} cache2 {HashMap@662}
由 4、5 发现两个 FastClass 并不相同,且传入的 key 分别为 初始类型 TargetObject 和 增强类型 TargetObject$$EnhancerByCGLIB。

4
本次路径为:
invokeSuper() -> init() -> helper() -> create()
传入的 key 为 "CglibInterceptor.TargetObject"
调用结束前,gen 为 "class CglibInterceptor.TargetObject$$FastClassByCGLIB$$eea6ba1a"
即由初始类型获得被 FastClass 处理过的类型。

5
本次路径为:
invokeSuper() -> init() -> helper() -> create()
传入的 key 为 "CglibInterceptor.TargetObject$$EnhancerByCGLIB$$5cb10b5e"
调用结束前,gen 为
"class CglibInterceptor.TargetObject$$EnhancerByCGLIB$$5cb10b5e$$FastClassByCGLIB$$3bf704cb"
即由 Enhancer 加强后的对象再由 FastClass 进行一次包装。
FastClass 是用于统一操作的结构,作用是根据 index 调用对应的 method 而不使用反射获取。传入 TargetObject 和 TargetObject$$EnhancerByCGLIB 即为被代理类和代理类。对应会建立被代理类和代理类的 FastClass 。
回到开头介绍的 FastClassInfo 中,包含的两个 FastClass,且 invokeSuper() 内部为调用 fci.f2.invoke(),即为调用代理类的 FastClass 的对应方法。那为什么要设立 invokeSuper() 和 invoke() 两种方法呢?
invokeSuper() 和 invoke() 的调用逻辑
对Demo中的 TargetInterceptor 类进行一个小修改,如下:
//修改前
Object result = methodProxy.invokeSuper(o, objects);
//修改后
Object result = methodProxy.invoke(o, objects);
运行后会产生如下结果:
调用前...
调用前...
调用前...
调用前...
调用前...
调用前...
...
Exception in thread "main" java.lang.StackOverflowError
出现多个函数调用前的打印信息,但没有出现 “调用后…” ,最后报错栈溢出。可以确定是循环嵌套调用 intercept() 方法。换句话说,methodProxy.invoke(o, objects) 会不停的调用到 intercept(),而methodProxy.invokeSuper(o, objects) 不会产生这样的情况。
上面提到,invokeSuper() 和 invoke() 方法的差距仅为调用的 FastClass 不同,所以关键原因即在TargetObject$$FastClassByCGLIB$$eea6ba1a 和 TargetObject$$EnhancerByCGLIB$$5cb10b5e$$FastClassByCGLIB$$3bf704cb 上。

