【Spring】深度剖析AOP

一文彻底搞懂 Spring AOP(概念、原理、使用、执行流程、面试重点)


在 Spring 开发中,我们经常看到很多注解:

复制代码
@Transactional
@Cacheable
@Async
@Log

这些注解看起来只是简单标记了一下方法,但实际上它们可以:

  • 自动开启事务
  • 自动记录日志
  • 自动缓存数据
  • 自动异步执行

很多人会问:

Spring 是怎么做到的?

答案就是:

复制代码
AOP(面向切面编程)

本篇文章将系统讲清 Spring AOP 的核心知识体系


一、什么是 AOP

1 AOP 概念

AOP 全称:

复制代码
Aspect Oriented Programming
面向切面编程

核心思想:

复制代码
在不修改原有代码的情况下
对程序功能进行增强

简单理解:

复制代码
在方法执行前后插入代码

例如:

java 复制代码
public void createUser(){
    System.out.println("创建用户");
}

我们希望:

复制代码
执行前记录日志
执行后记录日志

变成:

java 复制代码
log.info("方法开始");

createUser();

log.info("方法结束");

如果直接写在代码中:

复制代码
业务代码会变得混乱

AOP 的目的就是:

复制代码
把这些公共逻辑提取出来
统一处理

二、为什么需要 AOP

在真实项目中,有很多 重复逻辑

例如:

复制代码
日志
事务
权限校验
缓存
监控

如果每个方法都写:

java 复制代码
public void createUser(){

    log.info("开始");

    transaction.begin();

    //业务代码

    transaction.commit();

}

会出现问题:

复制代码
大量重复代码
难以维护

AOP 可以把这些逻辑统一管理:

复制代码
日志模块
事务模块
权限模块

业务代码只需要关注:

复制代码
核心业务

三、AOP 核心术语

学习 AOP 必须理解 5 个概念。


1 切面(Aspect)

切面就是:

复制代码
增强逻辑 + 切入点

例如:

复制代码
日志切面
事务切面
权限切面

示例:

java 复制代码
@Aspect
@Component
public class LogAspect {

}

2 连接点(JoinPoint)

连接点指的是:

复制代码
可以被拦截的方法

例如:

复制代码
Controller方法
Service方法

简单理解:

复制代码
程序执行的某个点

3 切入点(Pointcut)

切入点指的是:

复制代码
具体拦截哪些方法

例如:

复制代码
拦截所有Service方法

示例:

java 复制代码
@Pointcut("execution(* com.demo.service.*.*(..))")
public void pointcut(){}

4 通知(Advice)

通知就是:

复制代码
增强逻辑

例如:

复制代码
日志
权限
事务

通知类型:

类型 说明
@Before 方法执行前
@After 方法执行后
@AfterReturning 返回后
@AfterThrowing 异常后
@Around 环绕

5 目标对象(Target)

目标对象就是:

复制代码
原始业务对象

例如:

java 复制代码
UserService

四、Spring AOP 执行流程

假设调用:

复制代码
userService.createUser()

执行流程:

复制代码
Controller
   ↓
代理对象
   ↓
Before通知
   ↓
目标方法
   ↓
After通知

完整流程:

复制代码
调用代理对象
      ↓
执行前置通知
      ↓
执行目标方法
      ↓
执行后置通知

五、Spring AOP 的实现原理

Spring AOP 底层使用:

复制代码
动态代理

Spring 会创建:

复制代码
代理对象

替代原始对象。

调用流程:

复制代码
Controller
   ↓
Proxy(UserService)
   ↓
UserService

代理对象负责:

复制代码
增强逻辑

六、Spring AOP 两种代理方式

Spring AOP 有两种实现方式。


1 JDK 动态代理

条件:

复制代码
目标类必须有接口

示例:

java 复制代码
public interface UserService{
    void createUser();
}

Spring 生成代理:

复制代码
UserServiceProxy

代理接口。

特点:

复制代码
基于接口

2 CGLIB 代理

如果没有接口:

Spring使用:

复制代码
CGLIB

实现方式:

复制代码
继承目标类

例如:

复制代码
UserService$$EnhancerBySpring

七、Spring AOP 使用步骤


1 引入依赖

Spring Boot 已包含:

复制代码
spring-boot-starter-aop

2 开启 AOP

java 复制代码
@EnableAspectJAutoProxy

Spring Boot 默认已开启。


3 定义切面

