feat:增加SpringAOP文档
This commit is contained in:
@@ -27,6 +27,7 @@ export const routers = [
|
|||||||
text: '🍃 SpringBoot',
|
text: '🍃 SpringBoot',
|
||||||
items: [
|
items: [
|
||||||
{ text: 'Spring IOC简介', link: '/Web-Backend/SpringBoot/SpringIOC' },
|
{ text: 'Spring IOC简介', link: '/Web-Backend/SpringBoot/SpringIOC' },
|
||||||
|
{ text: 'Spring AOP简介', link: '/Web-Backend/SpringBoot/SpringAOP' },
|
||||||
{ text: 'SpringBoot启动流程', link: '/Web-Backend/SpringBoot/SpringBoot-Start-Process' },
|
{ text: 'SpringBoot启动流程', link: '/Web-Backend/SpringBoot/SpringBoot-Start-Process' },
|
||||||
{ text: 'Spring MVC简介', link: '/Web-Backend/SpringBoot/SpringMVC' },
|
{ text: 'Spring MVC简介', link: '/Web-Backend/SpringBoot/SpringMVC' },
|
||||||
{ text: 'SpringBoot Starter原理', link: '/Web-Backend/SpringBoot/SpringBootStarter' },
|
{ text: 'SpringBoot Starter原理', link: '/Web-Backend/SpringBoot/SpringBootStarter' },
|
||||||
|
|||||||
@@ -48,3 +48,7 @@
|
|||||||
.medium-zoom--opened .medium-zoom-overlay {
|
.medium-zoom--opened .medium-zoom-overlay {
|
||||||
opacity: 0.9 !important;
|
opacity: 0.9 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: #bd34fe;
|
||||||
|
}
|
||||||
221
docs/Web-Backend/SpringBoot/SpringAOP.md
Normal file
221
docs/Web-Backend/SpringBoot/SpringAOP.md
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
---
|
||||||
|
title: Spring AOP简介
|
||||||
|
date: 2025-12-25
|
||||||
|
---
|
||||||
|
|
||||||
|
# 一、基本概念
|
||||||
|
  AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,核心思想是**将与业务核心逻辑无关但又被多个模块共享的功能(如日志、事务、权限校验、性能监控)抽取出来,形成独立的 “切面”**,在不修改原有业务代码的前提下,通过 “织入” 的方式动态添加到目标方法的执行流程中。
|
||||||
|
  Spring AOP 是 Spring 框架对 AOP 思想的实现,基于**动态代理(JDK 动态代理 + CGLIB 动态代理)**,专注于解决企业级开发中的横切关注点问题。
|
||||||
|
| 术语 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 切面(Aspect) | 封装横切逻辑的类(如日志切面、事务切面),包含通知和切点 |
|
||||||
|
| 连接点(Joinpoint) | 程序执行过程中的某个特定点(如方法调用、异常抛出),Spring AOP 中仅支持方法级连接点 |
|
||||||
|
| 切点(Pointcut) | 匹配连接点的规则,用于指定切面要织入到哪些方法上 |
|
||||||
|
| 通知(Advice) | 切面的具体逻辑(如日志打印、权限校验),按执行时机分为 5 种 |
|
||||||
|
| 目标对象(Target) | 被切面织入的目标类(业务类) |
|
||||||
|
| 代理对象(Proxy) | Spring AOP 为目标对象创建的代理类,横切逻辑通过代理执行 |
|
||||||
|
| 织入(Weaving) | 将切面逻辑添加到目标对象的过程,Spring AOP 是运行时织入(通过动态代理) |
|
||||||
|
|
||||||
|
| 通知类型 | 执行时机 |
|
||||||
|
|----------|----------|
|
||||||
|
| 前置通知(Before) | 目标方法执行前执行 |
|
||||||
|
| 后置通知(After) | 目标方法执行后执行(无论是否抛出异常) |
|
||||||
|
| 返回通知(AfterReturning) | 目标方法正常返回后执行 |
|
||||||
|
| 异常通知(AfterThrowing) | 目标方法抛出异常后执行 |
|
||||||
|
| 环绕通知(Around) | 包裹目标方法执行,可自定义目标方法执行前后的逻辑(功能最强) |
|
||||||
|
|
||||||
|
# 二、原理
|
||||||
|
  Spring AOP 基于动态代理实现,分为两种方式:
|
||||||
|
1. JDK 动态代理
|
||||||
|
通过 java.lang.reflect.Proxy 生成代理类,代理类实现目标接口,调用 InvocationHandler 处理横切逻辑;基于接口,无侵入。
|
||||||
|
|
||||||
|
2. CGLIB 动态代理
|
||||||
|
通过继承目标类生成子类作为代理类,重写目标方法,织入横切逻辑;基于继承,目标类不能是 final,方法不能是 final。
|
||||||
|
|
||||||
|
  Spring AOP 自动选择规则:如果目标类实现了接口,使用 JDK 动态代理;否则使用 CGLIB。
|
||||||
|
|
||||||
|
# 三、实战
|
||||||
|
  例如存在以下业务模块:
|
||||||
|
```java
|
||||||
|
@Service
|
||||||
|
public class OrderService {
|
||||||
|
|
||||||
|
// 模拟创建订单
|
||||||
|
public String createOrder(String orderNo) {
|
||||||
|
System.out.println("创建订单:" + orderNo);
|
||||||
|
return "订单创建成功:" + orderNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟删除订单(故意抛出异常)
|
||||||
|
public void deleteOrder(String orderNo) {
|
||||||
|
System.out.println("删除订单:" + orderNo);
|
||||||
|
throw new RuntimeException("删除订单失败:订单不存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
  AOP实现:
|
||||||
|
```java
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.*;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
// 1. 标记为切面类
|
||||||
|
@Aspect
|
||||||
|
// 2. 交给Spring容器管理
|
||||||
|
@Component
|
||||||
|
public class LogAspect {
|
||||||
|
|
||||||
|
// 3. 定义切点:匹配OrderService类的所有方法
|
||||||
|
@Pointcut("execution(* com.example.aopdemo.service.OrderService.*(..))")
|
||||||
|
public void orderServicePointcut() {}
|
||||||
|
|
||||||
|
// 4. 前置通知:目标方法执行前执行
|
||||||
|
@Before("orderServicePointcut()")
|
||||||
|
public void beforeAdvice(JoinPoint joinPoint) {
|
||||||
|
// 获取方法名和参数
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
Object[] args = joinPoint.getArgs();
|
||||||
|
System.out.println("[前置通知] 方法:" + methodName + ",参数:" + Arrays.toString(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 后置通知:目标方法执行后执行(无论是否异常)
|
||||||
|
@After("orderServicePointcut()")
|
||||||
|
public void afterAdvice(JoinPoint joinPoint) {
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
System.out.println("[后置通知] 方法:" + methodName + " 执行完毕");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 返回通知:目标方法正常返回后执行
|
||||||
|
@AfterReturning(value = "orderServicePointcut()", returning = "result")
|
||||||
|
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
System.out.println("[返回通知] 方法:" + methodName + ",返回值:" + result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 异常通知:目标方法抛出异常后执行
|
||||||
|
@AfterThrowing(value = "orderServicePointcut()", throwing = "ex")
|
||||||
|
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
System.out.println("[异常通知] 方法:" + methodName + ",异常:" + ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. 环绕通知:包裹目标方法执行(功能最强)
|
||||||
|
@Around("orderServicePointcut()")
|
||||||
|
public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
|
||||||
|
String methodName = proceedingJoinPoint.getSignature().getName();
|
||||||
|
Object[] args = proceedingJoinPoint.getArgs();
|
||||||
|
|
||||||
|
// 前置逻辑
|
||||||
|
System.out.println("[环绕通知-前置] 方法:" + methodName + ",参数:" + Arrays.toString(args));
|
||||||
|
|
||||||
|
Object result = null;
|
||||||
|
try {
|
||||||
|
// 执行目标方法
|
||||||
|
result = proceedingJoinPoint.proceed();
|
||||||
|
// 返回后逻辑
|
||||||
|
System.out.println("[环绕通知-返回] 方法:" + methodName + ",返回值:" + result);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// 异常逻辑
|
||||||
|
System.out.println("[环绕通知-异常] 方法:" + methodName + ",异常:" + e.getMessage());
|
||||||
|
throw e; // 必须抛出异常,否则上层无法捕获
|
||||||
|
} finally {
|
||||||
|
// 后置逻辑
|
||||||
|
System.out.println("[环绕通知-后置] 方法:" + methodName + " 执行完毕");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
  测试:
|
||||||
|
```java
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
public class OrderServiceTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderService orderService;
|
||||||
|
|
||||||
|
// 测试正常方法(createOrder)
|
||||||
|
@Test
|
||||||
|
public void testCreateOrder() {
|
||||||
|
orderService.createOrder("ORDER_20251225");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试异常方法(deleteOrder)
|
||||||
|
@Test
|
||||||
|
public void testDeleteOrder() {
|
||||||
|
try {
|
||||||
|
orderService.deleteOrder("ORDER_9999");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 捕获异常,避免测试中断
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
  测试结果:
|
||||||
|
```plaintext
|
||||||
|
[环绕通知-前置] 方法:createOrder,参数:[ORDER_20251225]
|
||||||
|
[前置通知] 方法:createOrder,参数:[ORDER_20251225]
|
||||||
|
创建订单:ORDER_20251225
|
||||||
|
[环绕通知-返回] 方法:createOrder,返回值:订单创建成功:ORDER_20251225
|
||||||
|
[返回通知] 方法:createOrder,返回值:订单创建成功:ORDER_20251225
|
||||||
|
[后置通知] 方法:createOrder 执行完毕
|
||||||
|
[环绕通知-后置] 方法:createOrder 执行完毕
|
||||||
|
|
||||||
|
|
||||||
|
[环绕通知-前置] 方法:deleteOrder,参数:[ORDER_9999]
|
||||||
|
[前置通知] 方法:deleteOrder,参数:[ORDER_9999]
|
||||||
|
删除订单:ORDER_9999
|
||||||
|
[环绕通知-异常] 方法:deleteOrder,异常:删除订单失败:订单不存在
|
||||||
|
[异常通知] 方法:deleteOrder,异常:删除订单失败:订单不存在
|
||||||
|
[后置通知] 方法:deleteOrder 执行完毕
|
||||||
|
[环绕通知-后置] 方法:deleteOrder 执行完毕
|
||||||
|
```
|
||||||
|
|
||||||
|
# 四、切点表达式
|
||||||
|
| 切点表达式 | 说明 |
|
||||||
|
|------------|------|
|
||||||
|
| `execution(* com.example.service.*.*(..))` | 匹配 com.example.service 包下所有类的所有方法 |
|
||||||
|
| `execution(public String com.example.service.OrderService.create*(String))` | 匹配 OrderService 类中公共、返回值为 String、方法名以 create 开头、参数为 String 的方法 |
|
||||||
|
| `execution(* com.example..*Service.*(..))` | 匹配 com.example 包及其子包下所有以 Service 结尾的类的所有方法 |
|
||||||
|
| `@annotation(com.example.annotation.Log)` | 匹配标注了 @Log 自定义注解的方法 |
|
||||||
|
|
||||||
|
  组合切点:
|
||||||
|
```java
|
||||||
|
// 匹配OrderService的方法 且 方法名包含"Order"
|
||||||
|
@Pointcut("execution(* com.example.service.OrderService.*(..)) && execution(* *Order*(..))")
|
||||||
|
public void combinePointcut() {}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 五、总结
|
||||||
|
  通俗的解释,AOP本质是:找目标(通过切点规则,精准找到要 “加戏” 的方法 / 类)→ 造代理(Spring 自动给这些目标生成一个 “中间商”(代理对象))→ 加戏(在目标方法真正执行前 / 后 / 出问题时,让这个 “中间商” 帮你干额外的活)。
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
基于 Spring AOP 的知名框架/组件汇总
|
||||||
|
| 框架/组件 | 核心作用 | Spring AOP 应用说明 |
|
||||||
|
|-----------|----------|---------------------|
|
||||||
|
| AspectJ | 提供切点表达式语法、注解解析(@Aspect/@Pointcut 等) | Spring AOP 仅复用其语法规则,底层仍为自身动态代理(未使用 AspectJ 编译期织入) |
|
||||||
|
| Spring Core | 容器管理、动态代理创建(JDK/CGLIB) | 负责切面/目标类的生命周期管理,生成代理对象并完成织入逻辑 |
|
||||||
|
| Spring Transaction | 声明式事务管理 | 切点:匹配 @Transactional 注解方法;<br>通知:方法执行前开启事务、执行后提交、异常时回滚 |
|
||||||
|
| Spring Cache | 声明式缓存管理 | 切点:匹配 @Cacheable/@CacheEvict 等注解方法;<br>通知:方法执行前查缓存、执行后更新缓存 |
|
||||||
|
| spring-boot-starter-aop | AOP 基础依赖封装 | 自动引入 AspectJ + Spring AOP 核心,开箱即用 |
|
||||||
|
| Spring Security | 安全权限管理 | 切点:匹配 @PreAuthorize 等权限注解方法;<br>通知:方法执行前校验用户权限,无权限抛异常 |
|
||||||
|
| MyBatis-Plus | 增强 MyBatis CRUD 操作 | 切点:匹配 Mapper 接口方法/标注注解的实体类;<br>通知:织入分页逻辑、注解(@TableName)解析等 |
|
||||||
|
| Shiro | 权限管理框架 | 切点:匹配 @RequiresPermissions 注解方法;<br>通知:方法执行前校验用户权限 |
|
||||||
|
| Seata | 分布式事务框架 | 切点:匹配 @GlobalTransactional 注解方法;<br>通知:织入全局事务的开启、提交、回滚逻辑 |
|
||||||
|
| Sentinel | 流量控制/熔断降级框架 | 切点:匹配 @SentinelResource 注解方法;<br>通知:方法执行前校验流量阈值、熔断规则 |
|
||||||
|
| Dynamic-TP | 动态线程池框架 | 切点:匹配线程池执行方法;<br>通知:织入线程池耗时、队列长度等监控逻辑 |
|
||||||
|
| p6spy | 数据库 SQL 监控 | 切点:拦截 JDBC 操作方法;<br>通知:织入 SQL 打印、执行耗时统计逻辑 |
|
||||||
|
| dynamic-datasource-spring-boot-starter | 动态数据源切换 | 切点:匹配 @DS 注解方法;<br>通知:方法执行前切换数据源、执行后恢复默认数据源 |
|
||||||
|
| xxl-job | 分布式任务调度 | 切点:匹配任务执行方法;<br>通知:织入任务执行日志、监控指标采集逻辑 |
|
||||||
|
| Spring Cloud Sleuth | 微服务链路追踪 | 切点:拦截 HTTP/RPC 调用方法;<br>通知:织入 traceId/spanId 传递、链路信息采集逻辑 |
|
||||||
|
:::
|
||||||
@@ -38,6 +38,12 @@ public class AppConfig {
|
|||||||
<bean id="userService" class="com.example.UserService"/>
|
<bean id="userService" class="com.example.UserService"/>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
@Service、@Controller这些注解是@Component的衍生注解。
|
||||||
|
@Component注解可以通过@Autowired自动注入,一般用于自己编写的业务模块,需要配合@ComponentScan启用组件扫描(实际开发中@SpringBootApplication注解已经包含了@ComponentScan注解)。
|
||||||
|
@Bean注解一般用于注册第三方库的类。
|
||||||
|
:::
|
||||||
|
|
||||||
## 2.4 作用域
|
## 2.4 作用域
|
||||||
  控制 Bean 在容器中的实例数量和生命周期。Spring 提供多种作用域,默认是 singleton。通过 @Scope 注解指定,如 @Scope("prototype")。
|
  控制 Bean 在容器中的实例数量和生命周期。Spring 提供多种作用域,默认是 singleton。通过 @Scope 注解指定,如 @Scope("prototype")。
|
||||||
- singleton(单例):容器中只有一个实例,所有请求共享该实例(默认值)。
|
- singleton(单例):容器中只有一个实例,所有请求共享该实例(默认值)。
|
||||||
@@ -46,25 +52,32 @@ public class AppConfig {
|
|||||||
- session(Web):每个会话创建一个实例,在会话有效期内有效。
|
- session(Web):每个会话创建一个实例,在会话有效期内有效。
|
||||||
|
|
||||||
## 2.5 生命周期
|
## 2.5 生命周期
|
||||||
1. 实例化(Instantiation):容器通过构造器创建 Bean 实例(分配内存)。
|
1. 实例化(Instantiation)
|
||||||
2. 属性注入(Population):容器将依赖的 Bean 注入到当前 Bean 的字段或方法(如 @Autowired 标注的依赖)。
|
容器通过构造器创建 Bean 实例(分配内存)。
|
||||||
3. 初始化前(Post-processing before initialization):
|
|
||||||
执行 BeanPostProcessor 的 postProcessBeforeInitialization 方法(AOP 代理生成在此阶段)。
|
|
||||||
4. 初始化(Initialization):
|
|
||||||
调用 @PostConstruct 注解的方法(JSR-250 标准,推荐)。
|
|
||||||
若实现 InitializingBean 接口,调用 afterPropertiesSet() 方法。
|
|
||||||
执行自定义初始化方法(如 @Bean(initMethod = "init") 中指定的 init 方法)。
|
|
||||||
5. 初始化后(Post-processing after initialization):
|
|
||||||
执行 BeanPostProcessor 的 postProcessAfterInitialization 方法。
|
|
||||||
6. 使用(In Use):Bean 被应用程序调用。
|
|
||||||
7. 销毁(Destruction):
|
|
||||||
调用 @PreDestroy 注解的方法(JSR-250 标准,推荐)。
|
|
||||||
若实现 DisposableBean 接口,调用 destroy() 方法。
|
|
||||||
执行自定义销毁方法(如 @Bean(destroyMethod = "destroy") 中指定的 destroy 方法)。
|
|
||||||
|
|
||||||
|
2. 属性注入(Population)
|
||||||
|
容器将依赖的 Bean 注入到当前 Bean 的字段或方法(如 @Autowired 标注的依赖)。
|
||||||
|
|
||||||
|
3. 初始化前(Post-processing before initialization)
|
||||||
|
执行 BeanPostProcessor 的 postProcessBeforeInitialization 方法(AOP 代理生成在此阶段)。
|
||||||
|
|
||||||
|
4. 初始化(Initialization)
|
||||||
|
调用 @PostConstruct 注解的方法(JSR-250 标准,推荐)。
|
||||||
|
若实现 InitializingBean 接口,调用 afterPropertiesSet() 方法。
|
||||||
|
执行自定义初始化方法(如 @Bean(initMethod = "init") 中指定的 init 方法)。
|
||||||
|
|
||||||
|
5. 初始化后(Post-processing after initialization)
|
||||||
|
执行 BeanPostProcessor 的 postProcessAfterInitialization 方法。
|
||||||
|
|
||||||
|
6. 使用(In Use)
|
||||||
|
Bean 被应用程序调用。
|
||||||
|
|
||||||
|
7. 销毁(Destruction)
|
||||||
|
调用 @PreDestroy 注解的方法(JSR-250 标准,推荐)。
|
||||||
|
若实现 DisposableBean 接口,调用 destroy() 方法。
|
||||||
|
执行自定义销毁方法(如 @Bean(destroyMethod = "destroy") 中指定的 destroy 方法)。
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
# 三、BeanDefinition
|
# 三、BeanDefinition
|
||||||
## 3.1 定义
|
## 3.1 定义
|
||||||
  BeanDefinition是Spring框架中描述Bean的元数据对象,它包含了创建Bean实例所需的所有信息。
|
  BeanDefinition是Spring框架中描述Bean的元数据对象,它包含了创建Bean实例所需的所有信息。
|
||||||
@@ -172,7 +185,7 @@ public interface BeanFactory {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4.4 实现示例
|
## 4.4 使用示例
|
||||||
```java
|
```java
|
||||||
// 创建BeanFactory实例
|
// 创建BeanFactory实例
|
||||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||||
@@ -193,7 +206,7 @@ UserService userService = beanFactory.getBean("userService", UserService.class);
|
|||||||
- 延迟加载:默认在第一次请求时才创建Bean实例
|
- 延迟加载:默认在第一次请求时才创建Bean实例
|
||||||
- 基础功能:提供最基本的IOC功能
|
- 基础功能:提供最基本的IOC功能
|
||||||
|
|
||||||
# 五、ApplicationContext
|
# 五、ApplicationContext ★★★
|
||||||
## 5.1 定义
|
## 5.1 定义
|
||||||
  ApplicationContext是BeanFactory的子接口,在BeanFactory的基础上提供了更多企业级功能,是Spring容器的完整实现。
|
  ApplicationContext是BeanFactory的子接口,在BeanFactory的基础上提供了更多企业级功能,是Spring容器的完整实现。
|
||||||
|
|
||||||
@@ -544,5 +557,5 @@ protected void finishRefresh() {
|
|||||||
- 标记整个容器启动流程结束,容器进入就绪状态
|
- 标记整个容器启动流程结束,容器进入就绪状态
|
||||||
|
|
||||||
### 5.4.13 总结
|
### 5.4.13 总结
|
||||||
  refresh()方法按固定顺序执行12个步骤,核心可归纳为:准备容器环境 → 解析并注册Bean定义→ 初始化事件、消息等基础设施 → 实例化所有非懒加载的单例Bean→ 完成启动并发布事件。整个过程通过模板方法模式定义,确保了扩展性和一致性。
|
  refresh()方法按固定顺序执行12个步骤,核心可归纳为:**准备容器环境 → 解析并注册Bean定义→ 初始化事件、消息等基础设施 → 实例化所有非懒加载的单例Bean→ 完成启动并发布事件**。整个过程通过模板方法模式定义,确保了扩展性和一致性。
|
||||||
  核心在于两个关键扩展机制:BeanFactoryPostProcessor在Bean定义阶段介入,负责修改和注册Bean的定义信息;BeanPostProcessor在Bean实例化阶段介入,负责对创建好的Bean实例进行增强和包装。
|
  核心在于两个关键扩展机制:**BeanFactoryPostProcessor在Bean定义阶段介入,负责修改和注册Bean的定义信息;BeanPostProcessor在Bean实例化阶段介入,负责对创建好的Bean实例进行增强和包装。**
|
||||||
|
|||||||
@@ -4,37 +4,37 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
# 一、基础概念
|
# 一、基础概念
|
||||||
  Spring MVC(Spring Model-View-Controller)是 Spring Framework 中的一部分,它是一个基于 **<font style="color:#DF2A3F;">请求驱动</font>** 的 Web 框架,主要用于构建 Web 应用程序,并且遵循 MVC(模型-视图-控制器) 设计模式。它将 Web 应用的业务逻辑、用户界面和请求处理分离,使得代码更加模块化和可维护。
|
  Spring MVC(Spring Model-View-Controller)是 Spring Framework 中的一部分,它是一个基于 **请求驱动** 的 Web 框架,主要用于构建 Web 应用程序,并且遵循 MVC(模型-视图-控制器) 设计模式。它将 Web 应用的业务逻辑、用户界面和请求处理分离,使得代码更加模块化和可维护。
|
||||||
|
|
||||||
# 二、具体流程
|
# 二、具体流程
|
||||||

|

|
||||||
|
|
||||||
1. **客户端发起HTTP请求**
|
1. 客户端发起HTTP请求
|
||||||
|
|
||||||
  客户端(浏览器、API 客户端等)向服务器发送 HTTP 请求。请求包含了目标 URL、HTTP 方法(GET、POST 等)以及可能的请求参数。
|
  客户端(浏览器、API 客户端等)向服务器发送 HTTP 请求。请求包含了目标 URL、HTTP 方法(GET、POST 等)以及可能的请求参数。
|
||||||
前端通过发送 HTTP 请求(通常是 AJAX 请求)到后端的 API 端点,并期望获得响应(通常是 JSON 数据)。
|
前端通过发送 HTTP 请求(通常是 AJAX 请求)到后端的 API 端点,并期望获得响应(通常是 JSON 数据)。
|
||||||
|
|
||||||
2. **请求到达 DispatcherServlet**
|
2. 请求到达 DispatcherServlet
|
||||||
|
|
||||||
  所有 HTTP 请求都会先到达 Spring MVC 的核心组件:**<font style="color:#DF2A3F;">DispatcherServlet</font>**。它是前端控制器,负责将请求分发给正确的处理器。DispatcherServlet 是所有请求的入口,Spring Boot 会自动配置它。
|
  所有 HTTP 请求都会先到达 Spring MVC 的核心组件:**DispatcherServlet**。它是前端控制器,负责将请求分发给正确的处理器。DispatcherServlet 是所有请求的入口,Spring Boot 会自动配置它。
|
||||||
  DispatcherServlet 接受所有的 HTTP 请求,根据请求 URL 和 HTTP 方法,定位匹配的控制器方法,将请求交给相应的 Handler Mapping 来匹配控制器。在请求处理前后,执行 拦截器(可选)。最终通过 View Resolver 返回一个合适的视图(对于 RESTful API,通常返回 JSON 格式的数据)。
|
  DispatcherServlet 接受所有的 HTTP 请求,根据请求 URL 和 HTTP 方法,定位匹配的控制器方法,将请求交给相应的 Handler Mapping 来匹配控制器。在请求处理前后,执行 拦截器(可选)。最终通过 View Resolver 返回一个合适的视图(对于 RESTful API,通常返回 JSON 格式的数据)。
|
||||||
|
|
||||||
3. **查找处理器(Handler Mapping)**
|
3. 查找处理器(Handler Mapping)
|
||||||
|
|
||||||
  DispatcherServlet 根据请求的 URL 和 HTTP 方法,查找与之匹配的处理器方法(通常是一个控制器中的方法)。这是由 HandlerMapping 完成的。Spring MVC 提供了多种方式来映射 URL 到控制器方法,例如 @RequestMapping、@GetMapping 等注解。
|
  DispatcherServlet 根据请求的 URL 和 HTTP 方法,查找与之匹配的处理器方法(通常是一个控制器中的方法)。这是由 HandlerMapping 完成的。Spring MVC 提供了多种方式来映射 URL 到控制器方法,例如 @RequestMapping、@GetMapping 等注解。
|
||||||
  @RestController:该注解标记的类会返回 JSON 数据。
|
  @RestController:该注解标记的类会返回 JSON 数据。
|
||||||
  @RequestMapping:用于映射 URL 路径和 HTTP 方法。
|
  @RequestMapping:用于映射 URL 路径和 HTTP 方法。
|
||||||
  @GetMapping、@PostMapping 等:简化版本的 @RequestMapping。
|
  @GetMapping、@PostMapping 等:简化版本的 @RequestMapping。
|
||||||
|
|
||||||
4. **执行拦截器(Interceptor)**
|
4. 执行拦截器(Interceptor)
|
||||||
|
|
||||||
  在请求到达控制器之前,DispatcherServlet 会依次执行配置的拦截器。拦截器主要用于日志记录、安全检查、请求参数的预处理等。
|
  在请求到达控制器之前,DispatcherServlet 会依次执行配置的拦截器。拦截器主要用于日志记录、安全检查、请求参数的预处理等。
|
||||||
  preHandle:请求进入控制器方法之前。
|
  preHandle:请求进入控制器方法之前。
|
||||||
  postHandle:请求完成后,视图渲染之前。
|
  postHandle:请求完成后,视图渲染之前。
|
||||||
  afterCompletion:视图渲染完成后。
|
  afterCompletion:视图渲染完成后。
|
||||||
  **<font style="color:#DF2A3F;">如果拦截器的 preHandle 方法返回 false,请求会被拦截,后续的处理不会继续进行。</font>**
|
  **如果拦截器的 preHandle 方法返回 false,请求会被拦截,后续的处理不会继续进行。**
|
||||||
|
|
||||||
5. **控制器方法处理请求(Handler Execution)**
|
5. 控制器方法处理请求(Handler Execution)
|
||||||
|
|
||||||
  DispatcherServlet 调用合适的控制器方法来处理请求。控制器方法负责处理请求的业务逻辑,并返回一个 Java 对象,这个对象会被自动转换成 JSON 格式返回给客户端。
|
  DispatcherServlet 调用合适的控制器方法来处理请求。控制器方法负责处理请求的业务逻辑,并返回一个 Java 对象,这个对象会被自动转换成 JSON 格式返回给客户端。
|
||||||
  Spring 通过 @ResponseBody 注解(或 @RestController)实现将 Java 对象自动转换为 JSON 格式。默认情况下,Spring 使用 Jackson 来将 Java 对象序列化成 JSON 数据。
|
  Spring 通过 @ResponseBody 注解(或 @RestController)实现将 Java 对象自动转换为 JSON 格式。默认情况下,Spring 使用 Jackson 来将 Java 对象序列化成 JSON 数据。
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
  @RequestParam:用于获取单个请求参数。
|
  @RequestParam:用于获取单个请求参数。
|
||||||
  @PathVariable:用于从 URL 中提取变量(如 /users/{id} 中的 {id})。
|
  @PathVariable:用于从 URL 中提取变量(如 /users/{id} 中的 {id})。
|
||||||
|
|
||||||
6. **响应返回客户端**
|
6. 响应返回客户端
|
||||||
|
|
||||||
  DispatcherServlet 将处理完的结果(JSON 数据)返回给客户端。响应数据通常会包含:
|
  DispatcherServlet 将处理完的结果(JSON 数据)返回给客户端。响应数据通常会包含:
|
||||||
  **状态码**:如 200 OK(成功)、201 Created(资源创建成功)、404 Not Found(资源未找到)、500 Internal Server Error(服务器错误)等。
|
  **状态码**:如 200 OK(成功)、201 Created(资源创建成功)、404 Not Found(资源未找到)、500 Internal Server Error(服务器错误)等。
|
||||||
|
|||||||
Reference in New Issue
Block a user