Spring AOP理解与研发使用

2022-09-14 15:27:36 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

一、前言

Spring AOP是一种基于方法的AOP,只能用在方法上,在业务上我们一般使用Spring AOP去约定编程一套业务逻辑织入到相关的业务处理中,并抽取通用逻辑默认加入到相关业务中(前置处理后置业务处理或异常处理等),同时在应用上在想对一些现成业务进行干预处理时都会使用(比方说可以考虑对特定方法进行mock操作等处理)。Spring AOP和我们平时开发中使用的约定编程基本类似,本质都是通过约定对相应的方法通过动态代理技术织入约定流程中。本次一些基本的理念还是直接通过自己看过的一些书籍和博客进行总结了,实际应用上基本是结合自己的开发经验进行了一些基本的应用分享,如果有理解错误的地方请留言指正,谢谢!

二、Spring AOP基本理论知识

(一)基本术语总结

术语

基本概念

连接点(join point)

具体被拦截的对象,往往指的就是特定的方法,也可以指某个包路径下的所有类下的所有方法(进行mock干预经常这样干)或直接就是某个类下面的所有方法

切点(point cut)

切面作用的方法不只是单一的,可以通过正则和指示器的规则去定义,适配连接点

通知(advice)

按照约定的流程方法,根据约定织入流程中。 分类:前置通知、后置通知、环绕通知、事后反悔通知、异常通知

目标对象(target)

即被代理对象,也就是上面连接点(join point)中的指定的类

引入(introduction)

增加现有Bean的功能,引入新的类和方法

织入(weaving)

通过动态代理,为原对象生成代理对象,然后与切点定义匹配的连接点拦截,按约定将各类通知织入约定流程中

切面(aspect)

Spring AOP通过切面信息来增加Bean的功能或将对应方法织入流程,在切面中定义切点、各类 通知和引入内容

(二)具体开发注意事项

有相关疑问的可以留言直接问,以下内容,只是我平时觉得重点的应用注意事项总结:

  1. ProceedingJoinPoint,继承自连接点JoinPoint,实际作用上就是我们指定的具体某个类或某些类,本质上连接点就是什么类的什么方法
  2. 具体切面采用@Aspect注解标注,切面中定义我们想要约定实现的基本内容,以及相关的通知@Before、@After、@AfterReturning、@AfterThrowing、@Around,各通知中需要统一指明切点,一般我们都是直接定义切点@Pointcut,然后直接在各通知中进行引入即可。
  3. @Around是我们业务干预中的重点流程改造,一般主要干预处理的内容都在该通知中实现,处理上务必重点分析处理逻辑,代码上做兜底是必须操作。
  4. @DeclareParents业务处理中针对老逻辑进行干预并增加功能时,可以考虑采用引入方式处理,即通过该注解指明两个主要参数value和defaultImpl,value指明要增强的目标对象,defaultImpl指引入增强功能的类,具体我们后续案例介绍下。
  5. 非环绕通知中对于参数的处理直接使用JoinPoint(当然也可以不用),例如前置打印参数等内容,环绕通知则使用ProceedingJoinPoint,在使用上需要注意。
  6. 如果多个切面作用的类和方法是一样的,则切面的执行顺序是无序的,如果切面之间需要有先后顺序的的话,需要使用@Order注解或实现Ordered接口实现,数字越小优先级越高,实际处理上如果既有前置通知又有后置通知,则可以看到前置从小到大执行,后置从大到小执行,这说明其内部是一个典型的责任链模式(其应用具体见:)。

(三)切点正则和指示器规则

平时开发时对于切点的定义较多,如果已经很明确处理的切点的话则不需要进行复杂正则配置,但是如果是多类多方法时则正则是必须的。一般我们常用的AspectJ的指示器主要如下表:

AspectJ指示器

描述

arg()

限制连接点匹配参数为制定类型的方法

@args()

限制而连接点匹配参数为指定注解标注的只是方法

execution

用于匹配连接点的执行方法

this()

