CGLib 的 CallbackFilter 接口将 Enhancer 生成的子类的方法映射到特定的回调。为每个方法选择的回调类型会影响子类中为该方法生成的字节码,并且在类的生命周期内无法更改。
注意:CallbackFilter 实现应该是轻量级的,因为 CGLib 可能会使 CallbackFilter 对象保持活动状态以启用生成类的缓存。首选使用静态类来实现 CallbackFilter。
在 CallbackFilter 中,定义了 accept() 和 equals() 方法,定义分别如下:
accept 方法
int accept(java.lang.reflect.Method method)
该方法将方法映射到回调(Callback)。其中,method 参数表示被拦截的方法。该方法将返回一个回调数组的索引(由 Enhancer.setCallbacks(net.sf.cglib.proxy.Callback[]) 指定)。
equals 方法
boolean equals(java.lang.Object o)
使用中的 CallbackFilter 会影响 Enhancer 将使用哪个缓存类,因此这提醒您应该正确实现自定义 CallbackFilter 实现的 equals 和 hashCode,以提高性能。
下面通过一个完整实例,介绍怎样使用 CallbackFilter。
(1)定义被代理类,代码如下:
/**
* 被代理的类
* @author hxstrive.com 2021/12/29
*/
public class HelloWorld {
public String test(String msg) {
return msg;
}
public void hello() {
System.out.println("hello world");
}
}(2)定义客户端,代码如下:
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
/**
* 验证 CallbackFilter 接口的简单用法
* @author hxstrive.com 2022/1/3
*/
public class CallbackFilterDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloWorld.class);
// 实现自定义的 CallbackFilter,根据方法名称指定不同的 Callback 回调
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
return method.getName().equals("test") ? 0 : 1;
}
});
// 指定多个 Callback 回调
enhancer.setCallbacks(new Callback[]{
new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "Fixed Value";
}
},
new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("call intercept before");
Object result = proxy.invokeSuper(obj, args);
System.out.println("call intercept after");
return result;
}
}
});
HelloWorld proxy = (HelloWorld)enhancer.create();
System.out.println("test=" + proxy.test("hello world"));
proxy.hello();
}
}运行上面程序,输出如下:
test=Fixed Value call intercept before hello world call intercept after
上面代码中,有如下代码:
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
return method.getName().equals("test") ? 0 : 1;
}
});该代码将判断当前拦截的方法名称是否为“test”,如果是,则返回0;否则,返回1。需要注意,这里的 0 和 1 其实表示一个下标值。CGLib 将根据该下标值到 enhancer.setCallbacks(new Callback[]{}); 代码设置的回调数组中获取 Callback 实例。例如:
enhancer.setCallbacks(new Callback[]{
new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "Fixed Value";
}
},
new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("call intercept before");
Object result = proxy.invokeSuper(obj, args);
System.out.println("call intercept after");
return result;
}
}
});上面代码设置了两个 Callback 回调,分别为 FixedValue 和 MethodInterceptor。前者的下标为0,后者为 1;所以,我们在 CallbackFilter 的 accept() 方法中,根据方法名称是否等于“test”来返回 0 和 1。实质上就是指定方法名为 test 的方法使用 FixedValue 类型回调;其他方法均使用 MethodInterceptor 类型回调。