springboot+dynamic-datasource(多数据源)+quartz(定时任务)

发布于:2025-03-28 ⋅ 阅读:(26) ⋅ 点赞:(0)

1.添加pom文件

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.3.24</version> <!-- 根据你的 Spring 版本调整 -->
        </dependency>

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

        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.15</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

         <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>

2.配置文件
 

server:
  port: 80

spring:
  application:
    name: quartz_demo
  servlet:
    multipart:
      enabled: true
      max-file-size: 200MB
      max-request-size: 200MB
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://192.168.1.42:3306/base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
          username: root
          password: Qazxsw21`
          driver-class-name: com.mysql.cj.jdbc.Driver
        quartz:
          url: jdbc:mysql://192.168.1.43:3306/quartz?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
          username: root
          password: Qazxsw21`
          driver-class-name: com.mysql.cj.jdbc.Driver
      druid:
        initial-size: 8
        min-idle: 1
        max-active: 20
        max-wait: 60000
        time-between-eviction-runsMillis: 60000
        min-evictable-idle-timeMillis: 30000
        validation-query: select 1
        test-while-idle: true
        test-on-borrow: false
        test-on-return: false
        pool-prepared-statements: true
        max-open-prepared-statements: 20
        max-pool-prepared-statement-per-connection-size: 20
        filters: stat
        connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
        use-global-data-source-stat: true
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

org:
  quartz:
    scheduler:
      # 调度器实例名称,用于标识特定的调度器实例
      instanceName: SERVICEX-SCHEDULER-INSTANCE
      # 实例ID,AUTO表示自动生成
      instanceId: AUTO
      instanceIdGenerator:
        # 实例ID生成器类,使用简单的自增ID生成器
        class: org.quartz.simpl.SimpleInstanceIdGenerator
    jobStore:
      # 作业存储方式,使用JDBC事务型存储
      class: org.quartz.impl.jdbcjobstore.JobStoreTX
      # JDBC驱动委托类,标准JDBC实现
      driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
      # 数据库表前缀
      tablePrefix: QRTZ_
      # 是否启用集群模式
      isClustered: true
      # 集群节点检查间隔(毫秒)
      clusterCheckinInterval: 15000
      # 是否将JobDataMap中的值作为字符串存储
      useProperties: false
      # 数据库行锁SQL(针对不同数据库可能需要调整)
      selectWithLockSQL: SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE
    threadPool:
      # 线程池实现类
      class: org.quartz.simpl.SimpleThreadPool
      # 线程池大小
      threadCount: 10
      # 线程优先级(1-10)
      threadPriority: 5
      # 线程是否继承初始化线程的上下文类加载器
      threadsInheritContextClassLoaderOfInitializingThread: true

3.quartz的config文件(这里可以添加动态增删改查任务的方法,具体大家自己找一下,网上很多)

package com.quartz.demo.bootquartz.scheduler;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import org.quartz.Scheduler;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

import java.util.Properties;

/**
 * @ClassName SchedulerConfig
 * @Description 任务调度器
 * @Author LiuJiWei
 * @Date 2025/3/26 星期三
 * @Version 1.0
 */
@Component
@Configuration
public class SchedulerConfig {

    /**
     * 调度器
     */
    private Scheduler scheduler;

    /**
     * 获取调度器
     *
     * @return Scheduler
     * @throws Exception
     */
    @Bean
    public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) {
        scheduler = schedulerFactoryBean.getScheduler();
        return scheduler;
    }
    /**
     * 读取Quartz的配置文件配置
     * 给 schedulerFactory 方法用
     *
     * @return Properties
     * @throws Exception
     */
    @Bean
    public Properties quartzProperties() throws Exception {
        PropertiesFactoryBean factory = new PropertiesFactoryBean();
        factory.setLocation(new ClassPathResource("/application.yml"));
        factory.afterPropertiesSet();
        return factory.getObject();
    }


    /**
     * 配置调度器参数
     *
     * @return SchedulerFactoryBean
     * @throws Exception
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DynamicRoutingDataSource dataSource) throws Exception {
        // 创建调度器工厂Bean
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        // 【重要】设置调度器实例名称(集群环境中用于标识)
        factory.setSchedulerName("Cluster_Quartz_Scheduler");
        // 【关键】设置Quartz使用的数据源(需与quartz.properties中配置一致)
        // 注意:这里从动态数据源中获取名为"quartz"的特定数据源
        factory.setDataSource(dataSource.getDataSource("quartz"));
        // 设置Spring应用上下文在Job中的key
        // 这样在Job实现类中可以通过此key获取Spring上下文
        factory.setApplicationContextSchedulerContextKey("applicationContext");
        // 加载Quartz配置属性(从application.yml中读取)
        factory.setQuartzProperties(quartzProperties());
        // 【线程池配置】设置自定义线程池
        // 注意:如果同时配置了quartz.properties中的线程池,可能会有冲突
        factory.setTaskExecutor(null);
        // 【启动控制】是否自动启动调度器(默认true)
        // 设为false时需要手动调用start()方法
        factory.setAutoStartup(true);
        // 【关键】应用关闭时是否等待任务完成
        // true:优雅停机,会等待正在执行的任务完成
        // false:立即停止,可能中断正在执行的任务
        factory.setWaitForJobsToCompleteOnShutdown(true);
        // 【重要】是否覆盖已存在的Job定义
        // true:启动时覆盖同名的Job/Trigger定义
        // false:发现同名Job时会抛出异常
        factory.setOverwriteExistingJobs(true);
        // 【建议】添加以下额外配置(根据需求):
        // factory.setStartupDelay(10); // 延迟N秒启动(给应用留出初始化时间)
        // factory.setExposeSchedulerInRepository(true); // 集群环境下需要暴露
        return factory;
    }

}

测试添加任务及启动触发
1.任务

package com.quartz.demo.bootquartz.job;

import org.quartz.*;

import java.util.Date;

/**
 * @ClassName QuartzJob
 * @Description 任务1
 * @Author LiuJiWei
 * @Date 2025/3/26 星期三
 * @Version 1.0
 */
