在spring AOP中,通常会用cglib动态代理来生成AOProxy对象。cglib动态代理和JDk动态代理的不同之处在于cglib动态代理是通过继承被代理类,生成的动态代理类是被代理类的子类,然后通过重写业务方法来实现代理。
1、定义被代理类
public class cglibPerson {
public void findLove(){
System.out.println("肤白貌美大长腿");
}
}
2、定义代理类媒婆
public class cglibMeipo implements MethodInterceptor {
//好像并没有持有被代理对象的引用,也就是好像不满足都动态代理的第三个条件
public Object getInstance(Object object){
//Enhancer是CGLIB的字节码增强器,可以很方便的对类进行拓展,如为类设置Superclass。
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//这一步就是告诉chlib,生成的子类需要继承哪个类
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(object.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
//创建动态代理类对象并返回
//第一步、生成源代码,也就是代理类的二进制字节码文件
//第二步、加载二进制字节码,编译成class对象
//第三步、加载到JVM中,并返回被代理对象
return enhancer.create();
}
//实现MethodInterceptor,重写方法
//同样是做了字节码重组这样一件事情
//对于使用API的用户来说,是无感知的
//obj cglib生成的代理对象 sub:cglib生成的代理对象,method:被代理对象方法,objects:方法入参,methodProxy:代理方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("我是媒婆:" + "得给你找个男的");
System.out.println("开始进行海选");
System.out.println("--------------------------------");
//这个o的引用是由chlib new出来的
//chlib new出来的对象,是被代理对象的子类(继承了自己写的那个类)
//oop,在new子类之前,实际上默认先调用了我们super()方法的
//new了子类的同时,必须先new出来父类,这就相当于是间接的持有我们父类的引用
//子类重写了父类的所有方法
//我们改变子类对象的某些属性,也就是改变了父类的某些对象
//methodProxy.invokeSuper是代理类(子类)调用父类的方法
//methodProxy.invoke是调用自己,也就是代理类的方法
methodProxy.invokeSuper(obj,args);
System.out.println("--------------------------------");
System.out.println("如何合适就恋爱");
return null;
}
}
3、使用时,然后通过 代理类对象.getInstance(业务类对象) 返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指向它)。最后通过动态代理类对象进行方法调用。
public static void main(String[] args){
//创建业务类和代理类对象,
// 然后通过 代理类对象.getInstance(业务类对象) 返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指向它)。
// 最后通过动态代理类对象进行方法调用。
cglibPerson obj = (cglibPerson)new cglibMeipo().getInstance(new cglibPerson());
obj.findLove();
}
从代码看被代理的类无需接口即可实现动态代理,而CGLibProxy代理类需要实现一个方法拦截器接口MethodInterceptor并重写intercept方法,类似JDK动态代理的InvocationHandler接口,也是理解为回调函数,同理每次调用代理对象的方法时,intercept方法都会被调用,利用该方法便可以在运行时对方法执行前后进行动态增强。关于代理对象创建则通过Enhancer类来设置的,Enhancer是一个用于产生代理对象的类,作用类似JDK的Proxy类,因为CGLib底层是通过继承实现的动态代理,因此需要传递目标对象(如A)的Class,同时需要设置一个回调函数对调用方法进行拦截并进行相应处理,最后通过create()创建目标对象(如A)的代理对象,运行结果与前面的JDK动态代理效果相同。
JDK动态代理和chlib的区别
JDK的动态代理是通过接口来进行强制转换的
生成以后的代理对象,可以强制转换为接口
cglib的动态代理时通过生成一个被代理对象的子类,然后重写父类的方法
生成以后的对象,可以强制转换为被代理对象(也就是用自己写的类)
子类引用赋值给父类