CGLIB动态代理
jdk动态代理是根据实现接口来进行代理,只适合有接口的被代理类。而CGLIB动态代理是通过继承被代理类来实现代理的,适用于没有接口的被代理类。
代码实现
下面通过销售汽车的例子来实现代码。
pom文件引入依赖:
(如果不是maven工程,需要引入cglib和asm两个依赖,因为cglib需要靠asm解析)
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
/**
* 真实主体类(目标对象)
*/
public class CarFactory{
public void sell() {
System.out.println("进行汽车售卖");
}
public void check() {
System.out.println("进行汽车检测");
}
}
/**
* 代理工厂对象(创造代理类)
*/
public class ProxyFactory implements MethodInterceptor {
//真实主题类
private CarFactory carFactory=new CarFactory();
public CarFactory getProxyObject(){
//创建Enhance对象,类似jadk中的Proxy类
Enhancer enhancer = new Enhancer();
//设置父类的字节码对象
enhancer.setSuperclass(CarFactory.class);
//设置回调函数
enhancer.setCallback(this);
//创建代理对象
CarFactory carFactory=(CarFactory)enhancer.create();
return carFactory;
}
/**
*
* @param o 代理类对象
* @param method 代理的方法
* @param objects 代理方法参数
* @param methodProxy 代理方法
* @return 代理方法的返回值
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行其他操作");
method.invoke(carFactory,objects);
return null;
}
}
测试
public class Client {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
CarFactory proxyObject = proxyFactory.getProxyObject();
System.out.println("父类是"+proxyObject.getClass().getSuperclass());
proxyObject.sell();
System.out.println("--------");
proxyObject.check();
}
}
分析
ProxyFactory类不是代理类,是代理类工厂,用来创建代理类的。
通过CGLIB实现动态代理需要创建Enhancer对象,其就相当于Proxy类。因为CGLIB代理是通过继承被代理类来实现代理的,所以要设置其父类字节码对象,也就是被代理类。此外,还需要设置一个回调函数,参数是一个函数式接口,要重写intercept()方法,就相当于JDK代理中InvocationHandler接口。这个方法有四个参数:
@param o 代理类对象 * @param method 代理的方法 * @param objects 代理方法参数 * @param methodProxy 代理方法
在此方法中进行方法增强,当通过代理类调用代理方法时就会调用此方法。
method.invoke()方法就是执行被代理类中的方法(原方法)。
注:method.invoke()方法的第一个参数不能写成o,否则会进入死循环。
总结
CGLIB动态代理是通过继承被代理类来实现代理的,所以被代理类不用实现接口。但是需要注意的是CGLIB不能代理加了final关键字的类,因为加了final关键字的类不能被继承。
使用动态代理能够把代理的方法都集成在一个方法invoke中,即使新增方法,也不用修改代理类,扩展性好。
在很多地方都用到了代理,比如spring的aop就是通过代理实现的。鉴权也是通过代理。
关于CJLib的具体解释可查看这篇文章