CGLib简介
Cglib 是一个强大的高性能的代码生成包,它的底层就是asm(字节码框架),可以在运行期扩展 java 类,广泛的被许多 AOP 的框架使用,例如 Spring AOP,实现方法拦截。
Cglib优缺点
1.优点
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。
另一个优点是Cglib动态代理比使用java反射的JDK动态代理要快(Cglib的FastClass机制)。
2.缺点
对于被代理类中的final方法,无法进行代理,因为子类中无法重写final函数。
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
CGLib组成结构
CGLib包的底层是通过使用一个小而快的字节码处理框架ASM(Java字节码操控框架),来转换字节码并生成新的类,下图为CGLib与一些框架和语言的关系:
除了CGLib包,脚本语言例如 Groovy和BeanShell,也是使用ASM来生成java的字节码。
不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉,所以CGLib包要依赖于asm包,需要一起导入。
CGLib的应用场景
- CGLib被广泛使用在基于代理的AOP框架(例如Spring AOP和dynaop)提供方法拦截;
- hibernate使用CGLib对持久化对象创建代理;
- EasyMock和jMock作为流行的Java测试库,它们提供Mock对象的方式来支持测试,都使用了CGLib来对没有接口的类进行代理。
注意:Spring AOP和Hibernate同时使用JDK的动态代理和CGLib包,Spring AOP,如果不强制使用CGLib包,默认情况是使用JDK的动态代理来代理接口。
CGLib实现动态代理
CGLib实现动态代理的特点是针对类进行代理,具体来说是,cglib会对要被代理的类生成一个继承子类,在子类中对方法进行增强。
注意:关键点就在继承,所以无法对final类使用。
1.创建一个实现类
package com.demo.rpc.proxy; public class HelloService { public void sayHello(){ System.out.println("hello"); } }
2.新建一个代理类
package com.demo.rpc.proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CGLIBProxy implements MethodInterceptor { Object targetObject; public Object newProxy(Object targetObject){ this.targetObject = targetObject; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(targetObject.getClass()); enhancer.setCallback(this); Object proxyObj = enhancer.create(); return proxyObj; } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("代理之前"); Object invoke = method.invoke(targetObject, args); System.out.println("代理之后"); return invoke; } }
3.代用测试
@Test public void CGLIBProxy(){ CGLIBProxy proxy = new CGLIBProxy(); HelloService helloService = (HelloService)proxy.newProxy(new HelloService()); helloService.sayHello(); }
4.运行结果
代理之前 hello 代理之后
CGLib总结
总结来说CGLib是一个强大的、高性能的Code生产类库,在Spring中就是通过CGLib方式继承要被代理的类,重写父类的方法,实现Aop编程。
CGLib创建动态代理对象的性能时机要比jdk动态代理的方式高很多,但是创建对象所花的时间却要比jdk动态代理方式多很多。
在应用方面单例模式更适合用CGLib,无需频繁的创建对象,相反,则使用jdk动态代理的方式更加合适。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》