前言
Spring Boot 的价值不只是"少写配置",而是通过自动装配、事件机制和约定优于配置,将 Spring 生态中的组件组织成一套开箱即用的开发模型。本文以 Spring Boot 3.x 为背景,介绍自动装配原理、事件监听、@Async 异步任务,以及 @RequestMapping、@GetMapping、@PostMapping 的区别。
严格来说,事件发布、
@Async和请求映射主要由 Spring Framework 提供,Spring Boot 负责自动配置和简化使用。
一、Spring Boot 的自动装配原理
1. 自动装配解决了什么问题?
传统 Spring 项目需要手动声明大量 Bean。Spring Boot 会根据类路径中的依赖、配置文件和当前容器中的 Bean,判断应该启用哪些配置。例如引入 Web Starter 后,它可以配置 Spring MVC、消息转换器和嵌入式 Web 服务器。
启动类通常只有一个核心注解:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootApplication 是组合注解,主要包含:
-
@SpringBootConfiguration:标记配置类,本质上基于@Configuration; -
@ComponentScan:扫描启动类所在包及其子包中的组件; -
@EnableAutoConfiguration:开启自动装配。
2. 自动装配的执行流程
可将其概括为"获取候选配置 → 条件筛选 → 注册 Bean":
-
@EnableAutoConfiguration通过导入选择器触发自动配置导入; -
Spring Boot 从各个依赖的
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中读取自动配置类; -
通过条件注解判断配置是否生效;
-
满足条件的配置类进入容器,并注册相应 Bean。
二、Spring Boot 的事件监听机制
Spring 事件模型由三部分组成:事件、发布者和监听器。它适合降低模块之间的直接依赖,例如订单创建后,订单服务只发布事件,积分、通知等模块各自监听。
1. 定义并发布事件
public record OrderCreatedEvent(Long orderId) {}
@Service
public class OrderService {
private final ApplicationEventPublisher publisher;
public OrderService(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void createOrder(Long orderId) {
// 保存订单
publisher.publishEvent(new OrderCreatedEvent(orderId));
}
}
2. 监听事件
推荐使用 @EventListener:
@Component
public class OrderEventListener {
@EventListener
public void handle(OrderCreatedEvent event) {
System.out.println("处理订单:" + event.orderId());
}
}
三、使用 @Async 执行异步任务
先在配置类或启动类上开启异步支持:
@EnableAsync
@SpringBootApplication
public class DemoApplication {}
再把耗时任务放入独立的 Spring Bean:
@Service
public class MailService {
@Async("businessExecutor")
public CompletableFuture<String> sendMail(String address) {
// 执行发送逻辑
return CompletableFuture.completedFuture("success");
}
}
生产环境应显式配置线程池:
@Configuration
public class AsyncConfig {
@Bean("businessExecutor")
public ThreadPoolTaskExecutor businessExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(200);
executor.setThreadNamePrefix("business-");
executor.initialize();
return executor;
}
}
@Async 的底层核心是 AOP 代理:外部对象调用代理方法时,拦截器将任务提交给线程池。因此必须注意:
-
同一个类中使用
this.asyncMethod()属于自调用,会绕过代理; -
方法可返回
void、Future或CompletableFuture,需要结果时优先选择CompletableFuture; -
void方法的异常不会返回给调用方,可配置AsyncUncaughtExceptionHandler; -
新线程不会自动继承原线程的事务和普通
ThreadLocal上下文; -
线程数、队列容量和拒绝策略要结合任务耗时及流量设置,避免任务堆积。
事件监听也可结合 @Async,使特定监听器异步执行:
@Async("businessExecutor")
@EventListener
public void handle(OrderCreatedEvent event) {
// 在业务线程池中处理
}
四、@RequestMapping、@GetMapping 与 @PostMapping
三者都用于建立 HTTP 请求与 Controller 方法之间的映射。
|-------------------|--------------------|------|
| 注解 | 作用 | 常见位置 |
| @RequestMapping | 通用映射,可限定任意 HTTP 方法 | 类或方法 |
| @GetMapping | 映射 GET 请求 | 方法 |
| @PostMapping | 映射 POST 请求 | 方法 |
@GetMapping 和 @PostMapping 是组合注解,分别等价于:
@RequestMapping(method = RequestMethod.GET)
@RequestMapping(method = RequestMethod.POST)
推荐在类上用 @RequestMapping 定义公共路径,在方法上使用语义更明确的快捷注解:
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public User get(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping(consumes = "application/json",
produces = "application/json")
public User create(@RequestBody UserCreateRequest request) {
return userService.create(request);
}
}
@RequestMapping 还可通过 params、headers、consumes、produces 精确匹配请求。其中 consumes 匹配请求的 Content-Type,produces 约束响应媒体类型并参与内容协商。