前两篇博文中讲到静态代理和动态代理都要求目标对象实现一个接口,但在日常开发中,有时候目标对象只是一个单独的对象,并没有实现任何接口,这种情况下,上述两种代理方式都无法使用,应该使用以目标对象子类的方式实现代理,这种方法叫做Cglib代理。
Cglib代理也叫做子类代理,它是在内存中构建一个子类对象,从而实现对目标对象功能的扩展。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口,它广泛的被许多AOP框架使用,例如Spring AOP和synaop,为它们提供方法的interception(拦截)。
Cglib包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件格式和指令集都很熟悉。
Cglib代理实现方法:
1、引入cglib的jar包,如果你使用Spring的话,其核心包spring-core中已经包含的cglib
2、引入功能包后,就可以在内存中动态构建子类
3、代理对象不能为final,否则会报错
4、目标对象的方法如果被final、static修饰,那么该方法不会被拦截,即不能完成功能的扩展。
代码实现:
在【JAVA代理模式详解】之静态代理基础上,增加一个代理工厂类ProxyFactory2,实现MethodInterceptor接口
public class ProxyFactory2 implements MethodInterceptor {
/**
* 目标对象
*/
private Object target;
public ProxyFactory2(Object target) {
this.target = target;
}
/**
* 生成代理对象
*/
public Object getProxyInstance() {
// 工具类
Enhancer en = new Enhancer();
// 设置父类
en.setSuperclass(target.getClass());
// 设置回调
en.setCallback(this);
// 创建子类,即代理对象
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
System.out.println("Cglib代理:我是经纪人,我去安排歌手唱歌。");
Object ret = method.invoke(target, args);
System.out.println("Cglib代理:唱完了,请付款。");
return ret;
}
}
测试类:
public class ProxyMain {
public static void main(String[] args) {
// 目标对象
Singer singer = new SingerImpl();
// 代理对象
Singer proxy = (Singer) new ProxyFactory2(singer).getProxyInstance();
proxy.sing();
}
}
执行结果:
总结:在Spring AOP编程中
如果目标对象实现了接口,则用JDK代理
如果模板对象没有实现接口,则用Cglib代理