一、Spring AOP 注解概述

1.Spring 的 AOP 功能除了在配置文件中配置一大堆的配置,比如切入点、表达式、通知等等以外,
使用注解的方式更为方便快捷,特别是 Spring boot 出现以后,基本不再使用原先的 beans.xml 等配置文件了,而都推荐注解编程

@Aspect 切面声明,标注在类、接口(包括注解类型)或枚举上。
@Pointcut

切入点声明,即切入到哪些目标类的目标方法。既可以用 execution 切点表达式, 也可以是 annotation 指定拦截拥有指定注解的方法.

value 属性指定切入点表达式,默认为 "",用于被通知注解引用,这样通知注解只需要关联此切入点声明即可,无需再重复写切入点表达式

@Before

前置通知, 在目标方法(切入点)执行之前执行。

value 属性绑定通知的切入点表达式,可以关联切入点声明,也可以直接设置切入点表达式

注意:如果在此回调方法中抛出异常,则目标方法不会再执行,会继续执行后置通知 -> 异常通知。

@After 后置通知, 在目标方法(切入点)执行之后执行
@AfterReturning

返回通知, 在目标方法(切入点)返回结果之后执行.

pointcut 属性绑定通知的切入点表达式,优先级高于 value,默认为 ""

@AfterThrowing

异常通知, 在方法抛出异常之后执行, 意味着跳过返回通知

pointcut 属性绑定通知的切入点表达式,优先级高于 value,默认为 ""

注意:如果目标方法自己 try-catch 了异常,而没有继续往外抛,则不会进入此回调函数

@Around

环绕通知:目标方法执行前后分别执行一些代码,类似拦截器,可以控制目标方法是否继续执行。

通常用于统计方法耗时,参数校验等等操作。

2、上面这些 AOP 注解都是位于 aspectjweaver依赖中;对于习惯了 Spring 全家桶编程的人来说,并不是需要直接引入 aspectjweaver 依赖,因为 spring-boot-starter-aop 组件默认已经引用了 aspectjweaver 来实现 AOP 功能。换句话说 Spring 的 AOP 功能就是依赖的 aspectjweaver !

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>

3.AOP 底层是通过 Spring 提供的的动态代理技术实现的,在运行期间动态生成代理对象,代理对象方法执行时进行增强功能的介入,再去调用目标对象的方法,从而完成功能的增强。主要使用 JDK 动态代理与 Cglib 动态代理;所以如果目标类不是 Spring 组件,则无法拦截,如果是 类名.方法名 方式调用,也无法拦截。

二、@Aspect 快速入门

1、@Aspect 常见用于记录日志、异常集中处理、权限验证、Web 参数校验、事务处理等等

2、要想把一个类变成切面类,只需3步:

  1)在类上使用 @Aspect 注解使之成为切面类

  2)切面类需要交由 Sprign 容器管理,所以类上还需要有 @Service、
@Repository、@Controller、@Component 等注解
  2)在切面类中自定义方法接收通知 3、AOP 的含义就不再累述了,下面直接上示例:
