CGLib 的 CallbackHelper 类

本文将介绍使用 CGLib 的 CallbackHelper 类快速实现 CallbackFilter 过滤功能,为指定的方法返回回调

在“CGLib CallbackFilter 接口介绍”文章中介绍了怎样去使用 CallbackFilter 接口为拦截的方法映射不同的回调 Callback。本文将介绍使用 CallbackHelper 去实现 CallbackFilter 接口类似的功能。其实,CallbackHelper 是一个实现了 CallbackFilter 接口的抽象类,它为我们实现 CallbackFilter 提供了工具类,推荐优先考虑使用该抽象类,而不是 CallbackFilter 接口。

CallbackHelper 类部分源码如下:

import net.sf.cglib.core.ReflectUtils;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @version $Id: CallbackHelper.java,v 1.2 2004/06/24 21:15:20 herbyderby Exp $
 */
abstract public class CallbackHelper
implements CallbackFilter
{
    private Map methodMap = new HashMap();
    private List callbacks = new ArrayList();
    
    public CallbackHelper(Class superclass, Class[] interfaces)
    {
        // 获取所有方法的 Method 对象
        List methods = new ArrayList();
        Enhancer.getMethods(superclass, interfaces, methods);

        Map indexes = new HashMap();
        for (int i = 0, size = methods.size(); i < size; i++) {
            Method method = (Method)methods.get(i);
            // 调用抽象方法 getCallback() 获取回调,该方法有具体子类实现
            Object callback = getCallback(method);
            if (callback == null)
                throw new IllegalStateException("getCallback cannot return null");

            // 判断 getCallback() 返回的是否为 Callback 或者 Class 对象
            boolean isCallback = callback instanceof Callback;
            if (!(isCallback || (callback instanceof Class)))
                throw new IllegalStateException("getCallback must return a Callback or a Class");
            
            if (i > 0 && ((callbacks.get(i - 1) instanceof Callback) ^ isCallback))
                throw new IllegalStateException("getCallback must return a Callback or a Class consistently for every Method");
            
            // 将获取的回调 Callback 放入 callbacks 列表中
            // 且将 Method 和回调在 callbacks 列表中的下标位置进行关联
            Integer index = (Integer)indexes.get(callback);
            if (index == null) {
                index = new Integer(callbacks.size());
                indexes.put(callback, index);
            }
            methodMap.put(method, index);
            callbacks.add(callback);
        }
    }

    // 由子类去实现,根据不同的 Method 返回不同类型的 Callback
    abstract protected Object getCallback(Method method);

    //...
}

上面源码中,callbacks 列表用于存放所有的 Callback 回调;而 methodMap 保存 Method 和回调 Callback 在 callbacks 列表中下标关系。

示例代码

本示例使用 CallbackHelper 工具类为不同的 Method 定义不同的 Callback。

(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.CallbackHelper;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.FixedValue;
import net.sf.cglib.proxy.NoOp;
import java.lang.reflect.Method;

/**
 * 验证 CallbackHelper 功能
 * @author hxstrive.com 2022/1/3
 */
public class CallbackHelperDemo {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(HelloWorld.class);

        CallbackHelper callbackHelper = new CallbackHelper(HelloWorld.class, new Class[0]) {
            @Override
            protected Object getCallback(Method method) {
                if(method.getName().equals("test")) {
                    return new FixedValue() {
                        @Override
                        public Object loadObject() throws Exception {
                            System.out.println("call FixedValue.loadObject()");
                            return "Hello cglib";
                        }
                    };
                } else {
                    return NoOp.INSTANCE;
                }
            }
        };

        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());

        HelloWorld helloWorld = (HelloWorld) enhancer.create();
        helloWorld.hello();
        System.out.println("test=" + helloWorld.test("hello world"));
    }

}

运行上面程序,输出如下:

hello world
call FixedValue.loadObject()
test=Hello cglib

上面客户端代码中,test() 方法将使用 FixedValue 类型的回调 Callback。其他非 test() 方法,则使用 NoOp.INSTANCE 类型的回调。

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