动态代理
关于动态代理在之前的反射部分有过介绍。
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 上。

