Spring AOP:原理、 通知、连接点、切点、切面、表达式

简介: Spring AOP:原理、 通知、连接点、切点、切面、表达式

0:Spring AOP 原理

简单说说 AOP 的设计:

  1. 每个 Bean 都会被 JDK 或者 Cglib 代理。取决于是否有接口。
  2. 每个 Bean 会有多个“方法拦截器”。注意:拦截器分为两层,外层由 Spring 内核控制流程,内层拦截器是用户设置,也就是 AOP。
  3. 当代理方法被调用时,先经过外层拦截器,外层拦截器根据方法的各种信息判断该方法应该执行哪些“内层拦截器”。内层拦截器的设计就是职责连的设计。

可以将 AOP 分成 2 个部分:

第一:代理的创建;

第二:代理的调用。


开始分析(扯):

  1. 代理的创建(按步骤):
  • 首先,需要创建代理工厂,代理工厂需要 3 个重要的信息:拦截器数组,目标对象接口数组,目标对象。
  • 创建代理工厂时,默认会在拦截器数组尾部再增加一个默认拦截器 —— 用于最终的调用目标方法。
  • 当调用 getProxy 方法的时候,会根据接口数量大余 0 条件返回一个代理对象(JDK or  Cglib)。
  • 注意:创建代理对象时,同时会创建一个外层拦截器,这个拦截器就是 Spring 内核的拦截器。用于控制整个 AOP 的流程。
  1. 代理的调用
  • 当对代理对象进行调用时,就会触发外层拦截器。
  • 外层拦截器根据代理配置信息,创建内层拦截器链。创建的过程中,会根据表达式判断当前拦截是否匹配这个拦截器。而这个拦截器链设计模式就是职责链模式。
  • 当整个链条执行到最后时,就会触发创建代理时那个尾部的默认拦截器,从而调用目标方法。最后返回。

Spring对AOP的支持

Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:

1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了

2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB

AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:

1、定义普通业务组件

2、定义切入点,一个切入点可能横切多个业务组件

3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作

所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。


1:知识背景

软件系统可以看成是由一组关注点组成的,其中,直接的业务关注点,是直切关注点。而为直切关注点提供服务的,就是横切关注点。


2:面向切面的基本原理

什么是面向切面编程

横切关注点:影响应用多处的功能(安全、事务、日志)

切面:

横切关注点被模块化为特殊的类,这些类称为切面

优点:

每个关注点现在都集中于一处,而不是分散到多处代码中

服务模块更简洁,服务模块只需关注核心代码。

AOP 术语

  • 通知:
  • 定义:切面也需要完成工作。在 AOP 术语中,切面的工作被称为通知。
  • 工作内容:通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决何时执行这个工作。
  • Spring 切面可应用的 5 种通知类型:
  1. Before——在方法调用之前调用通知
  2. After——在方法完成之后调用通知,无论方法执行成功与否
  3. After-returning——在方法执行成功之后调用通知
  4. After-throwing——在方法抛出异常后进行通知
  5. Around——通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
  • 连接点:
  • 定义:连接点是一个应用执行过程中能够插入一个切面的点。
  • 连接点可以是调用方法时、抛出异常时、甚至修改字段时、
  • 切面代码可以利用这些点插入到应用的正规流程中
  • 程序执行过程中能够应用通知的所有点。
  • 切点:
  • 定义:如果通知定义了“什么”和“何时”。那么切点就定义了“何处”。切点会匹配通知所要织入的一个或者多个连接点。
  • 通常使用明确的类或者方法来指定这些切点。
  • 作用:定义通知被应用的位置(在哪些连接点)
  • 切面:
  • 定义:切面是通知和切点的集合,通知和切点共同定义了切面的全部功能——它是什么,在何时何处完成其功能。
  • 引入:
  • 引入允许我们向现有的类中添加方法或属性
  • 织入:
  • 织入是将切面应用到目标对象来创建的代理对象过程。
  • 切面在指定的连接点被织入到目标对象中,在目标对象的生命周期中有多个点可以织入
  1. 编译期——切面在目标类编译时期被织入,这种方式需要特殊编译器。AspectJ的织入编译器就是以这种方式织入切面。
  2. 类加载期——切面在类加载到
  3. JVM ,这种方式需要特殊的类加载器,他可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5 的 LTW 就支持这种织入方式
  4. 运行期——切面在应用运行期间的某个时刻被织入。一般情况下,在织入切面时候,AOP 容器会为目标对象动态的创建代理对象。Spring AOP 就是以这种方式织入切面。


3:Spring 对 AOP 的支持

  • 并不是所有的 AOP 框架都是一样的,他们在连接点模型上可能有强弱之分。
  • 有些允许对字段修饰符级别应用通知
  • 有些支持方法调用连接点
  • Spring 提供的 4 种各具特色的 AOP 支持
  1. 基于代理的经典 AOP;
  2. @AspectJ 注解驱动的切面;
  3. 纯 POJO 切面;
  4. 注入式 AspectJ 切面; Spring
  • 在运行期间通知对象
  • 通过在代理类中织入包裹切面,Spring 在运行期间将切面织入到 Spring 管理的 Bean 中。
    代理类封装了目标类,并拦截被通知的方法调用,再将调用转发给真正的目标 Bean


图片.png



