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;
    }
}