
4.2 动态代理
在Java中有多种动态代理技术,例如JDK、CGLIB、Javassist、ASM,其中最常用的动态代理技术是JDK和CGLIB。目前,在Spring AOP中常用JDK和CGLIB两种动态代理技术。
4.2.1 JDK动态代理
JDK动态代理是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象。因此,对于使用业务接口的类,Spring默认使用JDK动态代理实现AOP。下面通过一个实例演示如何使用JDK动态代理实现Spring AOP,具体步骤如下:
① 创建应用
创建一个名为ch4的Web应用,并导入所需的JAR包。
② 创建接口及实现类
在ch4的src目录下创建一个dynamic.jdk包,在该包中创建接口TestDao和接口实现类TestDaoImpl。该实现类作为目标类,在代理类中对其方法进行增强处理。
TestDao的代码如下:

TestDaoImpl的代码如下:

③ 创建切面类
在ch4的src目录下创建一个aspect包,在该包中创建切面类MyAspect,注意在该类中可以定义多个通知(增强处理的功能方法)。
MyAspect的代码如下:

④ 创建代理类
在dynamic.jdk包中创建代理类JDKDynamicProxy。在JDK动态代理中代理类必须实现java.Iang.reflect.InvocationHandler接口,并编写代理方法,在代理方法中需要通过Proxy实现动态代理。
JDKDynamicProxy的代码如下:

⑤ 创建测试类
在dynamic.jdk包中创建测试类JDKDynamicTest。在主方法中创建代理对象和目标对象,然后从代理对象中获取对目标对象增强后的对象,最后调用该对象的添加、修改和删除方法。
JDKDynamicTest的代码如下:

上述测试类的运行结果如图4.3所示。

图4.3 JDK动态代理的测试结果
从图4.3可以看出,testDao实例中的增加、修改和删除方法已经被成功调用,并且在调用前后分别增加了“模拟权限控制”“模拟异常处理”“模拟日志记录”和“性能监测”的功能。
4.2.2 CGLIB动态代理
从4.2.1节可知,JDK动态代理必须提供接口才能使用,对于没有提供接口的类,只能采用CGLIB动态代理。
CGLIB(Code Generation Library)是一个高性能开源的代码生成包,采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强。在Spring Core包中已经集成了CGLIB所需要的JAR包,不需要另外导入JAR包。下面通过一个实例演示CGLIB动态代理的实现过程,具体步骤如下:
① 创建目标类
在ch4的src目录下创建一个dynamic.cglib包,在该包中创建目标类TestDao,注意该类不需要实现任何接口。
TestDao的代码如下:

② 创建代理类
在dynamic.cglib包中创建代理类CglibDynamicProxy,该类实现MethodInterceptor接口。
CglibDynamicProxy的代码如下:

③ 创建测试类
在dynamic.cglib包中创建测试类CglibDynamicTest。在主方法中创建代理对象和目标对象,然后从代理对象中获取对目标对象增强后的对象,最后调用该对象的添加、修改和删除方法。
CglibDynamicTest的代码如下:

上述测试类的运行结果与图4.3一样,这里不再赘述。