Spring AOP原理

AOP即面向切面编程,是OOP编程的有效补充。使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统。从而避免了在业务逻辑的代码中混入很多的系统相关的逻辑——比如权限管理,事物管理,日志记录等等。这些系统性的编程工作都可以独立编码实现,然后通过AOP技术切入进系统即可。从而达到了将不同的关注点分离出来的效果。

一:Spring AOP概念

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程.AOP最早是AOP联盟的组织提出的,指定的一套规范,spring将AOP的思想引入框架之中,通过预编译方式运行期间动态代理实现程序的统一维护的一种技术。

举例:给StudentServiceImp中的

中所有方法添加进入方法的日志。

我们将记录日志功能解耦为日志切面,它的目标是解耦。进而引出AOP的理念:就是将分散在各个业务逻辑代码中相同的代码通过横向切割的方式抽取到一个独立的模块中

二、Spring AOP的术语


连接点(Jointpoint):表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等等,Spring只支持方法执行连接点,在AOP中表示为在哪里干;

切入点(Pointcut): 选择一组相关连接点的模式,即可以认为连接点的集合,Spring支持perl5正则表达式和AspectJ切入点模式,Spring默认使用AspectJ语法,在AOP中表示为在哪里干的集合;

通知(Advice):在连接点上执行的行为,通知提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段;包括前置通知(before advice)、后置通知(after advice)、环绕通知(around advice),在Spring中通过代理模式实现AOP,并通过拦截器模式以环绕连接点的拦截器链织入通知;在AOP中表示为干什么;

方面/切面(Aspect):横切关注点的模块化,比如上边提到的日志组件。可以认为是通知、引入和切入点的组合;在Spring中可以使用Schema和@AspectJ方式进行组织实现;在AOP中表示为在哪干和干什么集合;

引入(inter-type declaration):也称为内部类型声明,为已有的类添加额外新的字段或方法,Spring允许引入新的接口(必须对应一个实现)到所有被代理对象(目标对象), 在AOP中表示为干什么(引入什么);

目标对象(Target Object):需要被织入横切关注点的对象,即该对象是切入点选择的对象,需要被通知的对象,从而也可称为被通知对象;由于Spring AOP 通过代理模式实现,从而这个对象永远是被代理对象,在AOP中表示为对谁干;

织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。在AOP中表示为怎么实现的;

AOP代理(AOP Proxy):AOP框架使用代理模式创建的对象,从而实现在连接点处插入通知(即应用切面),就是通过代理来对目标对象应用切面。在Spring中,AOP代理可以用JDK动态代理或CGLIB代理实现,而通过拦截器模型应用切面。在AOP中表示为怎么实现的一种典型方式;
 

通知类型:

前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。

后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

异常通知(After throwing advice):在方法抛出异常退出时执行的通知。

最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。


三、Spring AOP 实现方式

        AOP分为静态AOP和动态AOP。静态AOP是指AspectJ实现的AOP,他是将切面代码直接编译到Java类文件中。动态AOP是指将切面代码进行动态织入实现的AOP。Spring的AOP为动态AOP,实现的技术为:JDK提供的动态代理技术 和 CGLIB(动态字节码增强技术)。尽管实现技术不一样,但都是基于代理模式,都是生成一个代理对象。

3.1 JDK动态代理

        主要使用到 InvocationHandler 接口和 Proxy.newProxyInstance() 方法。JDK动态代理要求被代理实现一个接口,只有接口中的方法才能够被代理。其方法是将被代理对象注入到一个中间对象,而中间对象实现InvocationHandler接口,在实现该接口时,可以在 被代理对象调用它的方法时,在调用的前后插入一些代码。而 Proxy.newProxyInstance() 能够利用中间对象来生产代理对象。插入的代码就是切面代码。所以使用JDK动态代理可以实现AOP。

JDK动态代理:必须是面向接口的,只有实现了具体接口的类才能生成代理对象

3.2 CGLIB动态代理

        CGLIB动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。CGLIB动态代理和jdk代理一样,使用反射完成代理,不同的是他可以直接代理类(jdk动态代理不行,他必须目标业务类必须实现接口),CGLIB动态代理底层使用字节码技术,CGLIB动态代理不能对 final类进行继承。(CGLIB动态代理需要导入jar包)。

最底层的是字节码 Bytecode ,字节码是 java 为了保证依次运行,可以跨平台使用的一种虚拟指令格式,在字节码文件之上的是ASM,只是一种直接操作字节码的框架,应用 ASM 需要对 Java 字节码、 class 结构比较熟悉位于 ASM 上面的是 Cglib、groovy、beanshell,后来那个种并不是 Java 体系中的内容是脚本语言,他们通过 ASM 框架生成字节码变相执行 Java 代码,在JVM中程序执行不一定非要写 java 代码,只要能生成 java 字节码, JVM 并不关系字节码的来源位于 cglib、groovy、beanshell之上的就是 hibernate 和 Spring AOP,最上面的是applications。

3.3 Cglib 和 jdk 动态代理的区别

        Jdk动态代理:利用拦截器(必须实现 InvocationHandler )加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
Cglib动态代理:利用 ASM 框架,对代理对象类生成的 class 文件加载进来,通过修改其字节码生成子类来处理
什么时候用 cglib 什么时候用 JDK 动态代理?

目标对象生成了接口 默认用 JDK 动态代理
如果目标对象使用了接口,可以强制使用 cglib
如果目标对象没有实现接口,必须采用 cglib 库, Spring 会自动在 JDK 动态代理和 cglib 之间转换
JDK 动态代理和 cglib 字节码生成的区别?

JDK 动态代理只能对实现了接口的类生成代理,而不能针对类。
Cglib 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法的增强,但是因为采用的是继承,所以该类或方法最好不要设置为 final ,对于 final 类或方法,是无法继承的
 

四、Spring AOP的配置

AOP是一个标准规范,而为了实现这个标准规范,有几种方式:

1:基于代理的AOP
2:@AspectJ注解驱动的切面
3:纯POJO切面
4:注入式AspectJ切面
        这四种方式都是实现aop的方法,这里讲一下通过AspectJ提供的注解实现AOP,使用AspectJ 注解方式来实现。

增加切面类

使用@Aspect注解声明一个切面,并使用@Before、@After等注解表明连接点

测试运行方法:可以看到对方法进行了增强

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值