一、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 }