定时任务Quartz

Quartz框架

在这里插入图片描述

  • Quartz三大组件JobDetail,Trigger,Scheduler
  • JobDetail和Trigger可以使用jobDataMap()给job传值

SpringBoot整合Quartz

  1. 创建数据库Quartz关联表(必须)

    
    DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
    DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
    DROP TABLE IF EXISTS QRTZ_LOCKS;
    DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
    DROP TABLE IF EXISTS QRTZ_CALENDARS;
    
    # 1、存储每一个已配置的 jobDetail 的详细信息
    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) 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 NULL,
        PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
    );
    
    # 2、 存储已配置的 Trigger 的信息
    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) NULL,
        NEXT_FIRE_TIME BIGINT(13) NULL,
        PREV_FIRE_TIME BIGINT(13) NULL,
        PRIORITY INTEGER NULL,
        TRIGGER_STATE VARCHAR(16) NOT NULL,
        TRIGGER_TYPE VARCHAR(8) NOT NULL,
        START_TIME BIGINT(13) NOT NULL,
        END_TIME BIGINT(13) NULL,
        CALENDAR_NAME VARCHAR(200) NULL,
        MISFIRE_INSTR SMALLINT(2) NULL,
        JOB_DATA BLOB NULL,
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
            REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
    );
    
    # 3、 存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数
    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),
        FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
            REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    
    # 4、 存储 Cron Trigger,包括 Cron 表达式和时区信息
    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(200) NOT NULL,
        TIME_ZONE_ID VARCHAR(80),
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
            REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    
    # 11、用来存储存储CalendarIntervalTrigger和DailyTimeIntervalTrigger
    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) NULL,
        STR_PROP_2 VARCHAR(512) NULL,
        STR_PROP_3 VARCHAR(512) NULL,
        INT_PROP_1 INT NULL,
        INT_PROP_2 INT NULL,
        LONG_PROP_1 BIGINT NULL,
        LONG_PROP_2 BIGINT NULL,
        DEC_PROP_1 NUMERIC(13,4) NULL,
        DEC_PROP_2 NUMERIC(13,4) NULL,
        BOOL_PROP_1 VARCHAR(1) NULL,
        BOOL_PROP_2 VARCHAR(1) NULL,
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    
    # 5、 Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)
    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 NULL,
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
            REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    
    # 6、 以 Blob 类型存储存放日历信息, quartz可配置一个日历来指定一个时间范围
    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)
    );
    
    # 7、 存储已暂停的 Trigger 组的信息
    CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        TRIGGER_GROUP  VARCHAR(200) NOT NULL,
        PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
    );
    
    # 8、 存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
    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 INTEGER NOT NULL,
        STATE VARCHAR(16) NOT NULL,
        JOB_NAME VARCHAR(200) NULL,
        JOB_GROUP VARCHAR(200) NULL,
        IS_NONCONCURRENT VARCHAR(1) NULL,
        REQUESTS_RECOVERY VARCHAR(1) NULL,
        PRIMARY KEY (SCHED_NAME,ENTRY_ID)
    );
    
    # 9、 存储少量的有关 Scheduler 的状态信息,假如是用于集群中,可以看到其他的 Scheduler 实例
    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)
    );
    
    # 10、 存储程序的悲观锁的信息(假如使用了悲观锁)
    CREATE TABLE QRTZ_LOCKS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        LOCK_NAME  VARCHAR(40) NOT NULL,
        PRIMARY KEY (SCHED_NAME,LOCK_NAME)
    );
    
    
    commit;
    
    
  2. 引入Maven依赖

     <!--quartz依赖-->
    	<dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
    
  3. 新建并编写quartz.properties配置文件

    #调度标识名,集群中每个实例都必须保持一致
    org.quartz.scheduler.instanceName=ClusterQuartz
    
    #ID自动获取,集群节点每一个必须不同
    org.quartz.scheduler.instanceId=AUTO
    
    #是否加入集群,通知Scheduler实例要它参与到一个集群当中
    org.quartz.jobStore.isClustered=true
    
    #集群调度实例失效的检查时间间隔ms
    org.quartz.jobStore.clusterCheckinInterval=5000
    
    #事务是否托管
    org.quartz.jobStore.txIsolationLevelReadCommitted=true
    
    #数据保存方式为数据库持久化
    org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
    
    #数据库代理类
    org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    
    #Quartz表前缀,默认QRTZ_
    org.quartz.jobStore.tablePrefix=QRTZ_
    
    #jobDataMap是否都为String类型,默认false
    org.quartz.jobStore.useProperties=false
    
    #线程池的实现类
    org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
    
    #指定线程数
    org.quartz.threadPool.threadCount=3
    
    #设置线程优先级
    org.quartz.threadPool.threadPriority=5
    
    
    
    
  4. 编写Job任务类继承QuartzJobBean
    (Job任务类中不用使用@Autowired进行自动注入,Job 对象实例化的过程是通过 Quartz 内部自己完成的,但是我们通过 Spring 进行注入的 Bean 却是由 Spring 容器管理的,Quartz 内部无法感知到 Spring 容器管理的 Bean,所以没有办法在创建 Job 的时候就给装配进去。需要手动进行注入NcrReportUtil bean = SpringUtil.getBean(NcrReportUtil.class);)

    @PersistJobDataAfterExecution
    @DisallowConcurrentExecution
    public class QuartzJob extends QuartzJobBean {
        @Override
        protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            try {
                //执行任务
                Thread.sleep(1000);
                System.out.println("taskName="+jobExecutionContext.getJobDetail().getKey().getName()+"   "+LocalDateTime.now());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
  5. 配置调度器Scheduler只需要有一个实例即可

    @Configuration
    public class SchedulerConfig {
    
        @Autowired
        private DataSource dataSource;
    
        @Bean
        public Scheduler scheduler() {
            return this.getSchedulerFactoryBean().getScheduler();
        }
    
        @Bean
        public SchedulerFactoryBean getSchedulerFactoryBean() {
            //配置SchedulerFactoryBean
            SchedulerFactoryBean sc = new SchedulerFactoryBean();
            sc.setApplicationContextSchedulerContextKey("application");
            sc.setSchedulerName("cluster_scheduler");
            sc.setDataSource(dataSource);
            sc.setQuartzProperties(getProperties());
            sc.setTaskExecutor(schedulerThreadPool());
            return sc;
        }
    
    
        public Properties getProperties() {
            try {
                PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
                //设置自定义配置文件的位置
                propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
                //读取quartz配置文件
                propertiesFactoryBean.afterPropertiesSet();
                return propertiesFactoryBean.getObject();
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    
        @Bean
        public Executor schedulerThreadPool() {
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors(), 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
            return threadPoolExecutor;
        }
    }
    
  6. 编写Spring容器启动监听器

    /**
     * 监听springboot容器启动时
     */
    @Component
    public class TaskListener implements ApplicationListener {
        @Autowired
        private Scheduler scheduler;
    
        @Override
        public void onApplicationEvent(ApplicationEvent applicationEvent) {
            try {
           	 	//集群测试任务1
                TriggerKey triggerKey1 = TriggerKey.triggerKey("trigger1", "group1");
                Trigger trigger1 = scheduler.getTrigger(triggerKey1);
                if (trigger1==null){
                    trigger1= TriggerBuilder.newTrigger()
                            .withIdentity(triggerKey1)
                            .withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?"))
                            .startNow()
                            .build();
    
                    JobDetail jobDetail1 = JobBuilder.newJob(QuartzJob.class)
                            .withIdentity("job1", "group1")
                            .build();
                    scheduler.scheduleJob(jobDetail1,trigger1);
                }
    
    			//集群测试任务2
                TriggerKey triggerKey2 = TriggerKey.triggerKey("trigger2", "group2");
                Trigger trigger2 = scheduler.getTrigger(triggerKey2);
                if (trigger2==null){
                    trigger2= TriggerBuilder.newTrigger()
                            .withIdentity(triggerKey2)
                            .withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?"))
                            .startNow()
                            .build();
    
                    JobDetail jobDetail2 = JobBuilder.newJob(QuartzJob.class)
                            .withIdentity("job2", "group2")
                            .build();
                    scheduler.scheduleJob(jobDetail2,trigger2);
                }
                
    			//多个jobDetail时多个scheduleJob()方法,但start()方法只用执行一次。
                scheduler.start();
    
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    }
    

一般job类都要加上这两个注解

@DisallowConcurrentExecution: Quartz默认是多线程并发执行job,每次都会创建新的job和JobDetail实例,上一次任务如果没执行完,后面的也不会等它。如果想只能有一个在执行可以在job类上使用@DisallowConcurentExecution

@PersistJobDataAfterExecution: job类上加@PersistJobDataAfterExecution:保持JobDetail中的jobDataMap()持久化,既只有一个实例。但对Trigger的无效。

Quartz集群

集群节点互相不通讯,要通过数据库表来实现集群的通讯。

Quartz集群原理:一个jobDetail和Trigger会自动分配给一个集群节点,而不是一个任务上一次执行在一个节点下一次执行又跑到另一个节点了。
(一个jobDetail就会在一个集群节点上执行,如果有多个jobDetail且有多个集群节点才会自动分配,但如果有多个jobDetail但只有一个集群节点,活就只能那一个节点全揽了)

同一个集群中,由于通过数据库实现高可用,就算每个集群节点定时任务的代码不一样也不会影响,Quartz还是会平均分配任务。

在这里插入图片描述
在这里插入图片描述

注意事项

定时任务的 Job 对象实例化的过程是通过 Quartz 内部自己完成的,但是我们通过 Spring 进行注入的 Bean 却是由 Spring 容器管理的,Quartz 内部无法感知到 Spring 容器管理的 Bean,所以没有办法在创建 Job 的时候就用@Autowired给装配进去。解决办法是需要手动注入Bean: NcrReportUtil bean = SpringUtil.getBean(NcrReportUtil.class);

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 好的,下面是关于使用Spring BootQuartz实现定时任务的简介: Quartz是一个流行的Java定时任务框架,可以在应用程序中执行各种定时任务,如定期备份、数据抽取和数据分析等。而Spring Boot是一个快速开发框架,提供了方便的集成Quartz的方式。 要使用Spring BootQuartz实现定时任务,首先需要在pom.xml文件中添加QuartzSpring Boot Quartz的依赖项。然后,定义一个定时任务,可以使用注解@Scheduled来指定任务的执行时间。例如: ```java @Component public class MyScheduler { @Scheduled(cron = "0 0/10 * * * ?") public void myTask() { //执行定时任务的代码 } } ``` 上述代码表示每隔10分钟执行一次myTask()方法。然后,在Spring Boot的主类中,使用@EnableScheduling注解来开启定时任务的支持。例如: ```java @SpringBootApplication @EnableScheduling public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } } ``` 最后,启动应用程序,定时任务将按照预定时间自动执行。如果需要更高级的定时任务控制,还可以使用Quartz的其他功能,如JobDetail和Trigger等。 ### 回答2: SpringBoot是一个开源的Java开发框架,它提供了很多有用的工具和插件,其中之一便是定时任务quartzquartz是一款功能强大的开源调度框架,它提供了简单易用的任务调度机制,支持多线程和分布式部署,可以满足大部分的调度需求。 在SpringBoot中,我们可以很方便地使用quartz来实现定时任务。以下是使用SpringBootquartz实现定时任务的基本步骤: 1. 在pom.xml文件中添加quartz的依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ``` 2. 创建一个任务类,实现Job接口,并实现execute方法来定义任务逻辑: ``` @Component public class MyTask implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { // 定时任务的执行逻辑 } } ``` 3. 在配置文件中定义任务调度器,并为任务分配cron表达式: ``` spring: quartz: job-store-type: jdbc properties: org.quartz.scheduler.instanceName: MyScheduler org.quartz.threadPool.threadCount: 5 job-details: myJob: durability: true requestsRecovery: true trigger-details: myTrigger: cron: 0 0/1 * * * ? job-name: myJob job-data-map: name: world ``` 4. 在任务执行类中,使用@Scheduled注解来指定任务的执行时间: ``` @Component public class MyTask { @Scheduled(cron = "0 0/1 * * * ?") public void doTask(){ // 定时任务的执行逻辑 } } ``` 以上4种方法都是使用SpringBootquartz实现定时任务的简单示例,根据实际需求可以进行相应调整和扩展。总的来说,使用springbootquartz实现定时任务非常方便,能够让我们更加轻松地管理、调度和执行任务,提高开发效率和质量。 ### 回答3: Spring Boot是一款快速构建基于Spring应用的工具,可帮助简化开发和部署。在Spring Boot中,与Quartz相比,Scheduled定时任务通常是首选的。但是,Quartz比Scheduled更灵活、功能更强大、配置更灵活,因此在一些特殊情况下,使用Quartz进行定时任务调度是比较必要的。 Quartz是用Java语言编写的一个开源的调度框架,其主要用于在一个预定义的时间间隔内重复执行某个任务,或者在特定时间点执行某个任务。Quartz提供了众多功能,比如支持分布式定时任务管理、支持动态创建/删除任务、支持时间表达式、状态存储、监控和事件触发等等。 Spring Boot集成了Quartz非常容易,只需要在Spring Boot项目中添加Quartz相关依赖,在Spring Boot配置文件中增加Quartz配置即可。以下是一个完整的Spring Boot集成Quartz的示例代码: 1.在pom.xml中添加QuartzSpring Boot Starter Web依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> ``` 2.在配置文件中增加Quartz相关配置: ``` spring.quartz.job-store-type=memory spring.quartz.properties.org.quartz.threadPool.threadCount=10 spring.quartz.properties.org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore ``` 3.编写定时任务处理类: ``` @Component public class JobScheduler { @Autowired private Scheduler scheduler; @Scheduled(cron = "0 0/1 * * * ?") public void doSomething() { JobDetail jobDetail = buildJobDetail(); Trigger trigger = buildJobTrigger(jobDetail); try { scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException e) { e.printStackTrace(); } } private JobDetail buildJobDetail() { JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("key", "value"); return JobBuilder.newJob(Job.class) .withIdentity(UUID.randomUUID().toString(), "job-group") .withDescription("sample job") .usingJobData(jobDataMap) .storeDurably(true) .build(); } private Trigger buildJobTrigger(JobDetail jobDetail) { return TriggerBuilder.newTrigger() .forJob(jobDetail) .withIdentity(UUID.randomUUID().toString(), "trigger-group") .withDescription("sample trigger") .withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * * * ?")) .build(); } } ``` 虽然Quartz需要对定时任务进行配置,但是它提供了更为灵活的条件和任务调度,非常适合在实际生产环境中使用。总之,使用Spring Boot集成Quartz可以非常方便地实现定时任务的调度,既简单又强大,可以大大提高应用的效率和可靠性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值