【Spring Boot AOP介绍】

文章目录

一、AOP是什么?

面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,通过分离横切关注点来提高模块化程度。AOP 允许开发者定义可以在代码执行的某些点(切点)执行的额外行为(切面),从而避免代码的重复和冗余。

1. AOP的核心概念

切面(Aspect)

切面是 AOP 的核心概念之一,代表一个横切关注点的模块化。切面可以包含多个通知(Advice),这些通知定义了切面在特定切点(Join Point)上的行为。

连接点(Join Point)

连接点是在程序执行的过程中可以插入切面的具体点。Spring AOP 支持的方法执行连接点,意味着切面可以在方法调用前后或方法抛出异常时执行。

切点(Pointcut)

切点是一个表达式,定义了哪些连接点会被切面切入。切点表达式通常使用类名、方法名、参数等信息来指定需要织入的连接点。

通知(Advice)

通知是切面在切点处所执行的代码。通知有多种类型,包括前置通知(Before)、后置通知(After)、返回通知(After Returning)、异常通知(After Throwing)和环绕通知(Around)。

目标对象(Target Object)

目标对象是被一个或多个切面切入的对象。Spring AOP 使用 JDK 动态代理或 CGLIB 代理来为目标对象创建代理对象。

AOP代理(AOP Proxy)

AOP 代理是由 AOP 框架生成的对象,用于实现切面契约。Spring AOP 使用 JDK 动态代理来代理实现接口的类,使用 CGLIB 来代理没有实现接口的类。

2. AOP的优势

模块化

通过 AOP,可以将日志记录、事务管理、安全性等横切关注点与业务逻辑分离,提升代码的模块化程度,使得每个模块职责单一、清晰。

代码复用

AOP 使得相同的横切关注点代码可以在多个模块中复用,减少代码重复,提升代码的可维护性。

解耦

业务逻辑代码与横切关注点代码解耦,业务逻辑代码更加简洁、清晰,横切关注点的变化不会影响业务逻辑代码。

3. AOP的实现方式

编译时织入

在编译代码时将切面织入目标代码,使用编译器提供的机制将横切关注点的代码编译到目标类中。这种方式的代表是 AspectJ。

类加载时织入

在类加载时通过类加载器将切面织入目标类。这种方式需要定制类加载器,较为复杂。

运行时织入

在应用程序运行时通过动态代理技术将切面织入目标对象。这是 Spring AOP 采用的方式,通过 JDK 动态代理或 CGLIB 实现。

4. Spring AOP概述

Spring AOP 是 Spring 框架的一部分,提供了简单易用的 AOP 功能。Spring AOP 使用动态代理实现运行时织入,并支持基于注解和基于 XML 的配置方式。Spring AOP 主要用于处理方法级别的横切关注点,适用于大多数企业应用场景。

二、Spring Boot AOP 基础

1. 引入依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 创建切面

java 复制代码
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void logBeforeMethod() {
        System.out.println("A method is about to be executed.");
    }
}

@Aspect 注解表明该类是一个切面类,@Component 注解将其注册为 Spring 容器的一个 Bean。@Before 注解用于定义前置通知,在目标方法执行前执行。

3. 定义切点

切点定义了切面织入的具体位置,可以通过 @Pointcut 注解来定义。

java 复制代码
import org.aspectj.lang.annotation.Pointcut;

@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}

@Pointcut 注解定义了一个名为 serviceLayer 的切点,该切点匹配 com.example.service 包中的所有方法执行。

4. 应用通知

通知是在切点处执行的代码,可以在目标方法执行前后或抛出异常时执行。Spring AOP 提供了多种类型的通知,如前置通知、后置通知、返回通知、异常通知和环绕通知。

后置通知

后置通知在目标方法执行后执行:

java 复制代码
import org.aspectj.lang.annotation.After;

@After("execution(* com.example.service.*.*(..))")
public void logAfterMethod() {
    System.out.println("A method has just been executed.");
}

环绕通知

环绕通知可以在目标方法执行前后执行,并且可以控制目标方法的执行:

java 复制代码
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;

@Around("execution(* com.example.service.*.*(..))")
public Object logAroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Method execution start.");
    Object result = joinPoint.proceed(); // 执行目标方法
    System.out.println("Method execution end.");
    return result;
}

@Around 注解定义了一个环绕通知,ProceedingJoinPoint 对象用于执行目标方法。环绕通知在目标方法执行前后打印日志信息。

三、实战案例

1. 日志记录

创建一个记录日志的切面

java 复制代码
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.controller.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Executing: " + joinPoint.getSignature().getName());
    }

    @AfterReturning(pointcut = "execution(* com.example.controller.*.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("Executed: " + joinPoint.getSignature().getName() + ", Returned: " + result);
    }
}
  • @Before 注解定义了前置通知,记录方法执行前的信息。
  • @AfterReturning 注解定义了后置返回通知,记录方法执行后的返回结果。
  • logBefore 方法在 com.example.controller 包下的所有方法执行之前打印日志,记录即将执行的方法名称。
  • logAfterReturning 方法在 com.example.controller 包下的所有方法执行之后打印日志,记录方法名称和返回结果。

2. 事务管理

创建一个事务管理的切面

java 复制代码
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TransactionAspect {

    @Around("@annotation(org.springframework.transaction.annotation.Transactional)")
    public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Transaction start.");
        Object result = joinPoint.proceed();
        System.out.println("Transaction end.");
        return result;
    }
}
  • @Around 注解定义了环绕通知,用于在方法执行前后执行自定义逻辑。
  • manageTransaction 方法在带有 @Transactional 注解的方法执行前后打印事务开始和结束的日志。
  • ProceedingJoinPoint 对象用于执行目标方法,并在目标方法执行前后插入自定义逻辑。
相关推荐
阿伟*rui34 分钟前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
XiaoLeisj3 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck3 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei3 小时前
java的类加载机制的学习
java·学习
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~5 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616885 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7895 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java6 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
睡觉谁叫~~~6 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust