Spring Boot参数验证、邮件发送、作业调度、任务简介

🔹 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 查找 UserTransactionTransactionManager
  • 数据源也应通过 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 配置文件

默认查找顺序:

  1. hazelcast.xmlhazelcast.yaml(类路径或当前目录)
  2. 系统属性 hazelcast.config

💡 客户端模式支持:

如果用了 hazelcast-client,优先尝试连接远程集群(而不是启动本地节点)。

查找顺序:

  1. ClientConfig Bean
  2. spring.hazelcast.config 指定的文件
  3. 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简单周期性任务(每小时统计)

✅ 最佳实践建议

  1. 参数校验:Service 层关键方法加 @Validated + 参数约束
  2. 邮件发送:务必设置超时时间,避免线程卡死
  3. 分布式事务:优先选 Atomikos,避免 Bitronix
  4. Hazelcast:适合中小规模分布式缓存,注意配置网络拓扑
  5. Quartz:复杂任务用 Quartz,简单任务用 @Scheduled
  6. 任务线程池:生产环境一定要自定义大小,防 OOM

如果你想深入了解某一部分(比如:“怎么用 Quartz 实现每周一上午9点发周报?”),我可以给出完整代码示例 😊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lang20150928

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值