一、Cglib 代理模式的基本介绍
1、静态代理和 JDK 代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理,这就是 Cglib 代理。
2、Cglib 代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展,有些地方也将 Cglib 代理归属到动态代理。
3、Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 java 类与实现 java 接口,它广泛的被许多 AOP 的框架使用,例如:Spring AOP,实现方法拦截
4、在 AOP 编程中如何选择代理模式:
(1)目标对象需要实现接口,用 JDK 代理;
(2)目标对象不需要实现接口,用 Cglib 代理;
5、Cglib 包的底层是通过使用字节码处理框架 ASM 来转换字节码并生成新的类;
二、Cglib 代理模式实现步骤
1、需要引入 cglib 的 jar 文件
2、在内存中动态构建子类,注意代理的类不能为 final,否则报错:java.lang.IllegalArgumentException;
3、目标对象的方法如果是 final/static ,那么就不会被拦截,即不会执行目标对象额外的业务方法;
三、Cglib 代理模式应用实例
1、要求
将上一节的案例用 Cglib 代理模式实现
2、UML 类图
3、代码实现
被代理类(目标对象)
1 public class TeacherDao {
2
3 public String teach() {
4 System.out.println("老师授课中。。。我是cglib代理,不需要实现接口");
5 return "Hello";
6 }
7 }
代理工厂:
1 public class ProxyFactory implements MethodInterceptor {
2
3 /**
4 * 维护一个目标对象
5 */
6 private Object target;
7
8 /**
9 * 通过构造器,传入一个 被代理的 对象
10 * @param target
11 */
12 public ProxyFactory(Object target) {
13 this.target = target;
14 }
15
16
17 /**
18 *
19 * @return 返回一个代理对象(是target的代理对象)
20 */
21 public Object getProxyInstance() {
22 /**
23 * 1、创建一个工具类
24 * 2、设置父类
25 * 3、设置回调函数
26 * 4、创建子类对象,即代理对象
27 */
28
29 Enhancer enhancer = new Enhancer();
30 enhancer.setSuperclass(target.getClass());
31 enhancer.setCallback(this);
32 return enhancer.create();
33 }
34
35 /**
36 * 重写 intercept 方法,会调用目标对象的方法
37 * @param obj
38 * @param method
39 * @param args
40 * @param proxy
41 * @return
42 * @throws Throwable
43 */
44 @Override
45 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
46 System.out.println(obj.getClass());
47 System.out.println(proxy.getClass());
48 System.out.println("cglib代理模式~~开始");
49 Object invoke = method.invoke(target, args);
50 System.out.println("cglib代理模式~~提交");
51 return invoke;
52 }
53 }
客户端:
1 public class Client {
2
3 public static void main(String[] args) {
4 //创建目标对象
5 TeacherDao teacherDao = new TeacherDao();
6
7 //获取代理对象
8 ProxyFactory proxyFactory = new ProxyFactory(teacherDao);
9 TeacherDao proxyInstance = (TeacherDao)proxyFactory.getProxyInstance();
10 //执行代理对象的方法,触发 intecept 方法,从而实现对目标对象的调用
11 String res = proxyInstance.teach();
12 System.out.println(res);
13 System.out.println("proxyInstance=" + proxyInstance);
14
15 }
16 }