springBoot整合Quartz定时任务

1.Quartz简介(可参考官方文档https://www.w3cschool.cn/quartz_doc/quartz_doc-1xbu2clr.html)

//DSL静态导入
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
//下面的事调度器的接口的DSL静态导入
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.CalendarIntervalScheduleBuilder.*;


SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();

Scheduler sched = schedFact.getScheduler();

sched.start();

//实例化一个job
JobDetail job = newJob(HelloJob.class)
      .withIdentity("myJob", "group1")
      .build();

//实例化trigger(40秒执行一次,永远执行)
 Trigger trigger = newTrigger()
      .withIdentity("myTrigger", "group1")
      .startNow()
      .withSchedule(simpleSchedule()
          .withIntervalInSeconds(40)
          .repeatForever())
      .build();

//启动调度任务
sched.scheduleJob(job, trigger);

 Quartz是一个任务调度框架,可以定时的去做某一件事情.

       1.  Scheduler:调度器。所有的调度都是由它控制

                          (1) 生命周期:SchedulerFactory创建它时开始,Scheduler只有在调用start()方法后,才会真正地触发trigger(即执行job),到Scheduler调用shutdown()方法时结束,Scheduler被创建后,可以增加、删除和列举Job和Trigger,以及执行其它与调度相关的操作(如暂停Trigger)。

                           (2)实例化: SchedulerBuilder接口的各种实现类,可以定义不同类型的调度计划(schedule)

 2.  Trigger: 定义触发的条件    

                       (1)了解Trigger:Trigger用于触发Job的执行。当你准备调度一个job时,你创建一个Trigger的实例,然后设置调度相关的属性。

                       (2)区分类型: SimpleTrigger和CronTrigger

                                      SimpleTrigger主要用于一次性执行的Job(只在某个特定的时间点执行一次),或者Job在特定的时间点执行,重复执行N次,每次执行间隔T个时间单位。

                                     CronTrigger在基于日历的调度上非常有用,如“每个星期五的正午”,或者“每月的第十天的上午10:15”等。  

                       (3)Trigger的公共属性 (构建trigger的时候可以通过TriggerBuilder设置)

                                     TriggerKey属性: 表示trigger的身份

                                     jobKey属性:当trigger触发时被执行的job的身份

                                     startTime属性:设置trigger第一次触发的时间;该属性的值是java.util.Date类型,表示某个指定的时间点;有些类型的trigger,会在设置的startTime时立即触发,有些类型的trigger,表示其触发是在startTime之后开始生效

                                      endTime属性:表示trigger失效的时间点

                                      priority属性: 优先级       注意: (只有同时触发的trigger之间才会比较优先级。10:59触发的trigger总是在11:00触发的trigger之行。如果trigger是可恢复的,在恢复后再调度时,优先级与原trigger是一样的。)

                                     misfire Instructions属性: 错过触发

                                     calendar属性: 日历示例(Quartz的Calendar对象(不是java.util.Calendar对象)可以在定义和存储trigger的时候与trigger进行关联。Calendar用于从trigger的调度计划中排除时间段。------参考官网)

       3.  JobDetail:  定义的是任务数据,真正的执行逻辑是在Job中,JobDetail & Job 方式,sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。

JobDetail job = newJob(HelloJob.class)
      .withIdentity("myJob", "group1")  //定义job的身份 key,分组
      .build();

  4.  Job: 调度程序执行组件的接口

          (1):Job接口的execute方法

public class HelloJob implements Job {

    public HelloJob() {
    }

    public void execute(JobExecutionContext context)
      throws JobExecutionException
    {
      System.err.println("Hello!  HelloJob is executing.");
    }
  }

          (2):如何给job实例增加属性或配置(JobDataMap,JobDetail对象的一部分).

                      JobDataMap: JobDataMap中可以包含不限量的(序列化的)数据对象,在job实例执行的时候,可以使用其中的数据;JobDataMap是Java Map接口的一个实现,额外增加了一些便于存取基本类型的数据的方法。

                       将job加入到scheduler之前,在构建JobDetail时,可以将数据放入JobDataMap.

JobDetail job = newJob(DumbJob.class)
      .withIdentity("myJob", "group1") // name "myJob", group "group1"
      .usingJobData("jobSays", "Hello World!")  //JobDataMap存放数据
      .usingJobData("myFloatValue", 3.141f) JobDataMap存放数据
      .build();

           在job的执行过程中,可以从JobDataMap中取出数据使用

public class DumbJob implements Job {
    public DumbJob() {
    }

    public void execute(JobExecutionContext context)
      throws JobExecutionException
    {
     //去JobDetail的key值
      JobKey key = context.getJobDetail().getKey();
        //从JobDataMap取值
      JobDataMap dataMap = context.getJobDetail().getJobDataMap();

      String jobSays = dataMap.getString("jobSays");
      float myFloatValue = dataMap.getFloat("myFloatValue");

      System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
    }
  }

注意:JobDataMap中存储的对象都会被序列化,因此很可能会导致类的版本不一致的问题

在Job执行时,JobExecutionContext中的JobDataMap为我们提供了很多的便利。它是JobDetail中的JobDataMap和Trigger中的JobDataMap的并集,但是如果存在相同的数据,则后者会覆盖前者的值。

  JobFactory也可以实现数据的自动“注入”

 public class DumbJob implements Job {


    String jobSays;
    float myFloatValue;
    ArrayList state;

    public DumbJob() {
    }

    public void execute(JobExecutionContext context)
      throws JobExecutionException
    {
      JobKey key = context.getJobDetail().getKey();

      JobDataMap dataMap = context.getMergedJobDataMap();  // Note the difference from the previous example

      state.add(new Date());

      System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
    }

    public void setJobSays(String jobSays) {
      this.jobSays = jobSays;
    }

    public void setMyFloatValue(float myFloatValue) {
      myFloatValue = myFloatValue;
    }

    public void setState(ArrayList state) {
      state = state;
    }

  }

(3)Job实例

        可以只创建一个job类,然后创建多个与该job关联的JobDetail实例,每一个实例都有自己的属性集和JobDataMap,最后, 将所有的实例都加到scheduler中。比如,你创建了一个实现Job接口的类“SalesReportJob”。该job需要一个参数(通过JobdataMap传入),表示负责该销售报告的销售员的名字。因此,你可以创建该job的多个实例(JobDetail),比如“SalesReportForJoe”、“SalesReportForMike”,将“joe”和“mike”作为JobDataMap的数据传给对应的job实例。

         当一个trigger被触发时,与之关联的JobDetail实例会被加载,JobDetail引用的job类通过配置在Scheduler上的JobFactory进行初始化。默认的JobFactory实现,仅仅是调用job类的newInstance()方法,然后尝试调用JobDataMap中的key的setter方法。

(4)Job状态与并发

           @DisallowConcurrentExecution:将该注解加到job类上,告诉Quartz不要并发地执行同一个job定义(这里指特定的job类)的多个实例。该限制是针对JobDetail的,而不是job类的。

           @PersistJobDataAfterExecution:将该注解加在job类上,告诉Quartz在成功执行了job类的execute方法后(没有发生任何异常),更新JobDetail中JobDataMap的数据,使得该job(即JobDetail)在下一次执行的时候,JobDataMap中是更新后的数据,而不是更新前的旧数据。该限制是针对JobDetail的,而不是job类的。因为job类的内容经常会影响其行为状态(比如,job类的execute方法需要显式地“理解”其”状态“)。

 

 注意:如果使用了@PersistJobDataAfterExecution注解,我们强烈建议你同时使用@DisallowConcurrentExecution注解,因为当同一个job(JobDetail)的两个实例被并发执行时,由于竞争,JobDataMap中存储的数据很可能是不确定的。

 (5)Job的其它特性

       Durability:如果一个job是非持久的,当没有活跃的trigger与之关联的时候,会被自动地从scheduler中删除。也就是说,非持久的job的生命期是由trigger的存在与否决定的;

       RequestsRecovery:如果一个job是可恢复的,并且在其执行的时候,scheduler发生硬关闭(hard shutdown)(比如运行的进程崩溃了,或者关机了),则当scheduler重新启动的时候,该job会被重新执行。此时,该job的JobExecutionContext.isRecovering() 返回true。

 (6)JobExecutionException

       这里暂时不做介绍了,可以关注官方文档

2.springBoot简单整和quartz

1.导入maven依赖

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

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

2.直接上java代码(我并没有在配置中配置信息,若你想配置可参考官方文档)

package org.medical.controller.quartz;

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.stereotype.Component;

import static org.quartz.TriggerBuilder.newTrigger;

import org.quartz.DateBuilder;

import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.CronScheduleBuilder.weeklyOnDayAndHourAndMinute;;


@Component
public class TestQuartzDemo {
	
	public static void asdf()  throws SchedulerException, InterruptedException {
		
		//创建Scheduler对象
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		
		/*定义一个SimpleTrigger
        Trigger trigger = newTrigger().withIdentity("trigger1", "group1") //定义name/group
        							  .startNow()//一旦加入scheduler,立即生效
        							  .withSchedule(simpleSchedule() //使用SimpleTrigger
                					  .withIntervalInSeconds(1) //每隔一秒执行一次
                					  .withRepeatCount(10)) //执行1000次
        							  .build();*/
		//定义一个cronTrigger
		Trigger trigger = newTrigger()
			    .withIdentity("trigger3", "group1") //代表trigger的身份,key/分组
			    .withSchedule(weeklyOnDayAndHourAndMinute(DateBuilder.MONDAY, 17, 13)) //周一下午5.13执行
			    .build();
		
		
        
        //定义一个JobDetail
        JobDetail job = newJob(HelloQuartz.class) //定义Job类为HelloQuartz类,这是真正的执行逻辑所在
        				.withIdentity("job1", "group1") //定义name/group
        				.usingJobData("name", "quartz") //定义属性
        				.build();
        
        //加入这个调度
        scheduler.scheduleJob(job, trigger);
        
        //启动之
        scheduler.start();
	}

}

定义job

package org.medical.controller.quartz;

import java.util.Date;

import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;

public class HelloQuartz implements Job{
	
	 public void execute(JobExecutionContext context) throws JobExecutionException {
	        JobDetail detail = context.getJobDetail();
	        
	        JobKey key = context.getJobDetail().getKey();
	        String name = detail.getJobDataMap().getString("name");
	        System.out.println("key"+key+"say hello to " + name + " at " + new Date());
	    }
}

 

注释:以上只是根据官方文档,及个人测试用,验证无误,简单的应用,欢迎大家投稿,多多支持小弟

3.springBoot整合quartz(解决无法注入spring Bean),直接上代码吧

package org.medical.controller.quartz2;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

@Component
public class MyJobFactory extends AdaptableJobFactory {
 
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;
 
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        // 调用父类的方法
        Object jobInstance = super.createJobInstance(bundle);
        // 进行注入
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}
package org.medical.controller.quartz2;

import java.io.IOException;

import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configuration
@EnableScheduling
public class QuartzSchedule {
	
	@Autowired 
	private MyJobFactory myJobFactory; 
	 
	@Bean 
	public SchedulerFactoryBean schedulerFactoryBean(Trigger updateTrigger) throws IOException {
	    SchedulerFactoryBean factory = new SchedulerFactoryBean();
	    factory.setOverwriteExistingJobs(true); 
	    // 延时启动 
	    //factory.setStartupDelay(20); 
	    // 自定义Job Factory,用于Spring注入
	    factory.setJobFactory(myJobFactory);
	    factory.setTriggers(updateTrigger); 
	    return factory; 
	 }
	 
	@Bean(name = "updateJobDetail") 
	public JobDetailFactoryBean uploadJobDetail() {
	    JobDetailFactoryBean jobDetail = new JobDetailFactoryBean(); 
	    jobDetail.setJobClass(MyJob.class); 
	    return jobDetail; 
	}
	 
	@Bean(name = "updateTrigger") 
	public CronTriggerFactoryBean updateTriggerFactoryBean(JobDetail updateJobDetail) { 
	    CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
	    trigger.setCronExpression("0 54 11 ? * MON-FRI");  //周一到周五的11.54执行
	    trigger.setJobDetail(updateJobDetail);
	    return trigger; 
	    }

}
package org.medical.controller.quartz2;
 
import java.io.Serializable;
import java.util.Date;
import java.util.Set;

import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

/*
*  我这里注入的事redisTemplate 定时清除redis缓存
*/
@DisallowConcurrentExecution
public class MyJob implements Job, Serializable {
    private static final long serialVersionUID = 1L;
    private Logger logger = LoggerFactory.getLogger(this.getClass());
 
 
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println(new Date());
        Set<String> keys = redisTemplate.keys("*");
        Long delete = redisTemplate.delete(keys);
        System.out.println(delete);
    }
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值