学习Spring Boot:(二十二)使用 AOP
前言
AOP 1,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。基于AOP实现的功能不会破坏原来程序逻辑,因此它可以很好的对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
正文
Spring Boot 中使用
- 在
pom.xml中加入 aop 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 当我们需要在非接口上面进行切面操作的时候,就需要
CGLIB来实现 AOP,在系统配置文件中加入设置:
spring:
aop:
proxy-target-class: true
默认为 false。
切点表达式
列出常用的几个表达式:
1. execution() 满足execution中描述的方法签名。 execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
* modifier-pattern:表示方法的修饰符;
* ret-type-pattern:表示方法的返回值
* declaring-type-pattern:表示方法所在的类的路径
* name-pattern:表示方法名
* param-pattern:表示方法的参数
* throws-pattern:表示方法抛出的异常
* 其中后面跟着?的是可选项。
this()是用来限定方法所属的类,为接口则限定所有的实现类,为类的话,限定这单个类。@annotation表示具有某个标注的方法。args表示方法的参数属于一个特定的类,@args表示参数有特定的标注注解。within包或者类型满足within中描述的包或者类型的类的所有非私有方法,@within类型拥有@target描述中给出的annotation,其中@target和@within的区别在于@within要求的annotation的级别为CLASS,而@target为RUNTIME
.target业务实例对象(非代理实例)的类型满足target 中的描述的类型,@target 类型拥有@target描述中给出的annotationbean()表示所有匹配的 bean,例如 ,bean(“*Service”),匹配所有Service结尾的类。可以使用!bean()表示不匹配。
注意事项:
* 在各个pattern中,可以使用”*”来表示匹配所有。
* 在param-pattern中,可以指定具体的参数类型,多个参数间用,隔开,各个也可以用 * 来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(*,String)表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型。
* 可以用(..)表示零个或多个任意的方法参数。
* 使用&&符号表示与关系,使用||表示或关系、使用!表示非关系。在XML文件中使用and、or和not这三个符号。
AspectJ提供了五种定义通知的标注:
@Before:前置通知,在调用目标方法之前执行通知定义的任务@After:后置通知,在目标方法执行结束后,无论执行结果如何都执行通知定义的任务@AfterReturning:后置通知,在目标方法执行结束后,如果执行成功,则执行通知定义的任务@AfterThrowing:异常通知,如果目标方法执行过程中抛出异常,则执行通知定义的任务@Around:环绕通知,在目标方法执行前和执行后,都需要执行通知定义的任务
通过标注定义通知只需要两个步骤:
1. 将以上五种标注之一添加到切面的方法中
2. 在标注中设置切点的定义。
创建环绕通知
环绕通知相比其它四种通知有其特殊之处。环绕通知本质上是将前置通知、后置通知和异常通知整合成一个单独的通知。
用@Around标注的方法,该方法必须有一个ProceedingJoinPoint类型的参数,
在方法体中,需要通过这个参数,以joinPoint.proceed();的形式调用目标方法。注意在环绕通知中必须进行该调用,否则目标方法本身的执行就会被跳过。
计算方法的执行时间:
@Around("logPointCut()") //切点
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
//执行方法
Object result = point.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
return result;
}
处理通知中参数
获取参数的方式则需要使用关键词是args。
@Pointcut("bean(sysUserServiceImpl) && args(userEntity,..)")
public void userPointCut(SysUserEntity userEntity) {
}
@Before("userPointCut(userEntity)")
public void validateUser(SysUserEntity userEntity) {
// to handler args
}
这里有个非常严格的一点就是,args(userEntity,..),表示目标方法,可能有多个参数,但是包括 userEntity,这里 userEntity 必须参数名相同,不同就编织了。
args()中参数的名称必须跟切点方法的签名中public void validateUser(SysUserEntity userEntity)的参数名称相同。如果使用切点函数定义,其中的参数名称也必须与通知方法签名中的参数完全相同
AfterReturning增强处理
@AfterReturning(pointcut = "logPointCut()", returning = "rtv")
public void logAfter(Object rtv) {
System.out.println(Objects.toString(rtv));
}
使用 @AfterReturning 注解时,指定了一个returning属性,假设该属性值为rvt,这表明允许在Advice方法(logAfter()方法)中定义名为rvt的形参,程序可通过rvt形参来访问目标方法的返回值。
注意:
虽然AfterReturning增强处理可以访问到方法的返回值,但它不可以改变目标方法的返回值。
AOP切面的优先级
有时候,我们对一个方法会有多个切面的问题,这个时候还会涉及到切面的执行顺序的问题。
我们可以定义每个切面的优先级, Spring 中提供注解 @Order(i) ,当 i 的值越小,优先级越高。
参考文章
- Aspect Oriented Programming的缩写 ↩
学习Spring Boot:(二十二)使用 AOP的更多相关文章
- 学习Spring Boot:(二十五)使用 Redis 实现数据缓存
前言 由于 Ehcache 存在于单个 java 程序的进程中,无法满足多个程序分布式的情况,需要将多个服务器的缓存集中起来进行管理,需要一个缓存的寄存器,这里使用的是 Redis. 正文 当应用程序 ...
- spring boot / cloud (十二) 异常统一处理进阶
spring boot / cloud (十二) 异常统一处理进阶 前言 在spring boot / cloud (二) 规范响应格式以及统一异常处理这篇博客中已经提到了使用@ExceptionHa ...
- 学习Spring Boot:(二十六)使用 RabbitMQ 消息队列
前言 前面学习了 RabbitMQ 基础,现在主要记录下学习 Spring Boot 整合 RabbitMQ ,调用它的 API ,以及中间使用的相关功能的记录. 相关的可以去我的博客/RabbitM ...
- 学习 Spring Boot:(二十九)Spring Boot Junit 单元测试
前言 JUnit 是一个回归测试框架,被开发者用于实施对应用程序的单元测试,加快程序编制速度,同时提高编码的质量. JUnit 测试框架具有以下重要特性: 测试工具 测试套件 测试运行器 测试分类 了 ...
- 学习Spring Boot:(二十四)多数据源配置与使用
前言 随着业务量增大,可能有些业务不是放在同一个数据库中,所以系统有需求使用多个数据库完成业务需求,我们需要配置多个数据源,从而进行操作不同数据库中数据. 正文 JdbcTemplate 多数据源 配 ...
- 学习Spring Boot:(二十)使用 MongoDB
前言 MongoDB 1 是可以应用于各种规模的企业.各个行业以及各类应用程序的开源数据库.基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案.Mongo ...
- Spring Boot(十二)单元测试JUnit
一.介绍 JUnit是一款优秀的开源Java单元测试框架,也是目前使用率最高最流行的测试框架,开发工具Eclipse和IDEA对JUnit都有很好的支持,JUnit主要用于白盒测试和回归测试. 白盒测 ...
- 学习Spring Boot:(二十三)Spring Boot 中使用 Docker
前言 简单的学习下怎么在 Spring Boot 中使用 Docker 进行构建,发布一个镜像,现在我们通过远程的 docker api 构建镜像,运行容器,发布镜像等操作. 这里只介绍两种方式: 远 ...
- 学习Spring Boot:(二)启动原理
前言 主要了解前面的程序入口 @@SpringBootApplication 这个注解的结构. 正文 参考<SpringBoot揭秘 快速构建微服务体系>第三章的学习,总结下. Sprin ...
随机推荐
- C# SignalR 即时通信
MSDN教程:https://docs.microsoft.com/en-us/aspnet/signalr/ 个人博客:http://www.cnblogs.com/zhili/p/SignalRQ ...
- 浅谈MySQL引擎(纯个人理解,如有错误请指正)
MySQL有很多引擎,MyISAM.InnoDB.MERGE.MEMORY(HEAP).BDB(BerkeleyDB).EXAMPLE.FEDERATED...等等 比较常用的就是InnoDB和MyI ...
- SQLAlchemy模块的使用教程
数据库表是一个二维表,包含多行多列.把一个表的内容用Python的数据结构表示出来的话,可以用一个list表示多行,list的每一个元素是tuple,表示一行记录,比如,包含id和name的user表 ...
- R绘图 第十二篇:散点图(高级)
散点图用于描述两个连续性变量间的关系,三个变量之间的关系可以通过3D图形或气泡来展示,多个变量之间的两两关系可以通过散点图矩阵来展示. 一,添加了最佳拟合曲线的散点图 使用基础函数plot(x,y)来 ...
- 【JVM.2】垃圾收集器与内存分配策略
垃圾收集器需要完成的3件事情: 哪些内存需要回收? 什么时候回收? 如何回收? 在前一节中介绍了java内存运行时区域的各个部分,其中程序计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭:栈 ...
- js中的栈、堆、队列、内存空间
栈(stack) .堆(heap). 队列(queue)是js的三种数据结构. 栈(stack) 栈的特点是"LIFO,即后进先出(Last in, first out)".数据存 ...
- [UWP 自定义控件]了解模板化控件(2.1):理解ContentControl
UWP的UI主要由布局容器和内容控件(ContentControl)组成.布局容器是指Grid.StackPanel等继承自Panel,可以拥有多个子元素的类.与此相对,ContentControl则 ...
- 支持自定义协议的虚拟仪器【winform版】
首先,这个程序的由来,额,工作以来,做的最久的就是上位机,对市面上的大部分组态软件都感到不满,不好用,LabView虽然用起来不错,但是入门还是不够简单,刚好现在工作比较闲(已经不再做上位机了),所以 ...
- C#_Attribute特性
[AttributeUsage(AttributeTargets.All)]//指定Attribute的使用范围,比如只能在class级别使用 public class Column : Attrib ...
- nginx下目录浏览及其验证功能、版本隐藏等配置记录
工作中常常有写不能有网页下载东西的需求,在Apache下搭建完成后直接导入文件即可达到下载/显示文件的效果;而Nginx的目录列表功能默认是关闭的,如果需要打开Nginx的目录列表功能,需要手动配置, ...