Spring学习之旅(六)Spring AOP工作原理初探

时间:2021-08-14 17:24:30

AOP(Aspect-Oriented  Programming,面向切面编程)是Spring提供的关键技术之一。

AOP基于IoC,是对OOP(Object-Oriented Programming,面向对象编程)的有效补充。

利用一种“横切”的技术,剖解封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为Aspect(切面,也称方面)。

AOP的核心思想就是“将应用程序中的业务逻辑与对其提供支持的通用服务功能进行分离,而业务逻辑与通用服务功能之间通过配置信息,实现整合”。

实现AOP的技术主要分为两大类:

一是采用动态代理技术,采用拦截器截取消息的方法,对该消息进行“插装”,以取代原有对象行为的执行;

二是采用静态织入的方式,引入特定的语法创建“切面”,从而使得编译器可以在编译期间织入有关“切面”代码。

Spring AOP是实现AOP的一种技术,是采用“动态代理技术”实现的。

(一)AOP技术相关的概念和术语

1)几个相关概念:

在小编的上篇博文中,在对原来的业务逻辑进行处理加入AOP部分时,类A中所有方法的执行前后,都成为了“所关注的地方”,这个地方称为“横切关注点”。这样原来的业务逻辑被分割开来,所以这个点也就成了联系前后逻辑的连接点,称为“连接点”。然后,对于整个原来的业务逻辑,我们需要告诉程序“在什么时候添加新的附加功能”,这里的“什么时候”的时机称为“通知”。在本例中“通知”有两个:“在类A中所有方法的执行前添加”称为“前置通知”;“类A中所有方法的执行后添加”称为“后置通知”。

例子中前置通知:

<!-- 配置前置通知及前置通知的切入点 -->
<aop:before method="methodX1" pointcut="execution(* com.edu.aop.hello.A.*())"></aop:before>

后置通知:

<!-- 配置后置通知及后置通知的切入点 -->
<aop:after method="methodX2" pointcut="execution(* com.edu.aop.hello.A.*())"></aop:after>

当原来的业务逻辑被“横向关注点”分割后,就可以在“该点”处插入(切入)新需求功能模块,这里将指明插入(切入)新需求功能模块的“地方”(配置文件代码部分)称为“切入点(Pointcut)”,而要插入的功能模块,称为“切面(Aspect)”。可见,配置“切面”就是指出:在什么地方(连接点)切入什么模块(切面)的哪个方法

2)Aspect(切面,也称方面)

是对系统中横切关注点逻辑进行模块化封装的AOP概念实体(就是定义一个类),它可以包含多个Pointcut(切入点)及相关的Advice(通知)定义。例如本例中的类X。

3)JoinPoint(连接点)

系统在运行之前,AOP的功能模块需要织入到OOP的功能模块中。要进行这种织入过程,需要知道在系统的哪些功能点上进行织入操作,这些将要在其上进行织入操作的系统功能点称为JoinPoint。

在Spring AOP中,一个连接点总是表示一个方法的执行。

常见的几种JoinPoint类型:方法调用、方法执行、构造方法调用、构造方法执行、字段设置、字段获取、异常处理执行、类初始化。

4)Pointcut(切入点)

Pointcut是对JoinPoint的形式描述,用于指出要对哪些Joinpoint进行拦截的定义。

(初学可理解为二者相同,只不过Pointcut用在配置文件的通知中;JoinPoint用在切面类中)

Pointcut通常和“一个切入点表达式”相关联,来表示在需要在哪些功能点上织入AOP的功能。

常见的Pointcut方式:

(1)直接指定JoinPoint所在的方法名称;

(2)正则表达式,Spring的AOP支持该种方式;

(3)使用特定的Pointcut表述语言。

5)Advice(通知)

一个Advice对应一个横切关注点逻辑的载体,它代表将会织入到JointPoint的横切逻辑:在切面的某个特定的连接点上执行的逻辑。

一个切面包括一个或者多个通知,每个通知就是告诉“在什么时机”调用执行什么方法。

Spring AOP提供了5种通知:

Before Advice(前置通知)、After Returning Advice(返回通知)、After throwing Advice(异常通知)、After Advice(后置通知)、Around Advice(环绕通知)

6)Target(目标对象)

通知被应用的对象(包含连接点的对象,或者说被通知或被代理的对象),即符合Pointcut所指定的条件,将在织入过程中被织入横切逻辑的对象。

本例中,即是A类的所有方法。

7)AOP Proxy(AOP 代理)

AOP框架创建的对象,用来执行切面(Aspect)的内容。

8)Weave(织入)

将Aspect应用到Target对象并导致Proxy对象创建的过程称为织入。

9)拦截机(Interceptor)

拦截器(也称拦截机)是AOP的另一种叫法。

(二)切入点表达式

通常,切入点表达式用于给出Pointcut对JointPoint的形式描述,指出要对哪些JoinPoint进行拦截。

切入点表达式的格式如下:

execution(方法访问权限 返回类型 方法的包路径.方法名(方法的参数)异常类型)

例如本例中:

execution(* com.edu.aop.hello.A.*())

使用说明:

1)“返回类型”、“方法名”和“方法参数”是必选项,其他各项是可选项;

2)在“切入点表达式”中可以使用通配符。

常用通配符:

“*”代表不包含“.”的字符串,若要包含“.”,必须使用转义符号“\.”;

“..”代表任意数量任意类型的参数。

3)名称模式匹配的是方法名。可以用*通配符表示匹配所有方法名。

4)若在同一包中,可省略包名,直接给出类(接口)名称;

5)切入点表达式可以通过操作符“&&”、“||”、“!”进行合并运算,形成一个新的切入点表达式。

例:

execution(* com.edu.aop.hello.A.*())||execution(* *.add(..))

(三)两种常用的AOP编程方法

1)基于XML配置的AOP编程。上篇博文案例就是此种编程方法,重点就是配置“切面信息”;

2)基于AspectJ注解配置的AOP编程。采用注解方式编程,所有的配置信息都在源代码中标注,非常简单方便。

两种AOP编程方法的设计思想与设计过程基本一致,即创建切面类、配置(注解)切面和配置(注解通知)。

参考书籍:《Java EE框架开发技术与案例教程》