/**
* 切面类,用于处理日志、参数校验等
*
* @author songwp
* @date 2020-04-27
*/
@Aspect
@Component
@Slf4j
public class HandleAspect { /**
* @Pointcut :切入点声明,即切入到哪些目标方法。value 属性指定切入点表达式,默认为 ""。
* 用于被下面的通知注解引用,这样通知注解只需要关联此切入点声明即可,无需再重复写切入点表达式
* <p>
* 切入点表达式常用格式举例如下:
* - * com.songwp.aspect.EmpService.*(..)):表示 com.songwp.aspect.EmpService 类中的任意方法
* - * com.songwp.aspect.*.*(..)):表示 com.songwp.aspect 包(不含子包)下任意类中的任意方法
* - * com.songwp.aspect..*.*(..)):表示 com.songwp.aspect 包及其子包下任意类中的任意方法
* </p>
* value 的 execution 可以有多个,使用 || 隔开.
*/
@Pointcut("execution(public * com.songwp.controller.*.*(..))")
public void aopPointCut() {} /**
* 前置通知:目标方法执行之前执行以下方法体的内容。
* value:绑定通知的切入点表达式。可以关联切入点声明,也可以直接设置切入点表达式
* <br/>
* * @param joinPoint:提供对连接点处可用状态和有关它的静态信息的反射访问<br/> <p>
* * * Object[] getArgs():返回此连接点处(目标方法)的参数,目标方法无参数时,返回空数组
* * * Signature getSignature():返回连接点处的签名。
* * * Object getTarget():返回目标对象
* * * Object getThis():返回当前正在执行的对象
* * * StaticPart getStaticPart():返回一个封装此连接点的静态部分的对象。
* * * SourceLocation getSourceLocation():返回与连接点对应的源位置
* * * String toLongString():返回连接点的扩展字符串表示形式。
* * * String toShortString():返回连接点的缩写字符串表示形式。
* * * String getKind():返回表示连接点类型的字符串
* * * </p>
*/
@Before("aopPointCut()")
public void beforeAdvice() {
System.out.println("前置通知执行");
} /**
* 后置通知:目标方法执行之后执行以下方法体的内容,不管目标方法是否发生异常。
* value:绑定通知的切入点表达式。可以关联切入点声明,也可以直接设置切入点表达式
*/
@After("aopPointCut()")
public void afterAdvice() {
System.out.println("后置通知执行");
} /**
* 返回通知:目标方法返回后执行以下代码
* value 属性:绑定通知的切入点表达式。可以关联切入点声明,也可以直接设置切入点表达式
* pointcut 属性:绑定通知的切入点表达式,优先级高于 value,默认为 ""
* returning 属性:通知签名中要将返回值绑定到的参数的名称,默认为 ""
*
* @param joinPoint :提供对连接点处可用状态和有关它的静态信息的反射访问
*/
@AfterReturning("execution(* com.songwp.service.impl.OperateLogServiceImpl.*(..))")
public void logAfterReturning(JoinPoint joinPoint) {
System.out.println("返回后通知: " + joinPoint.getSignature().getName());
} /**
* 异常通知:目标方法发生异常的时候执行以下代码,此时返回通知不会再触发
* value 属性:绑定通知的切入点表达式。可以关联切入点声明,也可以直接设置切入点表达式
* pointcut 属性:绑定通知的切入点表达式,优先级高于 value,默认为 ""
* throwing 属性:与方法中的异常参数名称一致,
*
* @param ex:捕获的异常对象,名称与 throwing 属性值一致
*/
@AfterThrowing(pointcut = "execution(* com.songwp.service.impl.OperateLogServiceImpl.*(..))", throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
System.out.println("异常后通知: " + joinPoint.getSignature().getName() + ", Exception: " + ex);
} /**
* 环绕通知
* 1、@Around 的 value 属性:绑定通知的切入点表达式。可以关联切入点声明,也可以直接设置切入点表达式
* 2、Object ProceedingJoinPoint.proceed(Object[] args) 方法:继续下一个通知或目标方法调用,返回处理结果,如果目标方法发生异常,则 proceed 会抛异常.
* 3、假如目标方法是控制层接口,则本方法的异常捕获与否都不会影响目标方法的事务回滚
* 4、假如目标方法是控制层接口,本方法 try-catch 了异常后没有继续往外抛,则全局异常处理 @RestControllerAdvice 中不会再触发
*
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("execution(* com.songwp.service.impl.OperateLogServiceImpl.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
this.checkRequestParam(joinPoint);
System.out.println("环绕通知: " + joinPoint.getSignature().getName());
// 继续执行方法
Object result = joinPoint.proceed();
System.out.println("环绕通知: " + joinPoint.getSignature().getName());
return result;
} /**
* 参数校验,防止 SQL 注入
*
* @param joinPoint
*/
private void checkRequestParam(ProceedingJoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
if (args == null || args.length <= 0) {
return;
}
String params = Arrays.toString(joinPoint.getArgs()).toUpperCase();
String[] keywords = {"DELETE ", "UPDATE ", "SELECT ", "INSERT ", "SET ", "SUBSTR(", "COUNT(", "DROP ",
"TRUNCATE ", "INTO ", "DECLARE ", "EXEC ", "EXECUTE ", " AND ", " OR ", "--"};
for (String keyword : keywords) {
if (params.contains(keyword)) {
log.error("参数存在SQL注入风险,其中包含非法字符 {}.", keyword);
throw new RuntimeException("参数存在SQL注入风险:params=" + params);
}
}
}
}

三、@Aspect 切面不生效原因

确保切面类被Spring管理‌:在切面类上添加 @Service、@Repository、@Controller、@Component  等注解
检查路径设置‌:确保切面类被 @ComponentScan 注解扫描到。即有没有被Spring容器管理。可以使用 @PostConstruct注解测试。
检查切面表达式‌:确保切面表达式正确无误,能够匹配到目标方法。

特别注意: 比如定义了一个 AOP 切面(@Pointcut)拦截 ServiceA 中的方法 B,当从其他类调用方法 B 时(比如 Controller 层),会正常切入拦截,而从本类其他方法中调用方法 B 时,无法切入拦截,因为此时默认并不是通过代理对象调用的,而是直接通过 this 对象来调的。可以参考@EnableAspectJAutoProxy注解。

总结:AOP的高级特性使得开发者能够以声明式的方式处理复杂的应用场景。通过灵活使用切入点表达式和正则表达式,可以在Spring AOP中实现精确的连接点匹配。此外,AOP在性能监控、日志记录、事务管理等场景中的应用,展示了其在提高代码模块化和可维护性方面的强大能力。

