Spring Framework 执行链路设计
前文我们分享了IoC、Web、数据访问、AOP、上下文等模块设计,聪明的码友已经想到了,该协同作业了。
至此协同作业我们从以下主流程进行展开:接收请求–>处理请求–>结果处理–>返回结果
一、Web 请求入口
场景:用户发起 HTTP 请求 → Spring Web 模块接收请求 → 调用 Controller 处理业务逻辑。
1. 核心流程
2. 核心组件与关键问题
组件 | 主要功能 |
---|---|
DispatcherServlet | 前端控制器,统一接收所有 HTTP 请求,协调其他组件完成请求处理流程(分发请求、调用处理器、渲染视图)。 |
HandlerMapping | 根据请求 URL 映射到对应的 Controller 方法(如通过 @GetMapping 注解),返回 HandlerExecutionChain (包含目标处理器和拦截器链)。 |
HandlerAdapter | 适配不同类型的处理器(如基于注解的 Controller 或传统 Servlet),执行方法并返回 ModelAndView 。 |
ViewResolver | 将逻辑视图名(如 userView )解析为实际的物理视图(如 JSP、Thymeleaf 模板)。 |
Interceptor | 实现横切关注点(如权限校验、日志记录),在请求处理前后插入自定义逻辑。 |
- 问题 1:如何动态映射 URL 到 Controller?
- Spring 解决方案:
@GetMapping
/@PostMapping
注解:通过注解定义 URL 路径和 HTTP 方法。- HandlerMapping:
RequestMappingHandlerMapping
解析注解并建立映射表。
- 问题 2:如何处理异常?
- Spring 解决方案:
@ControllerAdvice
:全局异常处理器,统一处理 Controller 层抛出的异常。HandlerExceptionResolver
:接口实现异常转换逻辑(如返回 JSON 错误响应)。
3. 示例代码
@RestController
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/user/{id}")public User getUser(@PathVariable String id) {return userService.findUserById(id);}
}@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public ResponseEntity<String> handleException(Exception ex) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());}
}
二、业务逻辑与 IoC 容器
问题:Controller 需要调用 Service 和 Repository,如何管理这些对象的生命周期?
解决方案:引入 IoC(控制反转),通过容器管理 Bean 的创建和依赖注入。
1. 核心流程
2. 核心组件与关键问题
组件 | 主要功能 |
---|---|
BeanFactory | Spring IoC 容器的核心接口,负责管理 Bean 的创建、依赖注入和生命周期。 |
ApplicationContext | 扩展 BeanFactory ,提供更丰富的功能(如事件发布、资源加载、国际化支持)。 |
BeanDefinition | 定义 Bean 的元数据(如类名、作用域、依赖关系),由容器解析后实例化 Bean。 |
BeanPostProcessor | 自定义 Bean 初始化/销毁逻辑(如 AOP 代理生成、属性赋值)。 |
- 问题 1:循环依赖
- 场景:
A
依赖B
,B
依赖A
,导致初始化死循环。 - Spring 解决方案:
- 三级缓存机制:
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects
:已完全初始化的 Bean。org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#earlySingletonObjects
:提前暴露的半成品 Bean。org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonFactories
:通过ObjectFactory
创建代理对象。
- 代理对象介入:通过
AOP
生成代理对象,绕过循环依赖。
- 三级缓存机制:
- 问题 2:Bean 生命周期管理
- Spring 提供:
@PostConstruct
:初始化后调用。@PreDestroy
:销毁前调用。BeanPostProcessor
:自定义初始化/销毁逻辑。
3. 示例代码
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;
}@Repository
public class UserRepository {@Autowiredprivate JdbcTemplate jdbcTemplate;
}
三、数据访问模块
问题:Service 需要查询数据库,如何封装 SQL 操作并管理事务?
解决方案:引入 Spring Data Access 模块,通过模板模式和声明式事务实现。
1. 核心流程
2. 核心组件与关键问题
组件 | 主要功能 |
---|---|
JdbcTemplate | 封装 JDBC 操作(查询、更新等),减少模板代码冗余。 |
@Transactional | 声明式事务管理,通过 AOP 控制事务边界(如 REQUIRED 、REQUIRES_NEW 传播模式)。 |
DataSource | 管理数据库连接池(如 HikariCP),提供高性能的数据库连接。 |
RowMapper | 自定义结果集映射逻辑,将数据库记录转换为 Java 对象。 |
- 问题 1:SQL 模板代码冗余
- Spring 解决方案:
JdbcTemplate
:封装 JDBC 操作(查询、更新等),减少重复代码。- RowMapper:自定义结果集映射逻辑。
- 问题 2:事务管理复杂
- Spring 解决方案:
@Transactional
:通过 AOP 实现事务边界控制。- 事务传播行为:支持
REQUIRED
、REQUIRES_NEW
等传播模式。
3. 示例代码
@Repository
public class UserRepository {@Autowiredprivate JdbcTemplate jdbcTemplate;public User findUserById(String id) {return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id = ?",new Object[]{id},(rs, rowNum) -> new User(rs.getString("name")));}
}@Service
public class UserService {@Transactionalpublic void updateUser(User user) {userRepository.update(user);}
}
四、上下文模块
问题:如何统一管理配置、事件、资源加载?
解决方案:引入ApplicationContext
,作为 Spring 容器的核心接口。
1. 核心组件与关键问题
组件 | 主要功能 |
---|---|
ApplicationContext | 管理应用配置、资源加载、事件发布和国际化支持。 |
PropertySourcesPlaceholderConfigurer | 解析 application.properties 中的占位符(如 ${spring.datasource.url} )。 |
ApplicationEventPublisher | 发布事件(如 ContextRefreshedEvent ),支持事件监听器(ApplicationListener )异步处理。 |
MessageSource | 提供多语言资源管理,支持国际化(i18n)。 |
- 问题 1:配置文件加载失败
Spring 解决方案:PropertySourcesPlaceholderConfigurer
:解析application.properties
中的占位符。@PropertySource
:自定义配置文件路径。
- 问题 2:事件监听效率低
Spring 解决方案:ApplicationListener
:异步监听事件(通过@Async
实现)。
2. 示例代码
@Configuration
public class AppConfig {@Beanpublic DataSource dataSource() {return DataSourceBuilder.create().build();}
}public class MyCustomListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {System.out.println("应用启动完成");}
}
五、AOP 模块
问题:如何将日志、事务等公共逻辑与业务代码解耦?
解决方案:引入 AOP(面向切面编程),通过拦截器链实现横切关注点管理。
1. 核心流程
2. 核心组件与关键问题
组件 | 主要功能 |
---|---|
@Aspect | 定义切面类,封装横切关注点(如日志、事务)。 |
@Pointcut | 定义切入点表达式(如 execution(* com.albert.service.*.*(..)) ),指定切面逻辑的应用范围。 |
MethodInterceptor | 通过责任链模式执行通知逻辑(如 @Before 、@After )。 |
ProxyFactory | 动态生成代理对象(JDK 动态代理或 CGLIB 代理)。 |
- 问题 1:切点表达式匹配错误
- Spring 解决方案:
- AspectJ 表达式语法:精确控制切点范围(如
execution(* com.albert.service.*.*(..))
)。
- AspectJ 表达式语法:精确控制切点范围(如
- 问题 2:代理性能问题
- Spring 解决方案:
- JDK 动态代理:适用于接口类。
- CGLIB 代理:适用于无接口类(需注意
final
方法限制)。
3. 示例代码
@Aspect
@Component
public class MyLogAspect {@Before("execution(* com.albert.service.*.*(..))")public void logBefore(JoinPoint joinPoint) {System.out.println("方法调用前: " + joinPoint.getSignature().getName());}
}
六、整体执行链路总结
1. Spring 容器启动阶段(资源准备)
1.1 Spring 容器初始化
ApplicationContext
加载配置- 读取
application.properties
或 XML 配置文件,解析 Bean 定义(BeanDefinition
)。 - 初始化
BeanFactory
,注册所有 Bean 的定义信息。
- 读取
- 资源预加载
- 数据库连接池初始化(如 Druid):
- 根据配置创建数据库连接池,建立初始连接,确保后续请求可直接使用。
- AOP 代理对象生成:
- 通过
InstantiationAwareBeanPostProcessor
在 Bean 实例化前生成代理对象(如 AOP 代理)。 - 示例:
postProcessBeforeInstantiation
返回代理对象,跳过默认实例化。
- 通过
- 数据库连接池初始化(如 Druid):
- Bean 实例化与依赖注入
- Bean 实例化:
- 调用构造函数创建 Bean 实例(或通过工厂方法)。
- 通过
BeanPostProcessor
在实例化前后进行拦截(如属性校验、动态代理)。
- 依赖注入(DI):
- 填充属性(
@Autowired
注解字段)。 - 通过
postProcessProperties
修改属性值(如解密敏感数据)。
- 填充属性(
- Bean 实例化:
- Bean 初始化
- 调用
@PostConstruct
方法或init-method
。 - 应用 AOP 通知(如
@Around
、@After
)。
- 调用
1.2 Web 模块初始化
DispatcherServlet
注册:- 将
DispatcherServlet
注册为处理 HTTP 请求的前端控制器。
- 将
HandlerMapping
配置:- 将 URL 映射到 Controller 方法(如
@GetMapping
注解)。
- 将 URL 映射到 Controller 方法(如
ViewResolver
配置:- 配置逻辑视图名到物理视图的映射规则(如 Thymeleaf 模板路径)。
1.3 事务管理器初始化
- 配置
PlatformTransactionManager
(如DataSourceTransactionManager
)。 - 注册事务注解驱动(
@EnableTransactionManagement
)。
1.4 事件监听器注册
- 注册
ApplicationListener
监听应用事件(如ContextRefreshedEvent
)。
2. 请求处理阶段(运行时流程)
2.1 客户端发送 HTTP 请求
- 请求由
DispatcherServlet
接收,进入 Spring MVC 流程。
2.2 请求映射与处理器调用
HandlerMapping
查找处理器:- 根据 URL 匹配对应的 Controller 方法(
@GetMapping
/@PostMapping
)。
- 根据 URL 匹配对应的 Controller 方法(
HandlerAdapter
调用处理器:- 执行 Controller 方法,获取
ModelAndView
。
- 执行 Controller 方法,获取
2.3 业务逻辑执行
- Service 层调用 Repository:
- 通过依赖注入的 DAO 或 JPA Repository 访问数据库。
- 事务管理:
@Transactional
注解触发事务边界(如开启事务、提交/回滚)。
2.4 AOP 拦截器链执行
- 通知逻辑执行:
@Before
:前置增强(如权限校验)。@After
:后置增强(如日志记录)。@Around
:环绕增强(如性能监控)。
- 异常处理:
@AfterThrowing
捕获异常并执行自定义逻辑。
2.5 视图解析与响应返回
ViewResolver
解析视图:- 将逻辑视图名(如
userView
)转换为物理视图(如 Thymeleaf 模板路径)。
- 将逻辑视图名(如
- 渲染视图并返回响应:
- 将
Model
数据传递给视图模板,生成 HTML 响应。
- 将
附录:各模块设计引入后的新问题与解决
模块 | 引入后的新问题 | Spring 解决方案 |
---|---|---|
Web | 请求映射冲突、异常处理不统一 | @RequestMapping 注解、@ControllerAdvice 全局异常处理器 |
IoC | 循环依赖、Bean 初始化失败 | 三级缓存机制、@Lazy 延迟加载、@PostConstruct 自定义初始化 |
数据访问 | SQL 模板代码冗余、事务管理复杂 | JdbcTemplate 、@Transactional 声明式事务 |
AOP | 切点匹配错误、代理性能问题 | AspectJ 表达式语法、JDK/CGLIB 代理选择 |
上下文 | 配置文件加载失败、事件监听效率低 | PropertySourcesPlaceholderConfigurer 、@Async 异步事件监听 |