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