使用 CGLIB 生成代理类
CGLIB(Code Generation Library),简单来说,就是一个代码生成类库。它可以在运行时候动态是生成某个类的子类。
此处使用前面定义的 Chinese 类,现在改为直接使用 CGLIB 来生成代理,这个代理类同样可以实现 Spring AOP 代理所达到的效果。
下面先为 CGLIB 提供一个拦截器实现类:
清单 12.AroundAdvice.java
显示更多上面这个 AroundAdvice.java 的作用就像前面介绍的 Around Advice,它可以在调用目标方法之前、调用目标方法之后织入增强处理。
接下来程序提供一个 ChineseProxyFactory 类,这个 ChineseProxyFactory 类会通过 CGLIB 来为
Chinese 生成代理类:
清单 13.ChineseProxyFactory.java
显示更多
上面粗体字代码就是使用 CGLIB 的 Enhancer 生成代理对象的关键代码,此时的 Enhancer 将以
Chinese 类作为目标类,以 AroundAdvice 对象作为”Advice”,程序将会生成一个 Chinese 的子类,这
个子类就是 CGLIB 生成代理类,它可作为 Chinese 对象使用,但它增强了 Chinese 类的方法。
测试 Chinese 代理类的主程序如下:
清单 14.Main.java
public class AroundAdvice implements MethodInterceptor
{
public Object intercept(Object target, Method method
, Object[] args, MethodProxy proxy)
throws java.lang.Throwable
{
System.out.println("执行目标方法之前,模拟开始事务 ...");
// 执行目标方法,并保存目标方法执行后的返回值
Object rvt = proxy.invokeSuper(target, new String[]{"被改变的参数"});
System.out.println("执行目标方法之后,模拟结束事务 ...");
return rvt + " 新增的内容";
}
}
public class ChineseProxyFactory
{
public static Chinese getAuthInstance()
{
Enhancer en = new Enhancer();
// 设置要代理的目标类
en.setSuperclass(Chinese.class);
// 设置要代理的拦截器
en.setCallback(new AroundAdvice());
// 生成代理类的实例
return (Chinese)en.create();
}
}显示更多
运行上面主程序,看到如下输出结果:
执行目标方法之前,模拟开始事务 …
— 正在执行 sayHello 方法 —
执行目标方法之后,模拟结束事务 …
被改变的参数 Hello , CGLIB 新增的内容
执行目标方法之前,模拟开始事务 …
我正在吃 : 被改变的参数
执行目标方法之后,模拟结束事务 …
class lee.Chinese$$EnhancerByCGLIB$$4bd097d9
从上面输出结果来看,CGLIB 生成的代理完全可以作为 Chinese 对象来使用,而且 CGLIB 代理对象的
sayHello()、eat() 两个方法已经增加了事务控制(只是模拟),这个 CGLIB 代理其实就是 Spring AOP
所生成的 AOP 代理。
通过程序最后的输出,不难发现这个代理对象的实现类是
lee.Chinese$$EnhancerByCGLIB$$4bd097d9,这就是 CGLIB 所生成的代理类,这个代理类的格式与
前面 Spring AOP 所生成的代理类的格式完全相同。
这就是 Spring AOP 的根本所在:Spring AOP 就是通过 CGLIB 来动态地生成代理对象,这个代理对象
就是所谓的 AOP 代理,而 AOP 代理的方法则通过在目标对象的切入点动态地织入增强处理,从而完成
了对目标方法的增强。
结束语
AOP 广泛应用于处理一些具有横切性质的系统级服务,AOP 的出现是对 OOP 的良好补充,它使得开发
者能用更优雅的方式处理具有横切性质的服务。不管是那种 AOP 实现,不论是 AspectJ、还是 Spring
AOP,它们都需要动态地生成一个 AOP 代理类,区别只是生成 AOP 代理类的时机不同:AspectJ 采用
编译时生成 AOP 代理类,因此具有更好的性能,但需要使用特定的编译器进行处理;而 Spring AOP 则
采用运行时生成 AOP 代理类,因此无需使用特定编译器进行处理。由于 Spring AOP 需要在每次运行时
生成 AOP 代理,因此性能略差一些。
public class Main
{
public static void main(String[] args)
{
Chinese chin = ChineseProxyFactory.getAuthInstance();
System.out.println(chin.sayHello("孙悟空"));
chin.eat("西瓜");
System.out.println(chin.getClass());
}
}JDK Proxy
Cglib Proxy
只能代理接口
以继承的方式完成代理,不能代理被final修饰的类
JDK Proxy
Cglib Proxy
生成代理类时间
1'060.766
960.527
方法调用时间
0.008
0.003
来源
JDK原生代码
第三方库,更新频率较低