AOP基本概念
概念:
- AOP是 Aspect Oriented Programing 的简称,中文最初翻译为"面向方面编程",通常我们更喜欢称之为"面向切面编程"。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能,日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其它类型的代码,如安全性、异常处理也是如此。这种散布在各处的代码被称为横切(cross cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用,因此引入了AOP的编程理念,可以说AOP是OOP的补充和完善。
- AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,它们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”
AOP术语
通知----Advice
- 切面也是有目标的 ——它必须完成的工作。在AOP术语中,切面的工作被称之为通知。
- 通知:定义了切面是什么,何时使用,其描述了切面要完成的工作,还解决何时执行这个工作的问题。
- Spring切面可以应用5种类型的通知:
- 前置通知(Before): 在目标方法被调用之前调用通知功能;
- 后置通知(After): 在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
- 返回通知(After-returning):在目标方法成功执行之后调用通知;
- 异常通知(After-throwing): 在目标方法抛出异常后通知调用;
- 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。
连接点----Join Point
- 连接点:是在应用执行过程中能够插入切面的一个点,这个点可以是方法调用时,抛出异常时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
切点----Pointcut
- 切点:是缩小切面所通知的连接点的范围。如果说通知定义了切面是什么和何时的话,那么切点就定义了何处。切点的定义会匹配通知所要织入的一个或者多个连接点。我们通常会使用明确的类和方法名称,或者利用正则表达式定义所匹配的类和方法名来指定这些切点。
切面----Aspect
- 切面:是通知和切点的结合。通知和切点共同定义了切面的全部内容————它是什么,在何时,在何处完成其功能。
织入----weaving
- 织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中。
- 在目标对象的生命周期里有多个点可以进行织入:
编译期:
- 切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面
的。类加载器:
- 切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入(load-time weaving. LTW)就支持以这种方式织入切面。
运行期:
- 切面在应用运行的某一时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象。SpringAOP就是以这种方式织入切面的。
Spring AOP
- 添加需要的jar包
- 添加命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
- 添加xml
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 代码
package com.github.Factory; interface ISubject{ void eat(); }
package com.github.Factory; class RealSubject implements ISubject{ @Override public void eat() { System.out.println("我要吃1个苹果"); } }
package com.github.Factory; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect class ProxySubject { @Pointcut("execution(* eat*(..))") private void ProxyInstance(){} @Before("ProxyInstance()") public void preHandle(){ System.out.println("-------------before---------"); } @After("ProxyInstance()") public void aftHandle(){ System.out.println("-------------After-----------"); } }
package com.github.Factory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); ISubject iSubject = (ISubject) context.getBean("realsubject"); iSubject.eat(); } }
优点:
- 降低模块耦合度
- 使系统容易扩展
- 延迟设计决定:使用AOP,设计师可以推迟为将来的需求作决定,因为需求作为独立的方面很容易实现
- 更好的代码复用性
2021-10-10 补充
AOP的通知执行顺序
1.Spring4执行顺序
- 正常顺序
- 前置环绕通知
- 前置通知
- 业务逻辑
- 后置环绕通知
- 后置通知
- 返回通知
- 异常顺序
- 前置环绕通知
- 前置通知
- 业务逻辑
- 后置通知
- 异常通知
2.Spring5执行顺序
- 正常顺序
- 前置环绕通知
- 前置通知
- 业务逻辑
- 返回通知
- 后置通知
- 后置环绕通知
- 异常顺序
- 前置环绕通知
- 前置通知
- 业务逻辑
- 异常通知
- 后置通知