当拦截到方法调用时,在调用目标 Bean 方法之前,代理会执行切面逻辑。
当真正应用需要被代理的 Bean 时,Spring 才创建代理对象。如果使用 ApplicationContext,在 ApplicationContext 从 BeanFactory 中加载所有 Bean 时,Spring 创建代理对象,因为 Spring 在运行时候创建代理对象,所以我们不需要特殊的编译器来织入 Spring AOP 的切面。

  • Spring 支持方法创建连接点
  • 因为 Spring 基于动态代理,所以 Spring 只支持方法连接点。
  • Spring 缺失对字段连接点的支持,无法让我们更加细粒度的通知,例如拦截对象字段的修改
  • Spring 缺失对构造器连接点支持,我发在 Bean 创建时候进行通知。


4:使用切点选择连接点

  • 切点用于准确定位,确定在什么地方应用切面通知。
  • Spring 定义切点
  • 在 Spring AOP 中,需要使用 AspectJ 的切点表达式来定义切点。
AspectJ 指示器 描述
arg () 限制连接点的指定参数为指定类型的执行方法
@args () 限制连接点匹配参数由指定注解标注的执行方法
execution () 用于匹配连接点的执行方法
this () 限制连接点匹配 AOP 代理的 Bean 引用为指定类型的类
target () 限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型注解
within() 限制连接点匹配指定类型
@within() 限制连接点匹配指定注释所标注的类型(当使用 Spring AOP 时,方法定义在由指定的注解所标注的类里)
@annotation 限制匹配带有指定注释的连接点

1. 创建自己的切点

图片.png

 

- execution( ) 指示器选择 Instrument 的 play( ) 方法。

方法表达式是以 * 号开头,标识了我们不关心的方法返回值的类型。

* 后我们指定了权限定类名和方法名。

对于方法的参数列表,使用(..)标识切点选择任意的 play( ) 方法,无论入参是什么。

- 假设我们需要匹配切点仅匹配 com.Springinaction.springidol 包。可以使用 within()

图片.png

 

注意 && 是将 execution( ) 和 within( ) 连接起来,形成的 and 关系。同理也可以使用 || 或关系、!非关系

- 创建 Spring 的 bean( ) 指示器

Spring 2.5 引入一个新的 bean( ) 指示器,该指示器允许我们在切点表达式中使用 Bean ID 来标识 Bean

bean( ) 使用 Bean ID 或 Bean 名称作为参数来限制切点只匹配特定 Bean。

如下,我们希望执行 Instrument 的 play( ) 方法时候应用通知,但限定 Bean 的 ID 为 eddie

图片.png

 

还可以使用非操作作为除了指定 ID 的 Bean 以外的其他 Bean应用通知

图片.png

 

在此场景下,切面会通知被编织到所有 ID 不为 eddie 的 Bean 中


5:在 XML 中声明切面

Spring 的 AOP 配置元素简化了基于 POJO 切面声明

 

 

AOP 配置元素

描述
aop : advisor 定义 AOP 通知器
aop : after 定义 AOP 后置通知(不管被通知方法是否执行成功)
aop : after-returing 定义 AOP after-returing 通知
aop : after-throwing 定义 AOP after-throwing 通知
aop : around 定义 AOP 环绕通知
aop : aspect 定义切面
aop : aspectj-autoproxy 启动 @AspectJ 注解驱动的切面
aop : before 定义 AOP 前置通知
aop : config 顶层的 AOP 配置元素,大多数 aop : * 元素必须包含在 元素内
aop : declare-parents 为被通知的对象引入额外接口,并透明的实现
aop : pointcut 定义切点

参考来源:http://blog.csdn.net/github_34889651/article/details/51321499

 


相关文章
|
10月前
|
缓存 Java 开发者
【Spring】原理:Bean的作用域与生命周期
本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。
1091 22
|
10月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
2971 0
|
9月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
9月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
771 2
|
11月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
1221 1
|
12月前
|
缓存 安全 Java
Spring 框架核心原理与实践解析
本文详解 Spring 框架核心知识,包括 IOC(容器管理对象)与 DI(容器注入依赖),以及通过注解(如 @Service、@Autowired)声明 Bean 和注入依赖的方式。阐述了 Bean 的线程安全(默认单例可能有安全问题,需业务避免共享状态或设为 prototype)、作用域(@Scope 注解,常用 singleton、prototype 等)及完整生命周期(实例化、依赖注入、初始化、销毁等步骤)。 解析了循环依赖的解决机制(三级缓存)、AOP 的概念(公共逻辑抽为切面)、底层动态代理(JDK 与 Cglib 的区别)及项目应用(如日志记录)。介绍了事务的实现(基于 AOP
454 0
|
前端开发 Java 数据库连接
Spring核心原理剖析与解说
每个部分都是将一种巨大并且复杂的技术理念传达为更易于使用的接口,而这就是Spring的价值所在,它能让你专注于开发你的应用,而不必从头开始设计每一部分。
352 32
|
12月前
|
监控 架构师 NoSQL
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
|
Java 开发者 Spring
Spring框架 - 深度揭秘Spring框架的基础架构与工作原理
所以,当你进入这个Spring的世界,看似一片混乱,但细看之下,你会发现这里有个牢固的结构支撑,一切皆有可能。不论你要建设的是一座宏大的城堡,还是个小巧的花园,只要你的工具箱里有Spring,你就能轻松搞定。
526 9
|
安全 前端开发 Java
Spring Boot 项目中触发 Circular View Path 错误的原理与解决方案
在Spring Boot开发中,**Circular View Path**错误常因视图解析与Controller路径重名引发。当视图名称(如`login`)与请求路径相同,Spring MVC无法区分,导致无限循环调用。解决方法包括:1) 明确指定视图路径,避免重名;2) 将视图文件移至子目录;3) 确保Spring Security配置与Controller路径一致。通过合理设定视图和路径,可有效避免该问题,确保系统稳定运行。
905 0