Java 入门篇:Spring Boot 3 全栈 Web 开发
背景
Spring Boot 是 Java 生态中最流行的微服务框架,用"约定大于配置"的理念大幅简化了 Spring 应用的搭建。本教程带你构建一个完整的用户管理系统。
核心概念
1. 控制反转(IoC)和依赖注入(DI)
Spring 容器管理 Bean 的生命周期和依赖关系。用 @Autowired(或构造函数注入)声明依赖,Spring 自动装配。
@RestController
public class UserController {
private final UserService service;
public UserController(UserService service) {
this.service = service; // Spring 自动注入
}
}
2. Spring MVC 请求流程
Client → DispatcherServlet → HandlerMapping
→ Controller → Service → Repository → DB
→ 返回 → ViewResolver / HttpMessageConverter
3. 常用注解速查
| 注解 |
作用 |
@SpringBootApplication |
组合了 @Configuration、@EnableAutoConfiguration、@ComponentScan |
@RestController |
组合了 @Controller + @ResponseBody,返回 JSON/文本 |
@GetMapping("/path") |
映射 GET 请求 |
@PathVariable |
提取 URL 路径参数 |
@RequestParam |
提取查询参数 |
@RequestBody |
提取 JSON 请求体 |
@Service |
标记业务逻辑层组件 |
@Repository |
标记数据访问层组件 |
@Transactional |
声明式事务管理 |
分步操作
第一步:创建项目
第二步:三层架构
controller/ ← 接收请求,返回响应
service/ ← 业务逻辑
repository/ ← 数据访问(JPA)
entity/ ← 实体类
dto/ ← 数据传输对象
第三步:实现 Service 层
@Service
@Transactional
public class UserService {
private final UserRepository repo;
public UserService(UserRepository repo) { this.repo = repo; }
public List<UserDTO> findAll() {
return repo.findAll().stream()
.map(UserDTO::fromEntity)
.toList();
}
}
第四步:异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<?> handleNotFound(EntityNotFoundException ex) {
return ResponseEntity.status(404).body(Map.of("error", ex.getMessage()));
}
}
第五步:集成 Swagger/OpenAPI
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.6.0</version>
</dependency>
访问 http://localhost:8080/swagger-ui.html 查看 API 文档。
思考题
@Component、@Service、@Repository 有什么区别?能否互换?
@Transactional 的传播行为(Propagation)有哪些?REQUIRED vs REQUIRES_NEW 的区别?
- Spring Boot 自动配置原理是什么?
@ConditionalOnClass 如何工作?
Java 进阶篇:虚拟线程与并发编程
背景
JDK 21 引入了虚拟线程(Virtual Threads,Project Loom),彻底改变了 Java 的并发模型。与传统平台线程不同,虚拟线程由 JVM 管理,轻量到可以创建百万个。
核心概念
1. 虚拟线程 vs 平台线程
Thread.ofPlatform().start(() -> {
System.out.println("Platform thread: " + Thread.currentThread());
});
Thread.ofVirtual().start(() -> {
System.out.println("Virtual thread: " + Thread.currentThread());
});
2. 使用 ExecutorService
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
var futures = IntStream.range(0, 1000)
.mapToObj(i -> executor.submit(() -> {
Thread.sleep(Duration.ofMillis(100)); // 虚拟线程不阻塞
return "Task " + i + " done";
}))
.toList();
futures.forEach(f -> {
try { System.out.println(f.get()); }
catch (Exception e) { e.printStackTrace(); }
});
}
3. Spring Boot 集成虚拟线程
# application.properties
spring.threads.virtual.enabled=true # Spring Boot 3.2+
@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
return protocolHandler -> protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
}
4. CompletableFuture 进阶
CompletableFuture<String> userFuture =
CompletableFuture.supplyAsync(() -> fetchUser(id), virtualExecutor);
CompletableFuture<Integer> orderFuture =
CompletableFuture.supplyAsync(() -> fetchOrders(id), virtualExecutor);
String result = CompletableFuture
.allOf(userFuture, orderFuture)
.thenApply(v -> String.format(
"用户: %s, 订单数: %d",
userFuture.join(), orderFuture.join()
))
.exceptionally(ex -> "Error: " + ex.getMessage())
.join();
5. 线程安全的集合
Map<String, Integer> map = new HashMap<>();
Map<String, Integer> safeMap = new ConcurrentHashMap<>();
List<String> list = new CopyOnWriteArrayList<>();
Queue<String> queue = new ConcurrentLinkedQueue<>();
虚拟线程最佳实践
| 场景 |
建议 |
| I/O 密集型(HTTP/DB 调用) |
虚拟线程极佳 |
| CPU 密集型 |
用平台线程 + ForkJoinPool |
| 使用 synchronized |
会 pin 住虚拟线程,优先用 ReentrantLock |
| ThreadLocal |
避免大量使用,改用 ScopedValue(JDK 21 preview) |
| 连接池 |
虚拟线程减少连接池压力,但数据库连接池仍需限制 |
思考题
- 虚拟线程为什么不适合 CPU 密集型任务?在什么条件下会 pin 住底层平台线程?
ReentrantLock 和 synchronized 在虚拟线程下的行为有什么区别?
- 如果数据库连接池只有 10 个连接,启动 10000 个虚拟线程同时查询会怎样?