字节码增强和spring AOP 原理

  • Java字节码增强指的是在Java字节码生成之后,对其进行修改,增强其功能,这种方式相当于对应用程序的二进制文件进行修改。Java字节码增强的应用场景主要是减少冗余代码,对开发人员屏蔽底层的实现细节。 字节码增强技术主要有两种实现机制:一种是通过创建原始类的一个子类;另一种是很暴力的方式,直接去修改原先的class字节码。
  • 字节码增强技术:AOP技术其实就是字节码增强技术,JVM提供的动态代理追根究底也是字节码增强技术。 
    应用场景:某一天系统出现OOM,通过工具分析,是莫各类的对象占用了很大空间,但是这个对象被许多程序访问,那么就很难找到,工程的全文匹配也只能找到自己的业务代码调用的地方,深入的反射,三方包调用无法匹配。这个时候AOP就可以帮助完成。
  • 两种实现机制:一种是通过创建原始类的一个子类,也就是动态创建的这个类继承原来的类,现在的SpringAOP正式通过这种方式实现,另一种是非常暴力的,即直接修改原先的Class字节码,在许多类的跟踪过程中会用到这技术(类加载时修改字节码信息,运行时修改)。
  • 字节码增强步骤: 
    1.在内存中获取到原始的字节码,然后通用一些开源提供的API来修改它的byte[]数组,得到一个新的byte[]。(ASM,javassist,cglib等技术) 
    2.将这个新的数组写到PermGen区域,也就是加载它或替换原来的Class字节码(也可以在进程外部调用完成)

反射和ASM区别

反射是读取持久堆上存储的类信息。而 ASM 是直接处理 .class 字节码的小工具(工具虽小,但是功能非常强大!)



反射只能读取类信息,而 ASM 除了读还能写。

反射读取类信息时需要进行类加载处理,而 ASM 则不需要将类加载到内存中。

反射相对于 ASM 来说使用方便,想直接操纵 ASM 的话需要有 JVM 指令基础。


Spring AOP 代理实现有两种: JDK动态代理 和 Cglib框架动态代理


一、首先说一下JDK中的动态代理

JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的,

但是,JDK中所要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具有一定的局限性,而且使用反射的效率也并不是很高。

二、使用CGLib实现

使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

JDK动态代理 简单介绍http://blog.csdn.net/qq_34446485/article/details/77460855

JDK API 内置 —- 通过 Proxy类,为目标对象创建代理 (必须面向接口代理 )

[java] 
view plain
 copy

  1. public class JdkProxyFactory implements InvocationHandler {  
  2.     // 被代理对象  
  3.     private Object target;  
  4.   
  5.     // 在构造方法对象时,传入被代理对象  
  6.     public JdkProxyFactory(Object target) {  
  7.         this.target = target;  
  8.     }  
  9.   
  10.     // 创建代理  
  11.     public Object createProxy() {  
  12.         // 三个参数: 类加载器、 实现接口、 invocationhandler  
  13.         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);  
  14.     }  
  15.   
  16.     @Override  
  17.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  18.         System.out.println(“记录日志!!!!!!”);  
  19.         // 调用目标真实方法  
  20.         // target 被代理对象, args 方法参数 , method 被调用的方法  
  21.         return method.invoke(target, args);  
  22.     }  
  23. }  

缺点: 使用Jdk动态代理,必须要求target目标对象,实现接口 ,如果没有接口,不能使用Jdk动态代理 

Cglib 动态代理

CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。

一、什么是CGLIB?

CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。

二、CGLIB原理

CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

CGLIB缺点:对于final方法,无法进行代理。

Cglib 不但可以对接口进行代理,也可以对目标类对象,实现代理 (解决了 Jdk 只能对接口代理问题 )在spring3.2版本 core包中内置cglib 类 

[java] 
view plain
 copy

  1. public class CglibProxyFactory implements MethodInterceptor {  
  2.     // 被代理目标对象  
  3.     private Object target;  
  4.   
  5.     // 在构造工厂时传入被代理对象  
  6.     public CglibProxyFactory(Object target) {  
  7.         this.target = target;  
  8.     }  
  9.   
  10.     // 创建代理对象方法  
  11.     public Object createProxy() {  
  12.         // 1、 创建Enhancer对象  
  13.         Enhancer enhancer = new Enhancer();  
  14.   
  15.         // 2、 cglib创建代理,对目标对象,创建子类对象  
  16.         enhancer.setSuperclass(target.getClass());  
  17.   
  18.         // 3、传入 callback对象,对目标增强  
  19.         enhancer.setCallback(this);  
  20.   
  21.         return enhancer.create();  
  22.     }  
  23.   
  24.     @Override  
  25.     public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
  26.         System.out.println(“记录日志……”);  
  27.         // 按照JDK编程  
  28.         return method.invoke(target, args);  
  29.     }  
  30. }  

Cglib 创建代理思想: 对目标类创建子类对象 


设置 superClass 对哪个类创建子类 (类似 JDK代理 接口)


设置 callback 实现增强代码 (类似 JDK代理 InvocationHandler )

在cglib的callback函数中,要执行被代理对象的方法 


method.invoke(target, args); 等价于 methodProxy.invokeSuper(proxy, args); 


优先对接口代理 (使用JDK代理),如果目标没有接口,才会使用cglib代理 !

《字节码增强和spring AOP 原理》

    原文作者:AOP
    原文地址: https://blog.csdn.net/StackFlow/article/details/80687765
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