spring提供的其他机制
我把它们整理成了下面这张思维导图,可以先快速建立整体印象:
Spring 核心机制
IoC 容器与 DI
BeanFactory / ApplicationContext
依赖注入 / @Autowired
AOP 面向切面编程
JDK / CGLIB 动态代理
@Aspect / @Before / @After / @Around
数据访问抽象
声明式事务 @Transactional
JDBC / ORM 集成
Web 开发
Spring MVC
RESTful 支持
核心工具与扩展
Spring 表达式语言 SpEL
类型转换与数据校验
Aware 接口体系
响应式编程
Spring WebFlux
Reactive Streams
R2DBC / RSocket
集成与消息
远程调用
JMS / AMQP
JMX
邮件 / 定时任务
测试
Mock 对象
测试上下文 TestContext
@MockBean
1.创建一个线程的机制
2.springevent
3.定时任务@scheduled和springtask相关
4.@retryable
5.国际化相关
6.单元测试相关
1. 创建线程的机制(异步执行与线程池)
Spring 并没有重新发明 Java 的线程,而是通过 TaskExecutor 抽象 和 @Async 注解 提供了声明式的异步执行能力,本质上是对 java.util.concurrent.Executor 的封装。
核心组件
TaskExecutor接口:Spring 的任务执行器抽象ThreadPoolTaskExecutor:最常用的线程池实现(基于ThreadPoolExecutor)@Async:标记异步方法@EnableAsync:启用异步处理
使用步骤
- 配置类加
@EnableAsync - 定义自定义线程池 Bean(推荐,避免默认的
SimpleAsyncTaskExecutor)
java
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("async-");
executor.initialize();
return executor;
}
- 在需要异步执行的方法上添加
@Async("taskExecutor")
最佳实践
- 必须自定义线程池,否则高并发下默认实现会为每个任务创建新线程,导致内存溢出
- 异步方法的返回值可以是
void、Future<T>、CompletableFuture<T> - 自调用(类内部直接调用
@Async方法)会导致异步失效,需要将异步方法放到独立的 Bean 中
2. Spring 事件(ApplicationEvent & @EventListener)
基于 观察者模式 实现业务解耦,适合在同一个应用内的不同模块间传递消息。
核心组件
ApplicationEvent:事件基类,自定义事件需继承它ApplicationEventPublisher:发布事件的接口(通常直接注入)@EventListener:注解在监听方法上ApplicationEventMulticaster:底层事件广播器(通常使用默认的SimpleApplicationEventMulticaster)
使用步骤
- 定义事件类:
java
public class OrderCreatedEvent extends ApplicationEvent {
private final Long orderId;
public OrderCreatedEvent(Object source, Long orderId) {
super(source);
this.orderId = orderId;
}
// getter...
}
- 发布事件:注入
ApplicationEventPublisher,调用publishEvent - 监听事件:
java
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) { ... }
最佳实践
- 默认同步执行 :事件发布线程会等待所有监听器执行完毕。如需异步,可在监听方法上加
@Async - 监听顺序 :使用
@Order注解 - 事务绑定 :使用
@TransactionalEventListener可将监听器与事务阶段绑定(如AFTER_COMMIT)
3. 定时任务(@Scheduled 与 TaskScheduler)
基于 java.util.concurrent.ScheduledExecutorService 的封装,提供方便的任务调度能力。
核心组件
@EnableScheduling:启用调度@Scheduled:标记定时方法TaskScheduler:调度器接口(默认实现ThreadPoolTaskScheduler)
使用步骤
- 配置类加
@EnableScheduling - 在方法上使用
@Scheduled:
java
@Scheduled(fixedDelay = 5000) // 上次结束后延迟5秒
@Scheduled(fixedRate = 5000) // 上次开始后间隔5秒(可能并发)
@Scheduled(cron = "0 0 * * * ?") // Cron表达式
最佳实践
- 默认单线程 :所有定时任务共用同一个线程。若某个任务阻塞,会延迟其他任务。建议自定义
TaskScheduler并设置线程池大小:
java
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5);
return scheduler;
}
fixedRate注意并发:若任务执行时间超过间隔,可能并发执行,需确保方法线程安全- 动态调度:实现
SchedulingConfigurer可动态修改 Cron 表达式
4. @Retryable 重试机制
用于处理临时故障(网络抖动、数据库死锁等),通过声明式重试提高成功率。
核心组件
@EnableRetry:启用重试@Retryable:标记需要重试的方法@Recover:重试耗尽后的降级方法
使用步骤
- 添加依赖:
spring-retry+spring-boot-starter-aop - 启动类加
@EnableRetry - 在方法上使用:
java
@Retryable(value = {DataAccessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2))
public void callRemoteService() { ... }
- 定义恢复方法:
java
@Recover
public void recover(DataAccessException e) { ... }
最佳实践
- 指定明确的异常类型,不要对所有异常重试
- 合理配置退避策略(
backoff),避免重试风暴 @Recover方法参数必须与重试方法抛出的异常匹配,且返回值类型一致
5. 国际化(i18n)相关
Spring 通过 MessageSource 接口提供了完善的国际化支持,可以轻松实现多语言文本管理。
核心组件
MessageSource:国际化消息的核心接口ResourceBundleMessageSource:基于资源文件的实现(推荐)ReloadableResourceBundleMessageSource:支持热加载的实现LocaleContextHolder:获取当前请求的Locale(Web 环境下)
使用步骤
- 在
src/main/resources下创建消息文件:messages.properties(默认)messages_zh_CN.properties(中文)messages_en_US.properties(英文)
- 配置
MessageSourceBean:
java
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("messages"); // 基础名
source.setDefaultEncoding("UTF-8");
source.setCacheSeconds(3600);
return source;
}
- 在代码中使用:
- 注入
MessageSource,调用getMessage("key", args, locale) - 在 Spring MVC 的 View 中,使用
#{}或message标签 - 在 Thymeleaf 等模板中直接使用
#{key}
- 注入
最佳实践
- 明确当前语言环境 :Web 应用中,可通过
LocaleResolver从请求头、Cookie 或 Session 解析Locale - 支持热加载 :开发时使用
ReloadableResourceBundleMessageSource,方便修改资源文件无需重启 - 参数化消息 :支持占位符,如
message.key=Hello {0},today is {1} - 与国际化配合 :
@Controller中可接收Locale参数,根据前端需求动态切换
6. 单元测试相关(spring-test 模块)
Spring 提供了 spring-test 模块,极大简化了基于 Spring 容器的集成测试编写。
核心组件
@RunWith(SpringRunner.class)/@ExtendWith(SpringExtension.class)(JUnit 5)@ContextConfiguration:指定配置文件或配置类@SpringBootTest:Spring Boot 的集成测试注解@MockBean:在容器中替换真实 Bean 为 Mock 对象(基于 Mockito)TestContext框架:缓存 ApplicationContext,提升测试执行速度
使用步骤(以 JUnit 5 + Spring Boot 为例)
java
@SpringBootTest // 启动完整上下文
@AutoConfigureMockMvc // 用于测试 MVC 接口
class UserServiceTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private RemoteService remoteService; // 替换真实 Bean
@Test
void testGetUser() throws Exception {
when(remoteService.call()).thenReturn("mock data");
mockMvc.perform(get("/user/1"))
.andExpect(status().isOk());
}
}
最佳实践
- 分层测试 :
- 单元测试:不启动 Spring 容器,只测试单个类(使用 Mockito)
- 切片测试:
@WebMvcTest(测试 Controller)、@DataJpaTest(测试 Repository)等,只加载部分 Bean,速度快 - 集成测试:
@SpringBootTest启动完整上下文,可用于测试完整流程
- 使用
@TestPropertySource或application-test.properties隔离测试环境配置 - 事务回滚 :
@Transactional加在测试方法上,默认会在结束后回滚,避免污染数据库 - 重复利用上下文 :
TestContext框架会缓存 ApplicationContext,不同测试类若配置相同则复用,注意不要使用@DirtiesContext
总结对比
| 机制 | 核心注解/接口 | 主要用途 | 常见陷阱 |
|---|---|---|---|
| 异步线程 | @Async, TaskExecutor |
提升响应速度,处理耗时任务 | 默认线程池无限创建线程;自调用失效 |
| Spring 事件 | @EventListener, ApplicationEvent |
业务解耦,模块间通信 | 默认同步阻塞;事件滥用导致理解困难 |
| 定时任务 | @Scheduled |
周期性执行任务 | 单线程阻塞;fixedRate 并发隐患 |
| 重试 | @Retryable, @Recover |
处理瞬时故障 | 无退避策略可能加重故障;忘记配置 @EnableRetry |
| 国际化 | MessageSource |
多语言支持 | 未正确设置编码;Locale 未传递 |
| 单元测试 | @SpringBootTest, @MockBean |
集成测试,模拟依赖 | 测试过慢(应优先使用切片测试);上下文污染 |