限制连接点匹配AOP代理的Bean,引用为指定类型的类

target

限制连接点匹配被代理对象为指定的类型

@target

限制连接点匹配特定的执行对象,这些对象要符合指定的注解类型

@within()

限制连接点匹配指定的类型

within()

限制连接点匹配指定的包

@annotation

限定匹配带有指定注解的连接点

基本使用举例如下

联合使用切点指示器

代码语言:javascript复制
/*匹配任意public访问修饰符修饰的方法*/
@Pointcut("execution(public * (..))")
private void anyPublicOperation() {} 

/*匹配包名以com.zyf.javabasic.trading开头的任意类的所有方法*/
@Pointcut("within(com.zyf.javabasic.trading..)") 
private void inTrading() {} 

/*匹配以com.zyf.javabasic.trading开头的任意类中任意以public访问修饰符修饰的方法*/
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {} 

共享切点定义

代码语言:javascript复制
/*匹配定义在web层且目标对象在com.zyf.javabasic.web包及其子包中的所有类的任意方法*/
@Pointcut("within(com.zyf.javabasic.web..)")
public void inWebLayer() {}

/*匹配定义在service层且目标对象在com.zyf.javabasic.service包及其子包中所有类中的任意方法*/
@Pointcut("within(com.zyf.javabasic.service..)")
public void inServiceLayer() {}

/*匹配定义在数据访问层且目标对象在com.zyf.javabasic.dao包及其子包中所有类中的任意方法*/
@Pointcut("within(com.zyf.javabasic.dao..)")
public void inDataAccessLayer() {}

/*匹配数据库访问层中目标对象在com.zyf.javabasic.dao..(..)及其子包中的任意方法*/
@Pointcut("execution( com.zyf.javabasic.dao..(..))")
public void dataAccessOperation() {}

切点表达式解读与使用示例

代码语言:javascript复制
/*匹配任意公共方法*/
execution(public * *(..)) 

/*匹配任意方法名以set字符开头的方法*/ 
execution(* set*(..)) 
    
/*匹配com.xyz.service.AccountService类下任意方法*/
execution(* com.xyz.service.AccountService.*(..)) 
    
/*匹配com.zyf.service包及其子包下任意类的所有方法*/     
execution(* com.zyf.service.*.*(..))

/*匹配com.zyf.service包下任意接口的所有方法*/
within(com.zyf.service.*) 

/*匹配com.zyf.service包及其子包下任意类的所有方法*/
within(com.zyf.service..*) 

/*匹配实现AccountService接口的代理的任意方法*/
this(com.zyf.service.AccountService) 

/*匹配实现AccountService接口的目标对象的任意方法*/ 
target(com.zyf.service.AccountService)

/*匹配只带一个参数的方法,且该参数为可序列化参数*/
args(java.io.Serializable) 
 
/*匹配具有Transactional的目标对象任意方法*/
@target(org.springframework.transaction.annotation.Transactional)

/*匹配目标对象声名有Transactional的方法*/  
 @within(org.springframework.transaction.annotation.Transactional)

/*匹配带有个参数的方法,且运行时参数类型绑定有Classified注解*/
@args(com.zyf.security.Classified)
 
/*匹配Spring容器中id或name属性值为tradeService的bean实例的方法*/
bean(tradeService)
 
/*匹配Spring容器中id或name属性值以Service结尾的bean实例的方法*/
bean(*Service)

三、AOP开发应用与分析

(一)方法自动打印出入参举例

(二)mock赋能干预举例

(三)场景业务处理举例

(四)异步业务处理举例

(五)@DeclareParents使用举例

参考文献、书籍和链接

1.杨开振,深入浅出Spring Boot 2.X,中国工信出版社集团/人民邮电出版社,2015.10.

2.Spring AOP详解及其用法(一)_heshengfu1211的博客-CSDN博客_auditable注解

3.Spring AOP 面向切面编程_劳资是学渣丶的博客-CSDN博客

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/158125.html原文链接:https://javaforall.cn

0 人点赞