image.png
新建了一个Springboot项目编写demo:
- 创建Enhancer增强器,设置参数:是否使用缓存、代理哪个类、方法拦截器,这里的MethodInterceptor和JDK动态代理中的InvocationHandler作用类似;
- 因为我用Lamda创建的,所以没有显示出MethodInterceptor实现的方法intercept(),和InvocationHandler的invoke方法一样。其中前三个参数相同,不同的是MethodInterceptor有第四个参数MethodProxy;
- 通过methodProxy的invokeSuper方法才能调用目标对象的方法;
- 然后通过enhancer.create() 创建一个实例对象。
public class CglibTest2 {
public static void main(String[] args) {
//System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\workspace\test\cdliByte");
Enhancer enhancer = new Enhancer();
enhancer.setUseCache(false);
enhancer.setSuperclass(TargetBean.class);
//匿名内部类 Lamda形式创建一个MethodInterceptor接口实例对象
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
System.out.println("执行前");
//jdk动态代理:因为我们的目标类有实现接口,我们可以通过jdk的Method的invoke调用目标方法
//Object ob = method.invoke(new TargetBean2(), args);
//cglib:调用methodProxy的invoke、invokeSuper方法
//invoke()是调用增强后的方法 会死循环 内存溢出、invokeSuper()会调用目标类的方法
//Object ob = methodProxy.invoke(o, args);
Object ob = methodProxy.invokeSuper(o, args);
System.out.println("执行后");
return ob;
});
TargetBean2 bean = (TargetBean2)enhancer.create();
bean.test();
}
}
interface InterfaceBean{
void test();
}
class TargetBean implements InterfaceBean{
@Override
public void test(){
System.out.println("我是目标类");
}
}
调用流程
- 直接看enhancer.create(),进去之后调用了this.createHelper(),生成一个EnhancerKey对象,里面保存了用户设置的代理信息,然后调用父类AbstractClassGenerator的creat方法;
- 通过ClassLoaderData 的get方法从缓存中获取代理类,this.getUseCache()参数就是我们demo中的enhancer.setUseCache(false)设置的boolean值,然后调用代理类的构造方法生成一个代理对象;
- 两个instance方法最终都会调用 ReflectUtils.newInstance(type, this.argumentTypes, this.arguments), 并且通过方法setThreadCallbacks(type, this.callbacks)设置callback到代理类中的一个TheadLocal中,代理类在调用方法时,就可以直接用我们自定义的MethodInterceptor中增强的内容。
public Object create() {
this.classOnly = false;
this.argumentTypes = null;
return this.createHelper();
}
private Object createHelper() {
this.preValidate();
Object key = KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter), this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID);
this.currentKey = key;
Object result = super.create(key);
return result;
}
protected Object create(Object key) {
try {
ClassLoader loader = this.getClassLoader();
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE;
AbstractClassGenerator.ClassLoaderData data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
if (data == null) {
Class var5 = AbstractClassGenerator.class;
synchronized(AbstractClassGenerator.class) {
cache = CACHE;
data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
if (data == null) {
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> newCache = new WeakHashMap(cache);
data = new AbstractClassGenerator.ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
this.key = key;
//获取代理类
Object obj = data.get(this, this.getUseCache());
//生成代理类对象
return obj instanceof Class ? this.firstInstance((Class)obj) : this.nextInstance(obj);
} catch (Error | RuntimeException var9) {
throw var9;
} catch (Exception var10) {
throw new CodeGenerationException(var10);
}
}
MethodProxy底层
- 前面提到调用methodProxy的invoke()是调用增强后的方法,会死循环内存溢出,invokeSuper()会调用目标类的方法;
- 通过设置System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\workspace\test\cdliByte")可以在对应目录下生成代理类的字节码文件,查看字节码文件的test方法能够看到methodProxy对象是由MethodProxy.create()方法创建的;
- invoke和invokeSuper方法都会执行this.init()来给FastClassInfo赋值,f1和f2分别为两个类的fastclass代理类,i1和i2是两个类中方法下标,以及生成fastclass代理类的字节码文件;
- 然后通过FastClassInfo对象执行目标类/代理类的方法,invoke(fci.i2, obj, args) 则会根据方法下标执行fastclass类中对应下标的方法。
image.png
生成的代理类和两个fastclass类的字节码文件如下:
image.png