在 CGLib 中,LazyLoader 接口用来延迟加 Enhancer 回调。并且该接口继承了 Callback 接口,Callback 接口没有定义任何方法(即一个标识接口,类似 JDK 的 java.io.Serializable 接口),Enhancer 使用的所有回调接口都扩展了这个接口。
LazyLoader 接口除了继承 Callback 接口外,自己还定义了一个 loadObject() 方法,它的定义如下:
java.lang.Object loadObject() throws java.lang.Exception
返回原始方法调用应该调度的对象。在调用增强实例中的第一个延迟加载方法时立即调用。然后,将来对代理实例的每次方法调用都使用相同的对象。
(1)创建被代理的类,代码如下:
/** * 被代理的类 * @author hxstrive.com 2021/12/29 */ public class HelloWorld { private String msg; public HelloWorld(String msg) { this.msg = msg; } public HelloWorld() { this("hello world"); } public String test(){ return this.msg; } }
(2)创建客户端代码,通过 Enhancer 类的 setCallback() 方法设置 LazyLoader 类型回调方法。然后在 LazyLoader 回调的 loadObject() 方法中返回目标实例对象。代码如下:
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.LazyLoader; /** * 验证 setCallback() 设置 LazyLoader 接口 * @author hxstrive.com 2021/12/31 */ public class CglibDemo { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloWorld.class); enhancer.setCallback(new LazyLoader() { @Override public Object loadObject() throws Exception { return new HelloWorld("lazyLoader test"); } }); HelloWorld sample = (HelloWorld) enhancer.create(); System.out.println("sample.test():\n" + sample.test()); System.out.println("\nsample.toString():\n" + sample.toString()); System.out.println("\nsample.getClass():\n" + sample.getClass()); System.out.println("\nsample.hashCode():\n" + sample.hashCode()); } }
运行结果如下:
sample.test(): lazyLoader test sample.toString(): com.hxstrive.cglib.callback.demo2.HelloWorld@108c4c35 sample.getClass(): class com.hxstrive.cglib.callback.demo2.HelloWorld$$EnhancerByCGLIB$$b9769574 sample.hashCode(): 277630005
根据上面输出结果可知,CGLib 生成的代理对象实际上调用的原始对象来自我们实现的 LazyLoader 回调类中 loadObject() 方法返回的 HelloWorld 对象。
如果我们在 LazyLoader 回调的 loadObject() 方法中返回一个非 HelloWorld.class 类型的实例,会发生什么情况呢?代码如下:
public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloWorld.class); enhancer.setCallback(new LazyLoader() { @Override public Object loadObject() throws Exception { return Calendar.getInstance(); } }); HelloWorld sample = (HelloWorld) enhancer.create(); System.out.println("sample.test():\n" + sample.test()); System.out.println("\nsample.toString():\n" + sample.toString()); System.out.println("\nsample.getClass():\n" + sample.getClass()); System.out.println("\nsample.hashCode():\n" + sample.hashCode()); }
运行上面代码将输出如下错误信息:
Exception in thread "main" java.lang.ClassCastException: java.util.GregorianCalendar cannot be cast to com.hxstrive.cglib.callback.demo2.HelloWorld at com.hxstrive.cglib.callback.demo2.HelloWorld$$EnhancerByCGLIB$$b9769574.test(<generated>) at com.hxstrive.cglib.callback.demo2.CglibDemo2.main(CglibDemo2.java:25)