• Springboot集成Quartz实现分布式任务调度


    注明:本文只是在项目中使用的过程当中解决问题才提出的解决方案,可能并不适配所有人的项目解决方案,仅作参考!

    附上博主在Github上的一个项目,不定时更新哟-->欢迎fork、star。欢迎关注博主哟: https://github.com/yarcl/SpringbootDemo

    注意:该项目当中所有内容均在项目当中存在,安装完数据、配置好后,直接使用即可。

    包含内容:

    a、双数据源配置

    b、quartz任务调度

    c、vue前端访问数据绑定

    ......

    1、Springboot集成Quartz,首先必须要完成的功能是搭建Springboot的项目。保证项目可以正常运行。

    目录结构如下图所示:

    2、加入Quartz的依赖关系

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

    3、加入依赖之后,在resources目录下增加quartz.properties文件,文件内容如下:

    org.quartz.jobStore.useProperties=false
    org.quartz.jobStore.tablePrefix=QRTZ_
    org.quartz.jobStore.isClustered=true
    org.quartz.jobStore.clusterCheckinInterval=5000
    org.quartz.jobStore.misfireThreshold=600000
    org.quartz.jobStore.txIsolationLevelReadCommitted=true
    org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
    org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    
    org.quartz.scheduler.instanceName=ClusterQuartz
    org.quartz.scheduler.instanceId=AUTO
    org.quartz.scheduler.rmi.export=false
    org.quartz.scheduler.rmi.proxy=false
    org.quartz.scheduler.wrapJobExecutionInUserTransaction=false
    
    org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
    org.quartz.threadPool.threadCount=5
    org.quartz.threadPool.threadPriority=9
    org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
    # 解决多次触发问题
    org.quartz.jobStore.acquireTriggersWithinLock=true

    4、当前配置需要进行数据存储触发内容和触发时间节点,需要创建quartz所需要的表,当然也可以去官网进行下载后查看对应的脚本文件:

    CREATE TABLE `QRTZ_BLOB_TRIGGERS` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `TRIGGER_NAME` varchar(200) NOT NULL,
      `TRIGGER_GROUP` varchar(200) NOT NULL,
      `BLOB_DATA` blob,
      PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
      KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
      CONSTRAINT `QRTZ_BLOB_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    CREATE TABLE `QRTZ_CALENDARS` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `CALENDAR_NAME` varchar(200) NOT NULL,
      `CALENDAR` blob NOT NULL,
      PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    CREATE TABLE `QRTZ_CRON_TRIGGERS` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `TRIGGER_NAME` varchar(200) NOT NULL,
      `TRIGGER_GROUP` varchar(200) NOT NULL,
      `CRON_EXPRESSION` varchar(120) NOT NULL,
      `TIME_ZONE_ID` varchar(80) DEFAULT NULL,
      PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
      CONSTRAINT `QRTZ_CRON_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    CREATE TABLE `QRTZ_FIRED_TRIGGERS` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `ENTRY_ID` varchar(95) NOT NULL,
      `TRIGGER_NAME` varchar(200) NOT NULL,
      `TRIGGER_GROUP` varchar(200) NOT NULL,
      `INSTANCE_NAME` varchar(200) NOT NULL,
      `FIRED_TIME` bigint(13) NOT NULL,
      `SCHED_TIME` bigint(13) NOT NULL,
      `PRIORITY` int(11) NOT NULL,
      `STATE` varchar(16) NOT NULL,
      `JOB_NAME` varchar(200) DEFAULT NULL,
      `JOB_GROUP` varchar(200) DEFAULT NULL,
      `IS_NONCONCURRENT` varchar(1) DEFAULT NULL,
      `REQUESTS_RECOVERY` varchar(1) DEFAULT NULL,
      PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`),
      KEY `IDX_QRTZ_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`),
      KEY `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),
      KEY `IDX_QRTZ_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
      KEY `IDX_QRTZ_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),
      KEY `IDX_QRTZ_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
      KEY `IDX_QRTZ_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    CREATE TABLE `QRTZ_JOB_DETAILS` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `JOB_NAME` varchar(200) NOT NULL,
      `JOB_GROUP` varchar(200) NOT NULL,
      `DESCRIPTION` varchar(250) DEFAULT NULL,
      `JOB_CLASS_NAME` varchar(250) NOT NULL,
      `IS_DURABLE` varchar(1) NOT NULL,
      `IS_NONCONCURRENT` varchar(1) NOT NULL,
      `IS_UPDATE_DATA` varchar(1) NOT NULL,
      `REQUESTS_RECOVERY` varchar(1) NOT NULL,
      `JOB_DATA` blob,
      PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
      KEY `IDX_QRTZ_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),
      KEY `IDX_QRTZ_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    CREATE TABLE `QRTZ_LOCKS` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `LOCK_NAME` varchar(40) NOT NULL,
      PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `TRIGGER_GROUP` varchar(200) NOT NULL,
      PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    CREATE TABLE `QRTZ_SCHEDULER_STATE` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `INSTANCE_NAME` varchar(200) NOT NULL,
      `LAST_CHECKIN_TIME` bigint(13) NOT NULL,
      `CHECKIN_INTERVAL` bigint(13) NOT NULL,
      PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    CREATE TABLE `QRTZ_SIMPLE_TRIGGERS` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `TRIGGER_NAME` varchar(200) NOT NULL,
      `TRIGGER_GROUP` varchar(200) NOT NULL,
      `REPEAT_COUNT` bigint(7) NOT NULL,
      `REPEAT_INTERVAL` bigint(12) NOT NULL,
      `TIMES_TRIGGERED` bigint(10) NOT NULL,
      PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
      CONSTRAINT `QRTZ_SIMPLE_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `TRIGGER_NAME` varchar(200) NOT NULL,
      `TRIGGER_GROUP` varchar(200) NOT NULL,
      `STR_PROP_1` varchar(512) DEFAULT NULL,
      `STR_PROP_2` varchar(512) DEFAULT NULL,
      `STR_PROP_3` varchar(512) DEFAULT NULL,
      `INT_PROP_1` int(11) DEFAULT NULL,
      `INT_PROP_2` int(11) DEFAULT NULL,
      `LONG_PROP_1` bigint(20) DEFAULT NULL,
      `LONG_PROP_2` bigint(20) DEFAULT NULL,
      `DEC_PROP_1` decimal(13,4) DEFAULT NULL,
      `DEC_PROP_2` decimal(13,4) DEFAULT NULL,
      `BOOL_PROP_1` varchar(1) DEFAULT NULL,
      `BOOL_PROP_2` varchar(1) DEFAULT NULL,
      PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
      CONSTRAINT `QRTZ_SIMPROP_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    CREATE TABLE `QRTZ_TRIGGERS` (
      `SCHED_NAME` varchar(120) NOT NULL,
      `TRIGGER_NAME` varchar(200) NOT NULL,
      `TRIGGER_GROUP` varchar(200) NOT NULL,
      `JOB_NAME` varchar(200) NOT NULL,
      `JOB_GROUP` varchar(200) NOT NULL,
      `DESCRIPTION` varchar(250) DEFAULT NULL,
      `NEXT_FIRE_TIME` bigint(13) DEFAULT NULL,
      `PREV_FIRE_TIME` bigint(13) DEFAULT NULL,
      `PRIORITY` int(11) DEFAULT NULL,
      `TRIGGER_STATE` varchar(16) NOT NULL,
      `TRIGGER_TYPE` varchar(8) NOT NULL,
      `START_TIME` bigint(13) NOT NULL,
      `END_TIME` bigint(13) DEFAULT NULL,
      `CALENDAR_NAME` varchar(200) DEFAULT NULL,
      `MISFIRE_INSTR` smallint(2) DEFAULT NULL,
      `JOB_DATA` blob,
      PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
      KEY `IDX_QRTZ_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
      KEY `IDX_QRTZ_T_JG` (`SCHED_NAME`,`JOB_GROUP`),
      KEY `IDX_QRTZ_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),
      KEY `IDX_QRTZ_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),
      KEY `IDX_QRTZ_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),
      KEY `IDX_QRTZ_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
      KEY `IDX_QRTZ_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
      KEY `IDX_QRTZ_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),
      KEY `IDX_QRTZ_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),
      KEY `IDX_QRTZ_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),
      KEY `IDX_QRTZ_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
      KEY `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
      CONSTRAINT `QRTZ_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

     注:或者去官网http://www.quartz-scheduler.org/downloads/下载对应的版本下,有如下的目录:也可以直接使用该脚本

    5、接下来可以配置数据源,如果项目当中已有对应表数据库的数据源,则可以直接使用,如果没有数据源,则需要用以下代码创建数据源

    package com.yarcl.crm.biz.util;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import javax.sql.DataSource;
    import java.beans.PropertyVetoException;
    /**
    * Created by xiaozhi on 2019/2/25.
    */
    @Configuration
    public class DataSourceConfig {
    
        @Value("${spring.datasource.url}")
        private String url;
    
        @Value("${spring.datasource.password}")
        private String password;
    
        @Value("${spring.datasource.username}")
        private String username;
    
        @Value("${spring.datasource.driverClassName}")
        private String driverClassName;
    
        @Bean("dataSourceBean")
        public DataSource dataSource() throws PropertyVetoException {
            ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
            comboPooledDataSource.setJdbcUrl(url);
            comboPooledDataSource.setDriverClass(driverClassName);
            comboPooledDataSource.setUser(username);
            comboPooledDataSource.setPassword(password);
            comboPooledDataSource.setInitialPoolSize(3);
            comboPooledDataSource.setMaxPoolSize(5);
            comboPooledDataSource.setMinPoolSize(3);
            return comboPooledDataSource;
        }
    }

    注:注解内容请自行参考Springboot注解说明

    6、配置Quartz的job配置类,如下代码:

    package com.yarcl.crm.biz.quartz;
    
    import org.quartz.spi.TriggerFiredBundle;
    import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.scheduling.quartz.SpringBeanJobFactory;
    import org.springframework.stereotype.Component;
    
    /**
    * Created by xiaozhi on 2019/2/25.
    */
    @Component
    public class SchedulerQuartzJob extends SpringBeanJobFactory implements ApplicationContextAware {
    
        private transient AutowireCapableBeanFactory beanFactory;
    
        @Override
        public void setApplicationContext(final ApplicationContext context) {
            beanFactory = context.getAutowireCapableBeanFactory();
        }
    
        @Override
        protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
            final Object job = super.createJobInstance(bundle);
            beanFactory.autowireBean(job);
            return job;
        }
    
    }

    7、配置Quartz的配置类,如下代码:

    package com.yarcl.crm.biz.util;
    import com.yarcl.crm.biz.quartz.SchedulerQuartzJob;
    import org.springframework.beans.factory.annotation.Autowired;
    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.concurrent.ThreadPoolTaskExecutor;
    import org.springframework.scheduling.quartz.SchedulerFactoryBean;
    
    import javax.sql.DataSource;
    import java.io.IOException;
    import java.util.Properties;
    
    /**
    * Created by xiaozhi on 2019/2/25.
    */
    @Configuration
    public class SchedulerQuartzConfig {
    
        @Autowired
        private SchedulerQuartzJob schedulerQuartzJob;
    
        @Autowired
        private DataSource dataSourceBean;
    
        @Bean(name = "schedulerFactoryBean")
        public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
            //获取配置属性
            PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
            propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
            //在quartz.properties中的属性被读取并注入后再初始化对象
            propertiesFactoryBean.afterPropertiesSet();
            //创建SchedulerFactoryBean
            SchedulerFactoryBean factory = new SchedulerFactoryBean();
            Properties pro = propertiesFactoryBean.getObject();
            factory.setOverwriteExistingJobs(true);
            factory.setDataSource(dataSourceBean);
    
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(10);
            executor.setMaxPoolSize(20);
            executor.setQueueCapacity(100);
    
            factory.setTaskExecutor(executor);
            factory.setAutoStartup(true);
            factory.setQuartzProperties(pro);
            factory.setJobFactory(schedulerQuartzJob);
            return factory;
        }
    }

     8、配置完应有的相关配置内容之后,如果需要执行任务,则任务的处理逻辑必须实现org.quartz.Job接口,代码如下:

    package com.yarcl.crm.biz.quartz;
    
    import com.yarcl.crm.biz.homepage.dao.HomepageDao;
    import com.yarcl.crm.biz.model.scheduler.SchedulerDo;
    import com.yarcl.crm.biz.model.scheduler.SchedulerVo;
    import com.yarcl.crm.biz.service.scheduler.SchedulerService;
    import lombok.extern.slf4j.Slf4j;
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.quartz.JobKey;
    import org.springframework.beans.factory.annotation.Autowired;
    
    /**
     * Created by xiaozhi on 2019/2/25.
     */
    @Slf4j
    public class CronJob implements Job {
    
        @Autowired
        private JobService jobService;
    
        @Autowired
        private SchedulerService schedulerService;
    
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            // 获取job的名称和group
            String jobName = jobExecutionContext.getJobDetail().getKey().getName();
            String jobGroup = jobExecutionContext.getJobDetail().getKey().getGroup();
            Object obj = jobExecutionContext.getMergedJobDataMap().get("executeClass");
            Object objFun = jobExecutionContext.getMergedJobDataMap().get("executeFunction");
            boolean isTrue = SchedulerDo.class.getSimpleName().equals(obj);
            if(isTrue) {
                SchedulerDo sDo = (SchedulerDo)objFun;
                Long id = sDo.getId();boolean isExist = schedulerService.findExistById(id);
                if(isExist) {
                    schedulerService.sendMessage(sDo);
                } else {
                    log.error("The schedule has been deleted when it is cron.");
                }
            }
            // 及时删除任务
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
            if(null != jobKey) {
                jobService.deleteJob(jobName, jobGroup);
            }
        }
    }

    9、添加一个job任务:

    public class JobServiceImpl {
       // 注入定时任务调度类
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired private SchedulerFactoryBean schedulerFactoryBean; /** * 创建一个定时任务 * @param jobName * @param jobGroup */public String addCronJob(String jobName, String jobGroup, SchedulerDo schedulerDo) { try { jobName = jobName+schedulerDo.getRemindDt().getTime()+ UUID.randomUUID(); String dateCron = new SimpleDateFormat("ss mm HH dd MM ? yyyy").format(schedulerDo.getRemindDt());        // 定时调度任务主题-1、构建定时任务调度器 Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobKey jobKey = JobKey.jobKey(jobName, jobGroup); JobDetail jobDetail = scheduler.getJobDetail(jobKey); if (jobDetail == null) { // 定时调度任务主题-2、构建job信息 jobDetail = JobBuilder.newJob(CronJob.class).withIdentity(jobName, jobGroup).build(); //用JopDataMap来传递数据 jobDetail.getJobDataMap().put("executeClass", SchedulerDo.class.getSimpleName()); jobDetail.getJobDataMap().put("executeFunction", schedulerDo); //表达式调度构建器(即任务执行的时间) CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(dateCron); // 定时调度任务主体-3、按新的cronExpression表达式构建一个新的trigger CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName + "_trigger", jobGroup + "_trigger") .withSchedule(scheduleBuilder).build();
              // 开启调度 scheduler.scheduleJob(jobDetail, trigger); } } catch (Exception e) { e.printStackTrace(); } return jobName; }
    }

    10、通过调用JobServiceImpl代码则可以实现向Quartz任务调度器持久化一个具体时间的调度。当前例子只适用于初学者进行实验性学习,不具有通用性.

    学习、成长
  • 相关阅读:
    实验三 敏捷开发与XP实践
    20145201 《信息安全系统设计基础》第3周学习总结
    20145201 《信息安全系统设计基础》第2周学习总结
    20145201 《信息安全系统设计基础》第1周学习总结
    20145201 《信息安全系统设计基础》第0周学习总结
    20145201《Java程序设计》课程总结
    20145201《Java程序设计》第五次实验报告
    20145201《Java程序设计》第十周学习总结
    20145201《Java程序设计》第九周学习总结
    20145201 实验四 Andoid开发基础
  • 原文地址:https://www.cnblogs.com/yarcl/p/11100037.html
Copyright © 2020-2023  润新知