Spring中的AOP(上)--AspectJ

Spring中的AOP(上)软件环境名称版本号jdk1.8springboot2.1.6.RELEASEspring document5.1.8.RELEASE以下jar包springboot已集成,无需单独引入,只为对照说明版本号名称版本号spring-aop5.1.8.RELEASEaspectjrt1.9.4...
摘要由CSDN通过智能技术生成

Spring中的AOP(上)

软件环境

名称 版本号
jdk 1.8
springboot 2.1.6.RELEASE
spring document 5.1.8.RELEASE

以下jar包springboot已集成,无需单独引入,只为对照说明版本号

名称 版本号
spring-aop 5.1.8.RELEASE
aspectjrt 1.9.4
aspectjtools 1.9.4
aspectjweaver 1.9.4

1. AOP简介

面向切面编程(AOP-Aspect-Oriented Programming)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP-Object-Oriented Programming). OOP中模块化的关键单元是类,而在AOP中, 模块化单元是切面.切面实现了跨越多种类型和对象的关注点(例如事务管理)的模块化.(在AOP中通常被称为"横切"问题.)

Spring的一个关键组件是AOP框架.虽然Spring IOC容器不依赖于AOP,但AOP补充了Spring IOC以提供非常强大的中间件解决方案.并且AOP结合IOC将使我们的程序变的更加简单.


本文讨论基于架构和基于@AspectJ的AOP支持.

具有AspectJ切入点的Spring AOP

Spring通过两种方式实现AOP
1. 基于xml配置 ①
2. @AspectJ ②
使用了AspectJ切入点语言,同时仍可以使用Spring AOP进行编织
AOP在Spring中的应用
  1. 声明式事务管理
  2. 用户自定义切面

1.1.AOP概念

  • Aspect(切面): 多个类的关注点的抽象. (把分布于不同业务但功能相同的代码从业务逻辑中抽离出来, 组成独立的模块,这些模块称为切面. ) 事务管理是横切关注点的一个很好的例子. 在Spring AOP中, 切面是通过使用常规类(基于xml配置)或使用@Aspect的常规类来实现的.

  • Join point(连接点): 程序执行期间的一个点, 例如执行方法或处理异常. 在Spring AOP中, 连接点始终表示方法执行(实际上连接点还可以是字段或者构造器).

  • Advice(建议): 针对特定连接点的采取的操作. 如"Around", “Before"和"After”. 许多AOP框架(包括Spring)将Advice建模为拦截器并在连接点周围维护一系列拦截器.

  • Pointcut(切入点): 要切入的连接点(方法). Advice与Pointcut表达式相关联, 并在切入点匹配的任何连接点处运行(例如, 执行具有特定名称的方法). 切入点表达式匹配的连接点的定义是AOP的核心, Spring默认使用AspectJ切入点表达式语言.

  • Introduction(简介): 代表类声明额外的方法或字段. Spring AOP允许您向任何Advice的对象引入新接口(以及相应的实现). 例如, 您可以使用Introduction使bean实现 IsModified接口, 以简化缓存. (Introduction在AspectJ社区中称作inter-type declaration(类型间声明).)

  • Target Object(目标对象): 由一个或多个切面Advice的对象. 也称为"Advice对象"(包含增强方法的对象). (由于Spring AOP是使用运行时代理实现的, 因此该对象始终是代理对象.)

  • AOP Proxy(AOP代理): 由AOP框架创建的对象, 包括目标对象和为目标对象加上的Advice. (在Spring Framework中, AOP代理是JDK动态代理或CGLIB代理.)

  • Weaving(编织): 连接切面与其他应用程序类型或对象去创建一个Advice对象的过程.这可以在编译时(例如,使用AspectJ编译器), 类加载时或在运行时完成.与其他纯Java AOP框架一样,Spring AOP在运行时执行编织.

Spring AOP包括以下类型的Advice:

  • Before: 在连接点之前运行但无法阻止执行流程进入连接点(除非它抛出异常).

  • AfterReturning: 在连接点正常完成后运行(方法不会抛出异常,正常返回).

  • AfterThrowing: 方法通过抛出异常退出,则执行.

  • After: 无论连接点怎样退出(正常或异常返回),都会执行.

  • Around: 围绕连接点. 这是最有力的Advice. Around可以在方法调用之前和之后执行自定义行为.它还可以选择是继续执行连接点, 还是返回自定义返回值或抛出异常来结束方法.

Spring建议使用可以实现所需行为的最不强大的Advice类型. 例如, 如果只需要使用方法的返回值更新缓存,那么最好实现AfterReturning而不是Around, 尽管Around可以完成同样的事情. 使用最具体的Advice类型可以提供更简单的编程模型, 减少错误的可能性.

由切入点匹配的连接点的概念是AOP的关键,它将其与仅提供拦截的旧技术区分开来.

这些术语不是特定于Spring的. AOP术语不是特别直观.

SpringAOP的目的不是提供最完整的AOP实现, 而是利用AOP实现和Spring IOC之间的紧密集成, 以帮助解决企业应用程序中的常见问题. 如果需要处理非常细粒度的对象(连接点不止方法还包括字段和构造器), 在这种情况下, AspectJ是最佳选择.

1.2 AOP代理

