quartz 定时框架整合多数据源

本文介绍了如何在Spring Boot项目中整合Quartz以支持多数据源的定时任务。通过引入相关依赖并配置Quartz,使得每个数据源都能拥有独立的定时任务。同时,利用注解定义任务并在启动时自动初始化,以及通过监听器在任务执行前切换数据源,确保任务执行时使用正确数据源。
摘要由CSDN通过智能技术生成

一、前言

最近,因为saas系统需要支持 租户可配置数据源的需求,所以将系统改造为多数据源,从而也对定时任务进行改造。

二、代码实现

1、整合quartz

在项目工程中引入对应的包。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
        </dependency>

        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
        </dependency>

2、关于quartz的配置

以下是quartz的配置,由于quartz 需要数据库库存储定时任务数据,所以在配置的时候,需要配置一个主数据源,用于储存任务信息。

spring:
  quartz:
    # 使用数据库存储
    job-store-type: jdbc
    # 相同 Scheduler 名字的节点,形成一个 Quartz 集群
#    scheduler-name: scheduler
    # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
    wait-for-jobs-to-complete-on-shutdown: true
    #配置的作业是否应覆盖现有的作业定义
    overwrite-existing-jobs: true
    jdbc:
      # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。
      initialize-schema: never
    properties:
      org:
        quartz:
          # JobStore 相关配置
          jobStore:
            # 使用的数据源
            dataSource: demo
            # JobStore 实现类
            class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            # Quartz 表前缀
            tablePrefix: QRTZ_
            # 是集群模式
            isClustered: true
            clusterCheckinInterval: 1000
            useProperties: false
          # 线程池相关配置
          threadPool:
            # 线程池大小。默认为 10threadCount: 25
            # 线程优先级
            threadPriority: 5
            # 线程池类型
            class: org.quartz.simpl.SimpleThreadPool
          scheduler:
            # 调度标识名 集群中每一个实例都必须使用相同的名称
            # 相同 Scheduler 名字的节点,形成一个 Quartz 集群
            instanceName: scheduler
            # ID设置为自动获取 每一个必须不同
            instanceId: AUTO
            #指定调度程序的主线程是否应该是守护线程
            makeSchedulerThreadDaemon: true

2、job的生成

在多数据源的情况需要根据不同的数据源生成多份job,然后在job执行时需要切换不同的数据源。

2.1

在此我们先定义一个注解,然后在程序启动的时候将带有该注解的任务全部初始化生成任务

@Target(ElementType.TYPE)
@Documented
public @interface QuartzJob {

    String name() default "";

    String cron() default "";

    String desc() default "";

}

2.2 初始化所有任务

在定义完注解类以后,这时候就需要一个loader 将业务代码中包含改注解的类转化成quartz 任务

/**
 * * 任务加载器
 * * 将所有的任务 初始化
 */
@Slf4j
public class JobLoader {


    private ApplicationContext context;


    private DynamicDataSourceProvider dynamicDataSourceProvider;


    private JobManagement jobManagement;


    public void init() {
        Map<String, Object> quartzJobMap = context.getBeansWithAnnotation(QuartzJob.class);

        Map<String, DataSource> dataSourceMap = dynamicDataSourceProvider.loadDataSources();

        if (!ObjectUtils.isEmpty(quartzJobMap) || ObjectUtils.isEmpty(dataSourceMap)) {
            dataSourceMap.keySet().forEach(sourceName -> {
                log.info("========== init  job  start  tenantId is {}  ==============", sourceName);
                quartzJobMap.values().forEach(job -> {
                    QuartzJob quartzJob = job.getClass().getAnnotation(QuartzJob.class);
                    if (ObjectUtils.isEmpty(quartzJob)){
                        log.error("loader job is fial !! jobClass is {}", job.getClass().getName());
                    }
                    try {
                        jobManagement.addJob(JobInfo.builder().jobName(sourceName + "-" + quartzJob.name())
                                .groupName(sourceName).desc(quartzJob.desc())
                                .beanClasz(quartzJob.jobClass()).cronStr(quartzJob.cron()).dataSourceName(sourceName).build());
                    } catch (SchedulerException e) {
                        log.error("add job is fial!! raeson:{}", e.getMessage());
                    }catch (Exception e){
                        log.error("add job is fial!! raeson:{}", e.getMessage());
                    }
                });
                log.info("========== init  job  is completed   tenantId is {}  ==============", sourceName);
            });
        }
    }

}

2.3 添加监听器

在我们初始化任务以后,则是到了最重要一个环节,就是怎么在每个任务执行的时候去切换数据源。在此我使用了 quartz的 监听器,在每个任务执行前去做件事情。

/**
 * * 任务监听器
 * *
 */
@Slf4j
public class SchedulerListener implements JobListener {

    @Override
    public String getName() {
        return JobDataKeyContant.DEFULT_SCHEDULER_NAME;
    }

    @Override
    public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
        String dataSourceName = jobExecutionContext.getJobDetail().getJobDataMap().getString(JobDataKeyContant.DATA_SOURCE);
        DynamicDataSourceContextHolder.push(dataSourceName);
        log.info("quartz job is excutting !  jobName: {},dataSource: {}", jobExecutionContext.getJobDetail().getKey().toString(), dataSourceName);
    }
    }
}

至此 整个功能实现就完成了。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Resean0223

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

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

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

打赏作者

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

抵扣说明:

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

余额充值