java 复制代码
@Aspect
@Component
public class LogAspect {

}

4 定义切入点

java 复制代码
@Pointcut("execution(* com.demo.service.*.*(..))")
public void pointcut(){}

含义:

复制代码
拦截service包所有方法

5 编写通知

前置通知
java 复制代码
@Before("pointcut()")
public void before(){
    System.out.println("方法执行前");
}

后置通知
java 复制代码
@After("pointcut()")
public void after(){
    System.out.println("方法执行后");
}

返回通知
java 复制代码
@AfterReturning("pointcut()")
public void afterReturn(){
}

异常通知
java 复制代码
@AfterThrowing("pointcut()")
public void exception(){
}

环绕通知(最强)
java 复制代码
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{

    System.out.println("方法开始");

    Object result = joinPoint.proceed();

    System.out.println("方法结束");

    return result;

}

八、切入点表达式(重点)

最常用表达式:

复制代码
execution()

语法:

复制代码
execution(访问修饰符 返回值 包名.类名.方法名(参数))

示例:

拦截 Service:

复制代码
execution(* com.demo.service.*.*(..))

解释:

复制代码
* 返回值任意
service包
任意类
任意方法
任意参数

九、Spring AOP 常见问题


1 同类方法调用失效

例如:

java 复制代码
@Service
public class UserService {

    public void methodA(){
        methodB();
    }

    @Transactional
    public void methodB(){
    }

}

事务不会生效。

原因:

复制代码
没有经过代理对象

2 private 方法无法增强

例如:

java 复制代码
private void test(){}

原因:

复制代码
CGLIB 无法重写 private 方法

3 final 方法无法增强

原因:

复制代码
final 方法不能被重写

十、Spring AOP 应用场景

AOP 在实际项目中非常常见:

场景 示例
事务管理 @Transactional
日志记录 接口日志
权限控制 登录校验
性能监控 方法耗时
缓存 @Cacheable

十一、Spring AOP 与 AspectJ 区别

Spring AOP AspectJ
实现方式 动态代理 字节码增强
织入时间 运行时 编译时
功能 简单 强大
使用难度 简单 较复杂

Spring 默认:

复制代码
Spring AOP

十二、Spring AOP 面试高频问题


1 什么是 AOP?

答:

复制代码
AOP 是一种编程思想,
可以在不修改业务代码的情况下
对方法进行增强。

2 Spring AOP 原理?

复制代码
动态代理

3 Spring AOP 有哪两种代理?

复制代码
JDK 动态代理
CGLIB 代理

4 AOP 常见通知类型?

复制代码
@Before
@After
@AfterReturning
@AfterThrowing
@Around

5 为什么事务会失效?

原因:

复制代码
没有通过代理对象调用

例如:

复制代码
同类方法调用
private方法
final方法

十三、Spring AOP 总结

Spring AOP 的核心思想:

复制代码
在不修改业务代码的情况下
增强方法功能

核心原理:

复制代码
动态代理

核心流程:

复制代码
Controller
   ↓
代理对象
   ↓
增强逻辑
   ↓
目标方法

AOP 在 Spring 中应用非常广泛:

复制代码
事务
日志
权限
缓存
监控

几乎所有 Spring 高级功能都基于 AOP 实现

相关推荐
泉城老铁2 小时前
一分钟搞定SpringBoot+Vue3 整合 SSE 实现实时消息推送
前端·vue.js·后端
老迟聊架构2 小时前
完全基于对象存储的数据库引擎:SlateDB
数据库·后端·架构
小杍随笔2 小时前
【Rust可见性控制:pub、pub(crate)、pub(super)实战】
开发语言·后端·rust
ノBye~2 小时前
Maven聚合项目搭建
java·maven
sevenlin2 小时前
SpringBoot3.3.0集成Knife4j4.5.0实战
java
乐观勇敢坚强的老彭2 小时前
本周C++编程课笔记:for循环练习
java·c++·笔记
摇滚侠2 小时前
从 Tomcat 服务最大连接数角度讲一讲高峰期高考查分网站打不开,服务器的资源是有限的,同一时间大量用户连接服务器,会耗尽服务器的资源,服务器会拒绝新的连接
java·服务器·tomcat
NE_STOP2 小时前
MyBatis-plus拓展之字段类型处理器、自动填充和乐观锁等(完结)
java
中国lanwp2 小时前
Maven Gradle SBT Mill Ivy Grape Leiningen Buildr构建工具
java·maven