CallBack接口,根据其名称我们就能知道,这就是一个回调。Callback会被加入到CGLIB生成的class的字节码中,当我们调用被代理类的方法的时候,就会调用到Callbak子接口的方法。
CGLIB中被Enhancer类使用的所有类型的的Callback都继承自该接口。
CallBack接口的子接口
Cglib的CallBack的子接口给Cglib的回调机制扩充了非常多的功能,提供了不同类型的回调形式
1.MethodInterceptor
这个接口应该是CGLIB中最最常用的接口,与JDK动态代理的形式有点类似,但是实现机制完全不一样
public class MethodInterceptorCallback implements MethodInterceptor {
/**
* 我们调用的所有的原始方法都会被替代为调用该方法
* 我们可以在该方法中使用反射的形式来调用原始方法(比较费时)
* 或者使用MethodProxy,使用MethodProxy性能更好
* @param obj: 代理类对象
* @param method : 原始方法对象
* @param args : 方法参数
* @param proxy : MethodProxy,该参数涉及到Cglib的FastClass机制
*/
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before invoke........");
// 利用CGLIB的fastClass机制来调用原始类的方法
Object obj = proxy.invokeSuper(obj,args);
System.out.println("after invoke.........");
return obj;
}
}
2.NoOp
顾名思义,就是什么事情都不做,当我们想要某个方法不被代理的时候,就可以使用该接口的实例,然后调用的就是原始方法。
该接口内部存在一个该接口的实例,我们可以直接将其传递给Enhancer。
3.LazyLoader
就像Hibernate中的懒加载,我们利用该接口也可以实现类似于Hibernate的懒加载。其实利用上面的MethodInterceptor我们也能实现懒加载,但是理解起来稍微麻烦一点,Cglib中专门提供了一个接口来实现。
假设某一个对象,创建他非常消耗性能,且可能被使用也可能不会被使用,这时候我们就可以考虑使用LazyLoader来实现了
@Test
public void testLazy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Lazy.class);
enhancer.setCallback(new LazyCallBack());
Lazy o = (Lazy) enhancer.create();
o.lazy();
}
static class LazyCallBack implements LazyLoader {
/**
* 当调用生成的代理对象的任意一个方法的时候
* 就会调用该方法,返回一个被代理类的实例,然后将方法调用就转接到我们的被代理实例上了
*/
@Override
public Object loadObject() throws Exception {
return new Lazy();
}
}
static class Lazy {
public void lazy(){
// 可以发现输出的依然是我们的原始类而不是代理类
System.out.println(this);
}
}
我们来看看CGLIB生成的代理类长什么样,帮助我们理解
设置系统属性
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\Users\\Desktop\\新建文件夹");
最后在指定位置就能找对应的class文件
删除了大部分代码,保留了与LazyLoader有关的
public class CglibTest$Lazy$$EnhancerByCGLIB$$28e7bcd2 extends Lazy implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private LazyLoader CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private Object CGLIB$LAZY_LOADER_0;
// 我们调用了生成的代理类实例的lazy()方法就会调用到该方法
public final void lazy() {
// 调用了CGLIB$LOAD_PRIVATE_0方法来获取CallBack类返回的实例,在调用实例的lazy()方法
((Lazy)this.CGLIB$LOAD_PRIVATE_0()).lazy();
}
private final synchronized Object CGLIB$LOAD_PRIVATE_0() {
// 获取到我们设置进去的回调,也就是LazyCallBack类的实例
Object var10000 = this.CGLIB$LAZY_LOADER_0;
if (var10000 == null) {
// 这里暂时不管
LazyLoader var10001 = this.CGLIB$CALLBACK_0;
if (var10001 == null) {
CGLIB$BIND_CALLBACKS(this);
var10001 = this.CGLIB$CALLBACK_0;
}
// 调用了我们的loadObejct方法,并缓存了对应的实例
var10000 = this.CGLIB$LAZY_LOADER_0 = var10001.loadObject();
}
return var10000;
}
}
4.Dispatcher
这个其实跟上面的3差不多,内部也是一个loadObject()方法
Object loadObject() throws Exception;
只不过上面的LazyLoader我们从Cglib生产的class我们就能看出,其只会在第一次调用被代理对象的方法的时候调用CallBack的loadObject()方法返回一个实例,然后将该实例缓存,以后就不会再调用了,但是在Dispatcher中就不一样了,我们来看他生成的字节码
/**
* 同样的方法,每次都会调用我们的loadObject()方法,每次都会产生新的实例
*/
public final void lazy() {
Dispatcher var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
((Lazy)var10000.loadObject()).lazy();
}
5.InvocationHandler
这个接口就与JDK的动态代理一模一样,这里就不讲了
6.FixedValue
该接口内部也是一个方法
Object loadObject() throws Exception;
为了便于理解,我们在上面的Lazy类上加了一个方法
// lazy()方法没有什么区别,只是多了返回值
public String lazy1(){
return null;
}
直接看生成的代码吧,不管我们调用的是什么被代理类的哪个方法,最后都是调用的FixedValue的loadObject()方法
public final void lazy() {
FixedValue var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
var10000.loadObject();
}
public final String lazy1() {
FixedValue var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return (String)var10000.loadObject();
}
2.CallbackFilter
这个接口用于将上面的多个Callback接口利用起来,可以实现在同一个类中针对不同的方法使用不同的Callback。
该接口存在一个方法
/**
* 传入一个method,返回一个数组下标
*/
int accept(Method method);
看到上面返回的是下标可能就有疑问了
我们前面的测试用例,设置Callback使用的是setCallback()方法,但是还存在另外一个方法,也就是setCallbacks(),可以一次传入多个Callback,也就是传递一个数组进去。那么上面的accept的返回值,就是我们的传入的数组的下标,这样就可以针对不同的方法,使用不同的Callback
@Test
public void testFilter() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(GoodsService.class);
enhancer.setInterceptDuringConstruction(false);
// 创建多个Callback,TransactionInterceptor是自定义的一个MethodInterceptor的一个实现类
Callback[] callbacks = new Callback[]{new TransactionInterceptor(), NoOp.INSTANCE};
enhancer.setCallbackFilter(new ProxyCallbackFilter());
enhancer.setCallbacks(callbacks);
GoodsService goodsService = (GoodsService) enhancer.create();
goodsService.placeOrder();
System.out.println(goodsService.toString());
}
static class ProxyCallbackFilter implements CallbackFilter {
@Override
public int accept(Method method) {
// 如果是toString方法就返回1,下标1对应的Callback我们传入的是NoOp.INSTANCE
// 也就是不进行代理
if ("toString".equals(method.getName())) {
return 1;
}
return 0;
}
}