上一篇文章介绍了通过JDKProxy的方式,将之前的静态代理转换为动态代理,传送门如下:
今天继续研究动态代理的另外一种形式,通过Cglib实现动态代理,Cglib是针对类来实现代理的,他的原理是对代理的目标类生成一个子类,并覆盖其中方法来实现增强,因为底层是基于创建被代理类的一个子类,所以它避免了JDK动态代理类的缺陷(被代理类必须要实现接口,JDK动态代理重要特点是代理接口)。但因为采用的是继承,所以不能对final修饰的类进行代理,因为final修饰的类不可继承。
通过Cglib实现动态代理,首先需要引入Cglib包:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
我们还是以找对象这个例子来说明,首先是被代理对象:
package com.rq.pattern.proxy.dynamicproxy.cglibproxy;
/**
* Title: WangWu
* Description:
* @author RQ
* @date 2020年3月30日
*/
public class WangWu {
/**
* 王五找老婆
*/
public void findLove() {
System.out.println("王五找老婆要求:身轻体柔易推倒");
}
}
可以看到,被代理对象是不需要实现接口的,接下来就是实现代理的类:
package com.rq.pattern.proxy.dynamicproxy.cglibproxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* Title: CglibMeiPo
* Description: 中介媒婆
* @author RQ
* @date 2020年3月30日
*/
public class CglibMeiPo implements MethodInterceptor{
public Object getInstance(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
private void before() {
System.out.println("中介媒婆收到相关需求,开始寻找资源");
}
private void after() {
System.out.println("相亲完成后,双方来电,开始交往");
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
before();
Object result = proxy.invokeSuper(obj, args);
after();
return result;
}
}
通过Cglib实现动态代理,核心是实现MethodInterceptor接口,并重写intercept()方法,Cglib生成代理类时,是通过Enhancer类实现的,入参是被代理类,因为动态生成的类是被代理类的子类,所以我们设置目标类为生成类的父类,enhancer.setSuperclass(clazz);其他的步骤都是Cglib中约定好的步骤,约定俗成。
如果想要针对动态生成的类做增强,我们可以将增强部分的代码写在intercept()方法中,该方法会被动态代理生成的类自动调用,例如在上面例子中的before()、after()方法都是针对生成类的增强。
看一下通过Cglib动态代理的具体使用方法:
package com.rq.pattern.proxy;
import com.rq.pattern.proxy.dynamicproxy.cglibproxy.CglibMeiPo;
import com.rq.pattern.proxy.dynamicproxy.cglibproxy.WangWu;
/**
* Title: CglibProxyTest
* Description: Cglib测试
* @author RQ
* @date 2020年3月30日
*/
public class CglibProxyTest {
public static void main(String[] args) {
CglibMeiPo meipo = new CglibMeiPo();
WangWu wangWu = (WangWu) meipo.getInstance(WangWu.class);
wangWu.findLove();
}
}
运行结果如下:
中介媒婆收到相关需求,开始寻找资源
王五找老婆要求:身轻体柔易推倒
相亲完成后,双方来电,开始交往
静态代理、JDK方式动态代理、Cglib方式动态代理比较如下:
1、静态代理在编译时产生class字节码文件,可以直接使用,效率高。
2、JDK动态代理必须实现InvocationHandler接口,通过invoke调用被委托类接口方法是通过反射方式,比较消耗系统性能,但可以减少代理类的数量,使用更灵活。
3、Cglib代理无需实现接口,通过生成类字节码实现代理,比反射稍快,不存在性能问题,但cglib会继承目标对象,需要重写方法,所以目标对象不能为final类。
以上是在学习动态代理模式中的学习心得,欢迎相互学习讨论。