@PersistJobDataAfterExecution  // 持久化jobMapData
@DisallowConcurrentExecution   // 禁止任务并发执行
public class QuartzJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            System.out.println("======================Quartz Job executed=============================");
            System.out.println(context.getScheduler().getSchedulerInstanceId());
            System.out.println("任务名称:" + context.getJobDetail().getKey().getName());
            System.out.println("执行时间:" + new Date());
            System.out.println("======================Quartz Job end=============================");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

2.项目启动则触发
 

package com.quartz.demo.bootquartz.trigger;

import com.quartz.demo.bootquartz.job.QuartzJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;


/**
 * @ClassName BootTrigger
 * @Description 任务启动器
 * @Author LiuJiWei
 * @Date 2025/3/26 星期三
 * @Version 1.0
 */
@Component
public class BootTrigger implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private Scheduler scheduler;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // 定义触发器
        TriggerKey triggerKey = TriggerKey.triggerKey("bootTriggerKey", "bootTriggerGroup");
        try {
            // 调度器中获取触发器,如果没有则新建一个触发器
            Trigger trigger = scheduler.getTrigger(triggerKey);
            if (trigger == null) {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(triggerKey)
                        .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
                        .build();
                // 定义要执行的任务
                JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class)
                        .withIdentity("QuartzJobKey", "QuartzJobGroup")
                        .build();
                // 传入调度器并开始执行任务
                scheduler.scheduleJob(jobDetail, trigger);
                scheduler.start();
            }
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

}

3.启动项目

2025-03-27 08:57:02.490  INFO 10536 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 10086 (http) with context path ''
2025-03-27 08:57:02.491  INFO 10536 --- [           main] o.s.s.quartz.SchedulerFactoryBean        : Starting Quartz Scheduler now
2025-03-27 08:57:02.515  INFO 10536 --- [           main] o.s.s.quartz.LocalDataSourceJobStore     : Freed 0 triggers from 'acquired' / 'blocked' state.
2025-03-27 08:57:02.520  INFO 10536 --- [           main] o.s.s.quartz.LocalDataSourceJobStore     : Handling 1 trigger(s) that missed their scheduled fire-time.
2025-03-27 08:57:02.548  INFO 10536 --- [           main] o.s.s.quartz.LocalDataSourceJobStore     : Recovering 0 jobs that were in-progress at the time of the last shut-down.
2025-03-27 08:57:02.548  INFO 10536 --- [           main] o.s.s.quartz.LocalDataSourceJobStore     : Recovery complete.
2025-03-27 08:57:02.550  INFO 10536 --- [           main] o.s.s.quartz.LocalDataSourceJobStore     : Removed 0 'complete' triggers.
2025-03-27 08:57:02.551  INFO 10536 --- [           main] o.s.s.quartz.LocalDataSourceJobStore     : Removed 0 stale fired job entries.
2025-03-27 08:57:02.555  INFO 10536 --- [           main] org.quartz.core.QuartzScheduler          : Scheduler Cluster_Quartz_Scheduler_$_NON_CLUSTERED started.
2025-03-27 08:57:02.568  INFO 10536 --- [           main] com.quartz.demo.QuartzDemoApplication    : Started QuartzDemoApplication in 2.839 seconds (JVM running for 3.393)
======================Quartz Job executed=============================
NON_CLUSTERED
任务名称:QuartzJobKey
执行时间:Thu Mar 27 08:57:02 CST 2025
======================Quartz Job end=============================
======================Quartz Job executed=============================
NON_CLUSTERED
任务名称:QuartzJobKey
执行时间:Thu Mar 27 08:57:05 CST 2025
======================Quartz Job end=============================
======================Quartz Job executed=============================
NON_CLUSTERED
任务名称:QuartzJobKey
执行时间:Thu Mar 27 08:57:10 CST 2025
======================Quartz Job end=============================