接着上篇博客的代理模式,我们继续,上篇博客介绍了JDK的动态代理,但是JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,这样就存在一定的局限性。对于这种情况,我们采用CGLIB来实现。
一、CGLIB动态代理
cglib是针对类来实现代理的,其实现原理:CGLIB的底层采用ASM字节码生成框架,使用字节码技术生成代理,比使用反射生成代理的效果要高,是对指定的目标类生成一个子类,并覆盖其中方法实现增强。但是也有一点点不足,因为采用的是继承,所以不能对final修饰的类进行代理。
还是使用以前的代码,依然还是简单的三步来实现。第一:建立一个普普通通的业务类;第二:写CGLIB代理类;第三:写测试代码或者客户端调用。这里的不同是第一步中,我们不需要在建接口了,只是一个普普通通的java类。
看代码:
<span style="font-family:KaiTi_GB2312;font-size:18px;"> /** * 业务类(包含业务逻辑) * 即:委托类 * @author Cassie */ public class Account{ @Override public void queryAccount() { System.out.println("查询方法..."); } @Override public void updateAccount() { System.out.println("修改方法..."); } }</span>
然后,我们来写CGLIB代理类:
<span style="font-family:KaiTi_GB2312;font-size:18px;">import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * 使用cglib动态代理 * @author Cassie * 实现MethodInterceptor 接口 */ public class CglibProxy implements MethodInterceptor { //委托对象,运行时定类型 private Object target; /** * 创建代理对象 * * @param target * @return */ public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回调方法 enhancer.setCallback(this); // 创建代理对象 return enhancer.create(); } @Override // 回调方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before"); Object result = proxy.invokeSuper(obj, args); System.out.println("after"); return result } } </span>
最后写测试类调用
<span style="font-family:KaiTi_GB2312;font-size:18px;">public class TestCglib { public static void main(String[] args) { //实例化代理 CglibProxy cglib=new CglibProxy(); //通过代理拿到对象 Account account = (Account)cglib.getInstance(new Account()); account.query(); } }</span>
通过以上代码,我们发现proxy.invokeSuper(obj,arg)是执行的关键。
使用CGLIB,需要实现 CGLib 给我们提供的 MethodInterceptor 实现类,并填充 intercept() 方法。方法中最后一个 MethodProxy 类型的参数 proxy,值得注意!CGLib 给我们提供的是方法级别的代理,也可以理解为对方法的拦截。我们直接调用 proxy 的 invokeSuper() 方法,将被代理的对象 obj 以及方法参数 args
传入其中即可。
至此,CGLIB代理也实现了。
时间: 2024-10-13 17:59:42