CGLib动态代理(实现原理全面详解)

CGLib动态代理(实现原理全面详解)-mikechen

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动态代理(实现原理全面详解)-mikechen

除了CGLib包,脚本语言例如 Groovy和BeanShell,也是使用ASM来生成java的字节码。

不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉,所以CGLib包要依赖于asm包,需要一起导入。

 

CGLib的应用场景

  1. CGLib被广泛使用在基于代理的AOP框架(例如Spring AOP和dynaop)提供方法拦截;
  2. hibernate使用CGLib对持久化对象创建代理;
  3. EasyMock和jMock作为流行的Java测试库,它们提供Mock对象的方式来支持测试,都使用了CGLib来对没有接口的类进行代理。

注意:Spring AOP和Hibernate同时使用JDK的动态代理和CGLib包,Spring AOP,如果不强制使用CGLib包,默认情况是使用JDK的动态代理来代理接口。

 

CGLib实现动态代理

CGLib实现动态代理的特点是针对类进行代理,具体来说是,cglib会对要被代理的类生成一个继承子类,在子类中对方法进行增强。

注意:关键点就在继承,所以无法对final类使用。

1.创建一个实现类

  1. package com.demo.rpc.proxy;
  2.  
  3. public class HelloService {
  4. public void sayHello(){
  5. System.out.println("hello");
  6. }
  7. }

2.新建一个代理类

  1. package com.demo.rpc.proxy;
  2.  
  3. import net.sf.cglib.proxy.Enhancer;
  4. import net.sf.cglib.proxy.MethodInterceptor;
  5. import net.sf.cglib.proxy.MethodProxy;
  6.  
  7. import java.lang.reflect.Method;
  8.  
  9. public class CGLIBProxy implements MethodInterceptor {
  10.  
  11.  
  12. Object targetObject;
  13.  
  14. public Object newProxy(Object targetObject){
  15. this.targetObject = targetObject;
  16. Enhancer enhancer = new Enhancer();
  17. enhancer.setSuperclass(targetObject.getClass());
  18. enhancer.setCallback(this);
  19. Object proxyObj = enhancer.create();
  20. return proxyObj;
  21. }
  22.  
  23.  
  24. @Override
  25. public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  26. System.out.println("代理之前");
  27. Object invoke = method.invoke(targetObject, args);
  28. System.out.println("代理之后");
  29. return invoke;
  30. }
  31. }
  32.  

3.代用测试

  1. @Test
  2. public void CGLIBProxy(){
  3. CGLIBProxy proxy = new CGLIBProxy();
  4. HelloService helloService = (HelloService)proxy.newProxy(new HelloService());
  5. helloService.sayHello();
  6. }

4.运行结果

  1. 代理之前
  2. hello
  3. 代理之后

 

CGLib总结

总结来说CGLib是一个强大的、高性能的Code生产类库,在Spring中就是通过CGLib方式继承要被代理的类,重写父类的方法,实现Aop编程。

CGLib创建动态代理对象的性能时机要比jdk动态代理的方式高很多,但是创建对象所花的时间却要比jdk动态代理方式多很多。

在应用方面单例模式更适合用CGLib,无需频繁的创建对象,相反,则使用jdk动态代理的方式更加合适。

评论交流
    说说你的看法
欢迎您,新朋友,感谢参与互动!