Spring基于注解实现 AOP 切面功能的更多相关文章

  1. 阶段3 2.Spring_08.面向切面编程 AOP_9 spring基于注解的AOP配置

    复制依赖和改jar包方式 src下的都复制过来. 复制到新项目里了 bean.xml里面复制上面一行代码到下面.把aop改成context. 配置spring容器创建时要扫描的包 Service的配置 ...

  2. Spring 基于注解的AOP实现

    在本文开始之前,我要引入一张图,这张图的来源 https://blog.csdn.net/chenyao1994/article/details/79708496 ,版权归原作者所有,我借鉴了原作者的 ...

  3. Spring基于注解配置AOP

    D:\Java\IdeaProjects\JavaProj\SpringHelloWorld\src\aop.xml <?xml version="1.0" encoding ...

  4. Spring 基于 AspectJ 的 AOP 开发

    Spring 基于 AspectJ 的 AOP 开发 在 Spring 的 aop 代理方式中, AspectJ 才是主流. 1. AspectJ 简介 AspectJ 是一个基于 java 语言的 ...

  5. Spring_Spring与AOP_AspectJ基于注解的AOP实现

    一.AspectJ.Spring与AOP的关系 AspectJ是一个面向切面的框架,它扩展了Java语言.AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Cl ...

  6. Spring基于注解的Cache支持

    Spring为我们提供了几个注解来支持Spring Cache.其核心主要是@Cacheable和@CacheEvict.使用@Cacheable标记的方法在执行后Spring Cache将缓存其返回 ...

  7. Spring 基于注解零配置开发

    本文是转载文章,感觉比较好,如有侵权,请联系本人,我将及时删除. 原文网址:< Spring 基于注解零配置开发 > 一:搜索Bean 再也不用在XML文件里写什么配置信息了. Sprin ...

  8. Spring基础知识之基于注解的AOP

    背景概念: 1)横切关注点:散布在应用中多处的功能称为横切关注点 2)通知(Advice):切面完成的工作.通知定了了切面是什么及何时调用. 5中可以应用的通知: 前置通知(Before):在目标方法 ...

  9. Spring AspectJ基于注解的AOP实现

    对于AOP这种编程思想,很多框架都进行了实现.Spring就是其中之一,可以完成面向切面编程.然而,AspectJ也实现了AOP的功能,且实现方式更为简捷,使用更加方便,而且还支持注解式开发.所以,S ...

  10. Spring之注解实现aop(面向切面编程)

    1:Aop(aspect object programming)面向切面编程,名词解释:    1.1:功能:让关注点代码与业务逻辑代码分离    1.2:关注点        重复代码就叫做关注点  ...

随机推荐

  1. QT原理与源码分析之QT对象类型QObject源码中的间接的设计思想

    这一篇文章介绍QT框架中QT对象类型QObject类型的源代码在设计上的一个比较优秀的设计思想. QObject类型定义 QObject 直接来看QObject的源代码.为了表达更简洁更直观,这里省略 ...

  2. 【赵渝强老师】史上最详细的PostgreSQL体系架构介绍

    PostgreSQL是最像Oracle的开源数据库,我们可以拿Oracle来比较学习它的体系结构,比较容易理解.PostgreSQL的主要结构如下: 一.存储结构 PG数据存储结构分为:逻辑存储结构和 ...

  3. Linux内核源码阅读:AArch64的异常处理机制详谈(内核版本6.11)

    ​ 任何玩过Arm64架构的朋友都知道,我们的ARM64架构有异常:Exception Levels, ELs,它是其异常处理机制的核心组成部分,允许系统在不同的特权级别下执行代码.ARM64定义了四 ...

  4. text-align的对齐方式

    text-align的6种取值 left:左对齐 right:右对齐 center:居中 start:如果内容方向是左至右,则等于left,反之则为right. end:如果内容方向是左至右,则等于r ...

  5. Litmus 实践:让群魔在混沌中乱舞,看 K8s 能撑到何时

    对于云服务而言,如果系统出现异常,将会带来很大的损失.为了最大程度地降低损失,我们只能不断探寻系统何时会出现异常,甚至缩小到某些特定参数变化是否会造成系统异常.然而随着云原生的发展,不断推进着微服务的 ...

  6. 最新Sql语句来啦

    创建数据库 CREATE DATABASE 数据库名称; 删除数据库 DROP DATABASE 数据库名称; 创建新表 create table 表名(列 类型 ,列 类型 ,..); 根据已有的表 ...

  7. gcc各等级优化的性质

    原帖地址:CSDN「隨意的風」gcc 中-O -O1 -O2 -O3 -Os -Ofast -Og优化的原理 一般来说,如果不指定优化标识的话,gcc就会产生可调试代码,每条指令之间将是独立的:可以在 ...

  8. redis的主从复制master/slaver

    什么是Redis的复制 ​ 就是我们常说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主. 复制原理 Slave启动成 ...

  9. att&ack学习笔记4

    初识ATT&CK框架前言:ATT&CK这一概念自2014年提出时起,作为安全分析领域中的前沿研究一直在默默地发挥着自己的影响,但是由于其概念在当时过于超前以至于并没有引起多大反响,直至 ...

  10. 解决 在docker环境中 mosquitto 无法启动 报错等问题

    报错内容 1592979788: Error: Unable to open log file /Users/bigbird/mqttconfig/mosquitto/log/mosquitto.lo ...