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 类型回调。