Spring AOP理解与研发使用

Spring AOP理解与研发使用SpringAOP理解与研发使用:基本理论(基本术语总结+具体开发注意事项+切点正则和指示器规则)+AOP开发应用与分析

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

一、前言

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 限定匹配带有指定注解的连接点

基本使用举例如下

联合使用切点指示器

/*匹配任意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() {} 

共享切点定义

/*匹配定义在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() {}

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

/*匹配任意公共方法*/
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.net/158125.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java学习之AWT GUI编程

    Java学习之AWT GUI编程

    2020年11月20日
    168
  • python初级:基础知识学习-变量、数据类型、运算符、选择结构

    python初级:基础知识学习-变量、数据类型、运算符、选择结构

    2021年10月6日
    32
  • mysql锁表原因及如何处理_表被锁了还能查询

    mysql锁表原因及如何处理_表被锁了还能查询1、锁表发生在insert update、delete中  2、锁表的原理是数据库使用独占式封锁机制,当执行上面的语句时,对表进行锁住,直到发生commite或者回滚或者退出数据库用户 3、锁表的原因  第一、A程序执行了对tableA的insert,并还未commite时,B程序也对tableA进行insert则此时会发生资源正忙的异常就是锁表 第二、锁表常…

    2022年8月23日
    3
  • 详解contextConfigLocation

    详解contextConfigLocationspring的应用初始化流程一直没有搞明白,刚刚又碰到了相关的问题。决定得好好看看这个流程。我们在开发spring的项目当中基本上都会在web.xml通过:来初始化各个spring的配置文件,但是我们只是知道这段代码的功能,并不是很清楚我们配置了这段代码之后为什么就能去初始化配置文件。当然我们还会加上:listener>          li

    2022年7月12日
    17
  • 深度学习:有监督学习、无监督学习和半监督学习

    深度学习:有监督学习、无监督学习和半监督学习是否有监督(supervised),就看输入数据是否有标签(label)。输入数据有标签,则为有监督学习,没标签则为无监督学习。文章目录一、监督式学习二、无监督式学习三、半监督式学习一、监督式学习在监督式学习下,输入数据被称为“训练数据”,每组训练数据有一个明确的标识或结果,如对防垃圾邮件系统中“垃圾邮件”“非垃圾邮件”,在建立预测模型的时候,监督式学习建立一个学习过程,将预测结果与“训练…

    2022年5月8日
    112
  • Android startActivityForResult()的用法

    Android startActivityForResult()的用法领导说我基础差,我也没反驳,知识忘记了,用到的时候查一下不久行了吗,自己最近在回顾知识好好的在补充一下,今天礼拜日,趁着空闲事件记录一下简单的知识startActivityForResult()也是经常使用到比如我们做城市选择点击城市,返回点击的城市等等,使用startActivityForResult()方法你需要清楚1startActivityForResult(Inten…

    2022年7月11日
    13

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号