CGLib CallbackFilter 接口介绍

本文介绍 CGLib 的 CallbackFilter 接口

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

尺有所短;寸有所长。物有所不足;智有所不明。——屈原《卜居》
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号