SpringBoot2.7 + Quartz2.3实战:动态任务调度与集群部署全解析

1. 为什么选择SpringBoot与Quartz的组合?

如果你用过Spring自带的@Scheduled注解,肯定知道它有多方便——加个注解,配个Cron表达式,定时任务就跑起来了。但用久了就会发现几个头疼的问题:任务信息全在代码里,改个时间就得重新部署;没法在运行时动态新增或暂停任务;更别说多台机器一起跑的时候,怎么防止任务被重复执行了。

我刚开始做运维平台的时候,就遇到过这些坑。当时需要给几百台网络设备做定时配置备份,每台设备的备份时间还不一样,用@Scheduled根本搞不定。后来换成了Quartz,才算真正解决了问题。SpringBoot 2.7对Quartz的集成已经非常成熟了,特别是spring-boot-starter-quartz这个starter,省去了大量繁琐的配置。但想把Quartz用得顺手,尤其是需要动态管理任务和集群部署时,有几个关键点必须自己动手处理,比如数据源绑定、Spring Bean注入,还有集群配置。

这篇文章我就结合自己踩过的坑,手把手带你实现一个生产级可用的动态任务调度系统。我会用一个真实的“网络设备定时备份”场景贯穿始终,从单机配置讲到集群部署,把增删改查任务、持久化、故障恢复这些核心功能都覆盖到。代码都是经过线上验证的,你拿过去改改就能用。

2. 环境准备与核心依赖:选对版本,事半功倍

第一步是把依赖和环境准备好。这里我强烈建议你锁定版本,避免以后升级带来不必要的麻烦。我目前用的是SpringBoot 2.7.11和Quartz 2.3.2,这个组合非常稳定。

在你的pom.xml里,需要加上这些依赖:

<!-- SpringBoot Quartz Starter (核心) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

<!-- Druid 数据库连接池 (性能好,监控全) -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.16</version>
</dependency>

<!-- MySQL驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- Hutool工具包 (处理JSON很方便) -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.22</version>
</dependency>

这里有个关键点:Quartz需要自己的数据库表来存储任务和触发器信息spring-boot-starter-quartz虽然能自动建表,但在生产环境我从来不建议用。因为自动建表可能因为权限问题失败,而且你不清楚它到底建了些什么。最稳妥的办法是手动执行官方提供的建表脚本。

你可以在Quartz的核心jar包里找到它:quartz-core-2.3.2.jar!/org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql。把这个脚本拿出来,在你的MySQL数据库里执行一遍。执行完后会看到一堆以QRTZ_开头的表,比如QRTZ_JOB_DETAILSQRTZ_TRIGGERS,这些就是Quartz的“大脑”,所有任务信息都会存在这里。

3. 攻克两大核心难题:数据源绑定与Bean注入

把Quartz整合到SpringBoot里,90%的坑都集中在两个地方:一是Quartz找不到Spring管理的数据源,二是Job类里无法使用@Autowired注入Spring Bean。下面我就分享我的解决方案,这也是本文最核心的部分。

3.1 自定义数据源提供者:让Quartz用上Druid

Quartz默认会用自己的方式去获取数据库连接,但我们的数据源(比如Druid)是由Spring容器管理的。如果不做特殊处理,Quartz就会报错,说找不到数据源。解决思路是:我们写一个中间人(ConnectionProvider),告诉Quartz:“别自己找了,用我这个现成的Druid连接池吧”。

import com.alibaba.druid.pool.DruidDataSource;
import org.quartz.utils.ConnectionProvider;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * 自定义Quartz数据源提供者
 * 作用:将Spring管理的Druid数据源桥接给Quartz使用
 */
@Component
public class DruidQuartzConnectionProvider implements ConnectionProvider {
    private final DruidDataSource dataSource;

    // 通过构造器注入Spring容器里的DruidDataSource
    public DruidQuartzConnectionProvider(DruidDataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Connection getConnection() throws SQLException {
        // 关键:直接从Druid连接池获取连接
        return dataSource.getConnection();
    }

    @Override
    public void shutdown() {
        // 数据源由Spring管理,这里不需要关闭
    }

    @Override
    public void initialize() throws SQLException {
        // 初始化工作由Spring完成,这里留空
    }
}

这个类实现了Quartz的ConnectionProvider接口。getConnection()方法是最关键的,它直接委托给Druid数据源。这样一来,Quartz每次需要操作数据库时,都会通过这个类拿到连接,完美衔接。

3.2 配置Quartz调度器工厂:支持Bean注入的关键

解决了数据源,下一个难题是Bean注入。Quartz在触发任务时,会自己new一个Job实例,这个实例完全在Spring容器之外,所以里面的@Autowired@Resource注解都会失效。我的解决办法是自定义一个JobFactory,在Quartz创建Job实例后,手动把这个实例“塞回”Spring容器,让Spring完成依赖注入。

import org.quartz.Scheduler;
import org.quartz.spi.TriggerFiredBundle;
import org.quartz.utils.DBConnectionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.annotation.PostConstruct;
import java.util.Properties;

@Configuration
public class QuartzConfig {

    @Autowired
    private DruidDataSource dataSource;
    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 初始化阶段,将自定义数据源提供者注册到Quartz
     */
    @PostConstruct
    public void initDataSourcePr
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值