🔹 5.17. Validation(方法参数校验)
✅ 核心概念:
利用 Java 的 Bean Validation 规范(JSR-303 / JSR-380) 来自动校验方法的输入参数或返回值。
只要项目里引入了 Hibernate Validator(最常见的实现),Spring Boot 就会自动启用这个能力。
🎯 使用场景:
你想确保某个方法接收的参数“合法”,比如字符串长度不能小于8。
💡 示例解析:
@Service
@Validated // ← 必须加!否则注解不生效
public class MyBean {
public Archive findByCodeAndAuthor(
@Size(min = 8, max = 10) String code, // 参数校验
Author author) {
...
}
}
@Size(min=8, max=10):表示code字符串必须在 8~10 个字符之间。- 如果调用时传入
"abc"→ 自动抛出异常(ConstraintViolationException) @Validated是 Spring 提供的注解,用于开启“类级别的方法参数校验”
📌 注意:这不是对 Controller 生效的 @Valid,而是对任意 Bean 方法生效!
✅ 常见约束注解:
| 注解 | 说明 |
|---|---|
@NotNull | 不能为 null |
@NotBlank | 字符串不能为空白(非空且去掉空格后不为空) |
@Email | 必须是邮箱格式 |
@Min(8) / @Max(10) | 数字范围 |
@Pattern(regexp="...") | 正则匹配 |
✅ 最佳实践:适用于 Service 层、配置类等需要强类型安全检查的地方。
🔹 5.18. Sending Email(发送邮件)
✅ 核心概念:
Spring 提供了一个统一接口 JavaMailSender 来发送邮件。Spring Boot 对它做了自动配置,只要加上依赖就能用。
📦 依赖引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
⚙️ 自动配置条件:
- 存在
spring.mail.host配置项(如 smtp.gmail.com) - 类路径中有 JavaMail 相关库(starter 已包含)
此时 Spring Boot 会自动创建一个 JavaMailSender Bean。
🛠️ 常见配置(application.yml):
spring:
mail:
host: smtp.gmail.com
port: 587
username: your-email@gmail.com
password: your-app-password
protocol: smtp
properties:
mail:
smtp:
auth: true
starttls:
enable: true
connectiontimeout: 5000 # 连接超时
timeout: 3000 # 读取超时
writetimeout: 5000 # 写入超时
❗重要提示:默认超时是无限的!容易导致线程阻塞 → 所以一定要设置合理的超时时间!
💡 JNDI 支持(高级用法):
如果你部署在 Java EE 服务器上,可以复用已有的邮件 Session:
spring.mail.jndi-name=mail/Session
这时其他所有配置都会被忽略,直接从 JNDI 查找 Session 对象。
🔹 5.19. Distributed Transactions with JTA(分布式事务)
✅ 核心概念:
当你的应用要同时操作 多个数据源(例如两个数据库、一个数据库 + 一个消息队列),并且要求它们要么全部成功、要么全部回滚——这就叫“分布式事务”。
JTA(Java Transaction API)就是解决这个问题的标准方案。
🧩 Spring Boot 支持三种方式:
| 方式 | 描述 | 是否推荐 |
|---|---|---|
| Atomikos | 嵌入式开源事务管理器 | ✅ 推荐 |
| Bitronix | 另一个嵌入式事务管理器 | ⚠️ 已弃用(Spring Boot 2.3+) |
| Java EE 应用服务器内置 | 如 WebLogic、WebSphere 中的 TM | ✅ 部署到企业级容器时使用 |
🔧 Atomikos 使用方式:
1. 添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
2. Spring Boot 自动配置:
- 创建
JtaTransactionManager - 所有
DataSource,JMS ConnectionFactory等资源升级为支持 XA 协议(可参与全局事务) - 你可以继续使用
@Transactional注解
3. 关键配置(application.yml):
spring:
jta:
transaction-manager-id: txID-1 # 每个实例必须唯一(避免冲突)
log-dir: /var/logs/transactions # Atomikos 日志存储位置
Atomikos 会在本地写日志文件来保证崩溃恢复时一致性。
🔄 多资源协调示例:
@Transactional
public void transferMoney() {
accountDao.withdraw("accountA", 100); // DB1
inventoryService.reduceStock("item1"); // DB2 or MQ
}
→ 如果第二步失败,第一步也会回滚,即使跨数据库!
⚠️ Bitronix 注意事项:
- 已被标记为 deprecated
- 不建议新项目使用
- 同样通过 starter 引入,配置类似
🏢 Java EE 容器集成:
如果你把应用打包成 .war 部署到 WebLogic/TomEE/JBoss:
- Spring Boot 会尝试从 JNDI 查找
UserTransaction或TransactionManager - 数据源也应通过 JNDI 获取(由容器管理)
spring:
datasource:
jndi-name: java:/comp/env/jdbc/mydb
🤔 XA vs Non-XA JMS 连接?
有时候你不希望某些 JMS 消息参与分布式事务(比如处理时间太长,超过 XA 超时限制)。
Spring Boot 提供了两种连接工厂:
| Bean 名称 | 用途 |
|---|---|
jmsConnectionFactory (@Primary) | XA 感知,参与分布式事务 |
xaJmsConnectionFactory | 同上(别名) |
nonXaJmsConnectionFactory | 非 XA,独立事务 |
@Autowired
@Qualifier("nonXaJmsConnectionFactory")
private ConnectionFactory nonXaFactory; // 用于不需要XA的场景
🔹 5.20. Hazelcast(分布式缓存)
✅ 核心概念:
Hazelcast 是一个基于内存的分布式数据网格(In-Memory Data Grid),可用于:
- 分布式缓存(替代 Redis 的轻量选择)
- 分布式锁
- 分布式队列/Map/Set
- Session 共享
🧩 Spring Boot 自动配置行为:
| 条件 | 行为 |
|---|---|
类路径有 hazelcast.jar | 自动配置 HazelcastInstance Bean |
存在 com.hazelcast.config.Config Bean | 使用你定义的配置 |
设置 spring.hazelcast.config=classpath:my.xml | 加载指定 XML/YAML 配置文件 |
默认查找顺序:
hazelcast.xml或hazelcast.yaml(类路径或当前目录)- 系统属性
hazelcast.config
💡 客户端模式支持:
如果用了 hazelcast-client,优先尝试连接远程集群(而不是启动本地节点)。
查找顺序:
ClientConfigBeanspring.hazelcast.config指定的文件hazelcast-client.xml/.yaml
🧠 与缓存集成:
如果你启用了缓存(@EnableCaching),并且存在 HazelcastInstance,Spring Boot 会自动将其包装成 CacheManager。
@Cacheable("users")
public User getUser(Long id) { ... }
→ 数据会被缓存在 Hazelcast 中,多个服务实例共享!
🔹 5.21. Quartz Scheduler(定时任务调度)
✅ 核心概念:
Quartz 是一个强大的作业调度框架,比 @Scheduled 更灵活,支持持久化任务、复杂触发规则。
📦 引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
✅ 自动配置功能:
- 创建
SchedulerFactoryBean - 创建并注册
Scheduler实例 - 支持 JobDetail、Trigger、Calendar 的自动装配
🗂️ JobDetail 示例:
@Bean
public JobDetail myJobDetail() {
return JobBuilder.newJob(MyJob.class)
.withIdentity("myJob")
.storeDurably() // 即使没绑定 Trigger 也能保存
.build();
}
🕰️ Trigger 示例(定时规则):
@Bean
public Trigger myTrigger() {
SimpleScheduleBuilder schedule = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever();
return TriggerBuilder.newTrigger()
.forJob(myJobDetail())
.withSchedule(schedule)
.build();
}
💾 持久化任务(JDBC Store):
默认是内存存储,重启就没了。可以用数据库持久化:
spring:
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: always # 启动时初始化表结构
# schema: classpath:custom-quartz.sql # 自定义脚本
需要有
DataSource,Spring Boot 会自动建表(QRTZ_* 开头)
🔄 使用非主数据源?
@Bean
@QuartzDataSource
public DataSource quartzDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(H2)
.setName("quartz")
.build();
}
→ Quartz 会使用这个专用数据源,不影响主业务 DB。
🧩 Job 中注入 Spring Bean:
public class SampleJob extends QuartzJobBean {
private MyService myService;
private String name;
// Spring 会自动注入这些字段
public void setMyService(MyService myService) {
this.myService = myService;
}
public void setName(String name) {
this.name = name;
}
@Override
protected void executeInternal(JobExecutionContext context) {
myService.process(name);
}
}
Quartz 本身不管理 Bean,但 Spring 增强了它,支持依赖注入!
🔹 5.22. Task Execution and Scheduling(异步任务 & 定时任务)
✅ 核心概念:
Spring Boot 帮你轻松搞定两类任务:
| 类型 | 注解 | 用途 |
|---|---|---|
| 异步任务 | @Async | 方法调用不阻塞主线程 |
| 定时任务 | @Scheduled | 每天凌晨清理日志等 |
🧱 默认线程池(TaskExecutor)
如果没有你自己定义的 Executor,Spring Boot 会自动创建一个 ThreadPoolTaskExecutor:
- 核心线程数:8
- 最大线程数:∞(可扩容)
- 队列容量:Int.MaxValue
- Keep-alive 时间:60 秒
适用于大多数场景。
⚙️ 自定义线程池配置(application.yml):
spring:
task:
execution:
pool:
max-size: 16 # 最大线程数
queue-capacity: 100 # 队列最多存100个任务
keep-alive: 10s # 空闲线程10秒后回收
当队列满时才会扩容线程,避免资源浪费。
🔄 MVC 异步请求支持:
Spring MVC 的异步请求(如 DeferredResult, Callable)也需要线程池。
Spring Boot 要求这个线程池是 AsyncTaskExecutor 类型,名字叫 applicationTaskExecutor。
如果你自定义了 Executor,记得让它实现 AsyncTaskExecutor,或者单独提供一个。
🕐 定时任务线程池(@Scheduled)
默认使用单线程的 ThreadPoolTaskScheduler。
可通过以下配置调整:
spring:
task:
scheduling:
pool:
size: 4 # 并发执行的定时任务最多4个
防止多个耗时任务互相阻塞。
🛠️ 构建器支持:
Spring Boot 提供了两个 Builder:
| Builder | 用途 |
|---|---|
TaskExecutorBuilder | 快速创建标准线程池 |
TaskSchedulerBuilder | 快速创建调度线程池 |
方便你在代码中手动构建,复用自动配置的默认值。
✅ 总结对比表
| 功能 | 技术 | 适用场景 |
|---|---|---|
| 参数校验 | Bean Validation + @Validated | 方法参数合法性检查 |
| 发送邮件 | JavaMailSender | 用户注册、通知、报警 |
| 分布式事务 | JTA + Atomikos | 跨多个数据库/消息队列的一致性操作 |
| 分布式缓存 | Hazelcast | 多实例间共享缓存、Session 管理 |
| 作业调度 | Quartz | 复杂定时任务、持久化任务、集群任务 |
| 异步任务 | @Async + TaskExecutor | 解耦耗时操作(如发短信) |
| 定时任务 | @Scheduled + TaskScheduler | 简单周期性任务(每小时统计) |
✅ 最佳实践建议
- 参数校验:Service 层关键方法加
@Validated+ 参数约束 - 邮件发送:务必设置超时时间,避免线程卡死
- 分布式事务:优先选 Atomikos,避免 Bitronix
- Hazelcast:适合中小规模分布式缓存,注意配置网络拓扑
- Quartz:复杂任务用 Quartz,简单任务用
@Scheduled - 任务线程池:生产环境一定要自定义大小,防 OOM
如果你想深入了解某一部分(比如:“怎么用 Quartz 实现每周一上午9点发周报?”),我可以给出完整代码示例 😊
724

被折叠的 条评论
为什么被折叠?



