CGLIB代理
JDK动态代理的使用非常简单,但它还有一定的局限性——使用动态代理的对象必须实现一个或多个接口。如果要对没有实现接口的类进行代理,那么可以使用CGLIB代理。
CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强。在Spring的核心包中已经集成了CGLIB所需要的包,所以开发中不需要另外导入JAR包。
接下来,通过一个案例来演示CGLIB代理的实现过程,具体步骤如下。
(1)在src目录下,创建一个com.itheima.cglib包,在包中创建一个目标类UserDao,UserDao不需要实现任何接口,只需定义一个添加用户的方法和一个删除用户的方法,如文件1所示。
文件1 UserDao.java
1 package com.itheima.cglib;
2 //目标类
3 public class UserDao {
4 public void addUser() {
5 System.out.println("添加用户");
6 }
7 public void deleteUser() {
8 System.out.println("删除用户");
9 }
10 }
(2)在com.itheima.cglib包中,创建代理类CglibProxy,该代理类需要实现MethodInterceptor接口,并实现接口中的intercept()方法,如文件2所示。
文件2 CglibProxy.java
1 package com.itheima.cglib;
2 import java.lang.reflect.Method;
3 import org.springframework.cglib.proxy.Enhancer;
4 import org.springframework.cglib.proxy.MethodInterceptor;
5 import org.springframework.cglib.proxy.MethodProxy;
6 import com.itheima.aspect.MyAspect;
7 // 代理类
8 public class CglibProxy implements MethodInterceptor{
9 // 代理方法
10 public Object createProxy(Object target) {
11 // 创建一个动态类对象
12 Enhancer enhancer = new Enhancer();
13 // 确定需要增强的类,设置其父类
14 enhancer.setSuperclass(target.getClass());
15 // 添加回调函数
16 enhancer.setCallback(this);
17 // 返回创建的代理类
18 return enhancer.create();
19 }
20 /**
21 * proxy CGlib根据指定父类生成的代理对象
22 * method 拦截的方法
23 * args 拦截方法的参数数组
24 * methodProxy 方法的代理对象,用于执行父类的方法
25 */
26 @Override
27 public Object intercept(Object proxy, Method method, Object[] args,
28 MethodProxy methodProxy) throws Throwable {
29 // 创建切面类对象
30 MyAspect myAspect = new MyAspect();
31 // 前增强
32 myAspect.check_Permissions();
33 // 目标方法执行
34 Object obj = methodProxy.invokeSuper(proxy, args);
35 // 后增强
36 myAspect.log();
37 return obj;
38 }
39 }
在文件2的代理方法中,首先创建了一个动态类对象Enhancer,它是CGLIB的核心类;然后调用了Enhancer类的setSuperclass()方法来确定目标对象;接下来调用了setCallback()方法添加回调函数,其中的this代表的就是代理类CglibProxy本身;最后通过return语句将创建的代理类对象返回。intercept()方法会在程序执行目标方法时被调用,方法运行时将会执行切面类中的增强方法。
(3)在com.itheima.cglib包中,创建测试类CglibTest。在该类的main()方法中首先创建代理对象和目标对象,然后从代理对象中获得增强后的目标对象,最后调用对象的添加和删除方法,如文件3所示。
文件3 CglibTest.java
1 package com.itheima.cglib;
2 // 测试类
3 public class CglibTest {
4 public static void main(String[] args) {
5 // 创建代理对象
6 CglibProxy cglibProxy = new CglibProxy();
7 // 创建目标对象
8 UserDao userDao = new UserDao();
9 // 获取增强后的目标对象
10 UserDao userDao1 = (UserDao)cglibProxy.createProxy(userDao);
11 // 执行方法
12 userDao1.addUser();
13 userDao1.deleteUser();
14 }
15 }
执行程序后,控制台的输出结果如图1所示。
图1 运行结果
从图1可以看出,目标类UserDao中的方法被成功调用并增强了。这种没有实现接口的代理方式,就是CGLIB代理。