Spring AOP默认使用AOP代理的标准JDK动态代理. ③
Spring AOP也可以使用CGLIB代理. 这是代理类而不是接口所必需的. 默认情况下, 如果业务对象未实现接口, 则使用CGLIB.

1.3 @AspectJ支持

Spring使用AspectJ提供的库; 使用与AspectJ 5相同的注释, 用于切入点解析和匹配. 但是, AOP运行时仍然是纯Spring AOP, 并且不依赖于AspectJ编译器或weaver.

1.3.1 启用@AspectJ支持

如果Spring确定bean被一个或多个切面Advice, 它会自动为该bean生成一个代理来拦截方法调用, 并确保根据需要执行Advice.

  • 使用Java配置启用@AspectJ支持
    @Configuration
    @EnableAspectJAutoProxy
    public class AppConfig {
   
    }
  • 使用XML配置启用@AspectJ支持
    <aop:aspectj-autoproxy/>
1.3.2 声明切面
  • 使用注释
package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
@Component // 还可以使用XML配置Bean的方式 ④
public class NotVeryUsefulAspect {
   
}
Tips: 在Spring AOP中, 切面本身不能成为其他切面Advice的目标. 
@Aspect类上的注释将其标记为切面, 因此将其从自动代理中排除.
1.3.3 声明切入点

切入点声明由两部分组成:一个是包含名称和任何参数的签名,另一个是切入点表达式.

// 切入点表达式使用的是AspectJ 5的切入点表达式
@Pointcut("execution(* transfer(..))")
private void anyOldTransfer() {
   } // 签名

切入点指示符根据搜索空间可以分为三组

  • kinded 特定类型指示符 execution, get, set, call, handler
  • scoping 范围界定指示符 within, withincode
  • contextual 基于上下文语境指示符 this, target, @annotation

编写正确的切入点至少应包括前两种类型(kinded和scoping).范围界定指示符的匹配非常快,使用它们意味着AspectJ可以非常迅速地排除不应进一步处理的连接点组.一个好的切入点应尽可能包括一个.

AspectJ切入点指示符未在Spring中提供支持的有:call,get,set,preinitialization, staticinitialization,initialization,handler,adviceexecution,withincode,cflow,cflowbelow,if,@this,和@withincode.
在Spring AOP的切入点表达式中使用这些切入点指示符会导致IllegalArgumentException异常.
Spring AOP可能会在将来的版本中扩展,以支持更多的AspectJ切入点指示符.
在编译期间, AspectJ处理切入点以优化匹配性能. 检查代码并确定每个连接点是否(静态地或动态地)匹配给定切入点, 这是一个【【代价高昂】】的过程.
(动态匹配意味着无法通过静态分析完全确定匹配,并且在代码中放置测试以确定代码运行时是否存在实际匹配).
为了获得最佳匹配性能, 要尽可能缩小匹配的搜索空间. scoping指示符非常快速匹配,使用它们意味着AspectJ可以非常快速地解除不应进一步处理的连接点组.
如果可能,一个好的切入点应该总是包含一个.
支持的切入点指示符

Spring AOP支持以下在切入点表达式中使用的AspectJ切入点指示符(PCD):

execution:用于匹配方法执行的连接点.这是使用Spring AOP时要使用的主要切入点指示符.

within:将匹配限制为某些类型内的连接点(使用Spring AOP时,在匹配类型内声明的方法的执行).

this:限制匹配到连接点(使用Spring AOP时方法的执行)的匹配,其中bean引用(Spring AOP代理)是给定类型的实例.

target:在目标对象(代理的应用程序对象)是给定类型的实例的情况下,将匹配限制为连接点(使用Spring AOP时方法的执行).

args:在参数是给定类型的实例的情况下,将匹配限制为连接点(使用Spring AOP时方法的执行).

@target:在执行对象的类具有给定类型的注释的情况下,将匹配限制为连接点(使用Spring AOP时方法的执行).

@args:限制匹配的连接点(使用Spring AOP时方法的执行),其中传递的实际参数的运行时类型具有给定类型的注释.

@within:将匹配限制为具有给定注释的类型内的连接点(使用Spring AOP时,使用给定注释的类型中声明的方法的执行).

@annotation:将匹配限制在连接点的主题(Spring AOP中正在执行的方法)具有给定注释的连接点上.

Spring AOP还支持附加的切入点指示符(PCD) bean.

使用PCD,可以将连接点的匹配限制为特定的命名Spring Bean或一组命名Spring Bean(使用通配符时).该beanPCD具有下列形式:

bean(idOrNameOfBean)

该切入点指示符(PCD)bean只在Spring AOP中支持.它是AspectJ定义的标准PCD的特定于Spring的扩展,因此不适用于@Aspect模型中声明的切面.

组合切入点表达式
@Pointcut("execution(public * (..))")
private void anyPublicOperation() {
   } 

@Pointcut("within(com.xyz.someapp.trading..)")
private void inTrading() {
   } 

@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {
   }

anyPublicOperation 如果方法执行连接点表示任何公共方法的执行,则匹配.

inTrading 如果交易模块中有方法执行,则匹配.

tradingOperation 如果方法执行代表交易模块中的任何公共方法,则匹配.

最佳实践是从较小的命名组件中构建更复杂的切入点表达式

例子

常用PCD(切入点指示符) execution 格式如下:

execution(权限修饰符? 方法返回类型 类的reference路径?方法名(参数) 
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值