原文同步发表至我的博客【夜月归途】html
原文连接:http://www.guitu18.com/se/java/2018-06-29/18.htmljava
本博客关于Java动态代理相关内容直达连接:spring
Java中的动态代理设计模式是很是经典且很是重要的设计模式之一,在感叹设计者的天才设计至于,咱们想去探究一下这个设计模式是如何来实现的;设计模式
著名的spring框架的AOP的原理就是Java的动态代理机制;框架
在Spring中动态代理是实现有两种:JDK动态代理和Cglib动态代理,本篇分析的是Cglib动态代理的实现;ide
JDK动态代理以前已经作过度析了[ JDK动态代理浅析 ],经过案例咱们知道了,Java动态代理的强大之处;可是不难看出来使用JDK动态代理也有着它的局限性,JDK动态代理是在JVM内部动态的生成class字节码对象,可是JDK动态代理只能针对接口进行操做,也就是只能对接口的实现类去进行代理;post
如今分析一下另外一种经常使用的动态代理技术:Cglib动态代理;性能
CGLIB(Code Generation Library)是一个开源项目;
是一个强大的,高性能,高质量的Code生成类库,它能够在运行期扩展Java类与实现Java接口;
CGLIB包的底层是经过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类;
Cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理;
因此Cglib能够为无接口的类直接作代理,固然有接口的类也是能够的并没有影响。 测试
由于采用的是继承,因此不能对final修饰的类进行代理;Cglib的使用限制无疑要比JDK动态代理要宽松不少;ui
废话很少说,先上案例;
这里说明一下,若是是Spring框架那么无所谓,Spring框架的spring-core.jar包中已经集成了cglib与asm;若是你要单独使用CGLIB,那么须要导入cglib的jar包和asm相关jar包;
Programmer类:
public class Programmer { public void work(String name) { System.out.println(name + " 正在工做..."); } }
CglibProxyFactory代理类:
public class CglibProxyFactory implements MethodInterceptor { private Object target; public CglibProxyFactory(Object target) { this.target = target; } public Object getProxyInstance() { // 建立 Enhancer 对象 Enhancer enhancer = new Enhancer(); // 设置目标对象的Class enhancer.setSuperclass(target.getClass()); // 设置回调操做,至关于InvocationHandler enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("开始事务..."); // 两种方式执行方法,第二行注释掉的,和当前行代码效果相同,下面会分析; Object invoke = method.invoke(target, args); // Object invoke = methodProxy.invokeSuper(proxy, args); System.out.println("提交/回滚事务..."); return invoke; } }
Cglib建立代理的方式很是简单,是经过Enhancer对象,须要给它set两个参数:
设置目标对象的Class; 设置回调操做,至关于InvocationHandler,须要实现MethodInterceptor 接口; 以后执行create()方法便可返回目标对象的代理对象;
这里为了方便,直接让CglibProxyFactory实现了MethodInterceptor 接口,须要实现重写MethodInterceptor.intercept()方法;
在intercept()方法中,其实跟InvocationHandler.invoke中作的事是同样的,咱们须要调用method.invoke()去执行方法;
在案例中,还有注释掉的一行:Object invoke = methodProxy.invokeSuper(proxy, args);
这个和上面的 Object invoke = method.invoke(target, args); 是同样的效果,都是代理执行方法,下面进行说明;
从代码中看出,intercept()的参数比JDK的invoke()多了一个,前三个参数跟JDK的invoke()方法同样很少说,第四个参数MethodProxy methodProxy是当前代理对象执行的方法的一个代理,也就是MethodProxy methodProxy是第二个参数Method method的代理;
前面咱们说过,Cglib动态代理的机制是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理;也就是参数一Object proxy其实是咱们的目标对象Object target的一个子类;
咱们直接使用 method.invoke(target, args) 执行方法,和使用methodProxy.invokeSuper(proxy, args) 执行是一个什么关系呢;
第一个被代理类target直接调用method执行没问题,第二个实际上是target的子类proxy去掉用父的方法,我第一次看这里也是有点绕哈,可是其实就是这么个关系,这两个方法执行的效果是同样的,可是一般咱们只使用第一种方式;
测试执行,贴测试代码:
public class CglibProxyFactoryTest { public static void main(String[] args) { Programmer programmer = new Programmer(); CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(programmer); Programmer instance = (Programmer) cglibProxyFactory.getProxyInstance(); instance.work("夜月归途"); } }
控制台输出:
开始事务... 夜月归途 正在工做... 提交/回滚事务...
看到这里和JDK的动态代理是同样的,Cglib的的动态代理没有接口的限制,有接口的类和无接口的类均可以被代理,只要不是final的;
在这里,一样代码能够精简一下:
public class CglibProxyFactory { public static Object getProxyInstance(Object target) { // 建立 Enhancer 对象 Enhancer enhancer = new Enhancer(); // 设置目标对象的Class enhancer.setSuperclass(target.getClass()); // 设置回调操做,至关于InvocationHandler enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("开始事务..."); // Object invoke1 = method.invoke(target, args); Object invoke2 = methodProxy.invokeSuper(proxy, args); System.out.println("提交/回滚事务..."); return invoke2; } }); return enhancer.create(); } }
以匿名内部类形式建立代理对象,这样子代码清爽许多;
尾巴: