0


SpringBoot——Quartz 定时任务

优质博文:IT-BLOG-CN

一、Scheduled 定时任务

【1】添加

Scheduled

相关依赖,它是

Spring

自带的一个

jar

包因此引入

Spring

的依赖:

<dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId></dependency>

【2】导入依赖之后,就可以在

Maven Dependencies

中看到相关的依赖,如下:

【3】编写定时任务类:重点是

@Scheduled

注解和

cron

属性;

/**
 * Scheduled 定时任务
 * 定时任务不属于持久层也不属于业务层,所以应该使用 @Component 进行标记
 * @author Administrator
 *
 */@ComponentpublicclassScheduledDemo{/**
     * 定时任务方法,如果是定时任务方法,需要添加 scheduled注解
     * scheduled:表示当前方法就是一个定时任务方法
     * cron属性: 定时任务触发时间的一个字符串表达式
     * 触发条件:每2秒触发一次,博客后面重点说 cron 表达式
     */@Scheduled(cron="0/2 * * * * ?")publicvoidscheduledMethod(){System.out.println("定时任务"+newDate());}}

【4】在启动类中开启定时任务的启动:

@EnableScheduling

注解

@SpringBootApplication@EnableSchedulingpublicclassScheduledApplication{publicstaticvoidmain(String[] args){SpringApplication.run(ScheduledApplication.class, args);}}

【5】

cron

表达式:是一个字符串,分为 6 或 7 个域(建议使用 6个域),每个域代表一个含义 :
 ■ 7个域:Seconds Minutes Hours Day Month Week Year (秒、分、小时、月份中的日期、月分、星期中的日期、年)
 ■ 6个域(少一个 Year):Seconds Minutes Hours Day Month Week

【6】各cron 字段的含义:星期和日是有冲突的,一般会舍掉一个。表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感;
位置时间域名允许值允许的特殊字符1秒0-59, - * /2分钟0-59, - * /3小时0-23, - * /4日0-31, - * / ? L W C5月1-12, - * /6星期1-7, - * / ? L C #7年1970-2099, - * /
①、星号(*):可用在所有字段中,表示对应时间域的每一个时刻。例如在秒时间域中表示每一秒;
②、问号(?):该字段只在星期和日期域中使用,它通常指定为“无意义的值”,相当于一个占位符;
③、减号(-):表示的是一个范围,如在小时字段中使用1-3,则表示 1,2,3点都执行;
④、逗号(,):表示一个列表值,如在秒域中使用 12,15表示第12秒和第15秒触发跑批;
⑤、斜杠(/):x/y 表示一个等步长序列,x为起始值,y为增量步长值,例如秒中使用 0/2 表示从0秒开始,没过2秒执行一次。
⑥、L:该字符只在日期和星期域中使用,但它在两个字段中的意思不同。L在日期字段表示月份的最后一天,如一月的31,二月的28等,如果在星期域中表示星期六(7),但是如果L出现在星期字段里,而且前面有一个数值 X,则表示这个月的最后 X 天,例如:6L表示该月的最后星期五;
⑦、W:该字符只能出现在日期域中,表示离该日期最近的工作日,例如 15W:表示离该月15号最近的工作日,如果15号是星期六则匹配星期五 14号。如果15号是星期日则匹配星期一 16日。如果15号是星期三则匹配星期三 15号本身。但需要注意关联的匹配不能够跨月,例如15号是2月的最后一天星期日,应该向下配置3月1日,但是不能跨月,只能匹配2月26星期五(2月最后一个工作日)W只能指定单一日期,不能指定范围;
⑧、LW组合:在日期字段组合使用,表示当月的最后一个工作日;
⑨、#号:该字符只能在星期域中使用,表示当月某个工作日。如6#3:表示当月的第三个星期五。
⑩、C:该字符只在日期和星期中使用,表示“Calendar” 的意思,表示计划所关联的日期。如果日期没有被关联,则表示所有日期。例如5C在日期域中表示 5日以后的第一天。1C在星期域中表示星期日后的第一天。

二、Springboot 整合Quartz 定时任务框架

Quartz 是 OpenSymphony开源组织在 Job scheduling(任务调度)领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz 可以用来创建简单或为运行十个,百个,甚至是好几万个 Jobs这样复杂的程序。Jobs 可以做成标准的 Java组件或 EJBs。Quartz是一个完全由 Java编写的开源作业调度框架。

【1】quartz 的 maven 依赖:

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

【2】 Job(任务:你要做什么事):

importorg.quartz.Job;importorg.quartz.JobExecutionContext;importorg.quartz.JobExecutionException;/**
 *  定时任务类
 * @author zzx
 *
 */publicclassQuartzDemoimplementsJob{/**
     * 任务触发时所执行的方法
     */publicvoidexecute(JobExecutionContext context)throwsJobExecutionException{System.out.println("任务调度"+newDate());}}

【3】Trigger(触发器:什么时候去做):有两种形式进行表达,其中一种就是 cron 表达式

【4】scheduler(任务调度:你什么时候需要做什么事):将 job 与 Trigger 进行整合。下面是一个例子:

importorg.quartz.CronScheduleBuilder;importorg.quartz.JobBuilder;importorg.quartz.JobDetail;importorg.quartz.Scheduler;importorg.quartz.SimpleScheduleBuilder;importorg.quartz.Trigger;importorg.quartz.TriggerBuilder;importorg.quartz.impl.StdSchedulerFactory;publicclassQuartzMain{publicstaticvoidmain(String[] args)throwsException{//1、Job(任务:你要做什么事),这里使用的是建造者模式JobDetail job =JobBuilder.newJob(QuartzDemo.class).build();//2、Trigger(触发器:什么时候去做),这里 triggerbuilder 也是用建造者模式封装。触发条件分为两种//3.1 第一种:简单的 trigger 触发时间,通过 Quartz 提供方法完成简单的重复调用。如下一个例子:每秒触发一次//Trigger build = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever()).build();//3.2 第二种:按照 cron 的表达式来给定触发时间Trigger trigger=TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")).build();//3、scheduler(任务调度:你什么时候需要做什么事) 将上面的job 和 trigger进行组装 这里使用工厂模式。Scheduler defaultScheduler =StdSchedulerFactory.getDefaultScheduler();
        defaultScheduler.scheduleJob(job, trigger);//4、启动
        defaultScheduler.start();}}

三、SpringBoot 整合 Quartz

【1】整合时相关依赖一下:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId></dependency><!--Quartz 坐标--><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.0</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></exclusion></exclusions></dependency><!--事务--><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId></dependency></dependencies>

【2】 创建一个 Job 类:实现 Job 接口

/**
 *  定时任务类
 * @author zzx
 *
 */
public class QuartzDemo implements Job {
    /**
     * 任务触发时所执行的方法
     */
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("任务调度"+new Date());
    }
}

【3】编写 Quartz 的配置参数

importcom.example.demo.scheduled.QuartzDemo;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.scheduling.quartz.CronTriggerFactoryBean;importorg.springframework.scheduling.quartz.JobDetailFactoryBean;importorg.springframework.scheduling.quartz.SchedulerFactoryBean;importorg.springframework.scheduling.quartz.SimpleTriggerFactoryBean;/**
 * quartz 配置类
 */@ConfigurationpublicclassQuartzConfig{//1、创建 Job 对象@BeanpublicJobDetailFactoryBeanjobDetailFactoryBean(){JobDetailFactoryBean jobDetailFactoryBean =newJobDetailFactoryBean();//通过反射的方式实例化 Job,并没有经过 spring 处理,所以依赖的对象不能通过 autowrite 注入
        jobDetailFactoryBean.setJobClass(QuartzDemo.class);return jobDetailFactoryBean;}//2、创建 Trigger 对象:也是分为两种:下面是创建一个简单的 trigger//这里需要传入 JOB 对象,作为参数关联/*    @Bean
    public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
        SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();
        //获取 JobDetail 关联
        simpleTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        // 触发条件   该参数表示一个执行的毫秒数
        simpleTriggerFactoryBean.setRepeatInterval(2000);
        //设置重复次数
        simpleTriggerFactoryBean.setRepeatCount(5);
        return simpleTriggerFactoryBean;
    }*///通过 cron 表达式表示执行 trigger@BeanpublicCronTriggerFactoryBeancronTriggerFactoryBean(){CronTriggerFactoryBean cronTriggerFactoryBean =newCronTriggerFactoryBean();//获取 JobDetail 关联
        cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean().getObject());// 触发条件   该参数表示一个执行的毫秒数
        cronTriggerFactoryBean.setCronExpression("0/2 * * * * ?");return cronTriggerFactoryBean;}// 创建 scheduler 对象@BeanpublicSchedulerFactoryBeanschedulerFactoryBean(){SchedulerFactoryBean schedulerFactoryBean =newSchedulerFactoryBean();//关联 Trigger
        schedulerFactoryBean.setTriggers(cronTriggerFactoryBean().getObject());return schedulerFactoryBean;}}

【4】修改启动类

/**
 * 整合 Quartz
 */@SpringBootApplication@EnableSchedulingpublicclassScheduledApplication{publicstaticvoidmain(String[] args){SpringApplication.run(ScheduledApplication.class, args);}}

四、Job 类中注入对象

【1】给 Job 类中注入 Service 类型的对象;

/**
 *  定时任务类
 * @author zzx
 *
 */publicclassQuartzDemoimplementsJob{@AutowiredprivateUserService userService;/**
     * 任务触发时所执行的方法
     */publicvoidexecute(JobExecutionContext context)throwsJobExecutionException{
        userService.test();System.out.println("任务调度"+newDate());}}

【2】当运行时会出现空指针异常:userService 对象为空;

Caused by:java.lang.NullPointerException:null
    at com.example.demo.scheduled.QuartzDemo.execute(QuartzDemo.java:25)~[classes/:na]
    at org.quartz.core.JobRunShell.run(JobRunShell.java:202)~[quartz-2.3.0.jar:na]...1 common frames omitted

【3】没有注入 userService 的原因如下,它是通过反射创建 Job 对象,并没有经过 SpringIOC 处理,所以依赖的对象不能通过 autowrite 注入;

protectedObjectcreateJobInstance(TriggerFiredBundle bundle)throwsException{Class<?> jobClass = bundle.getJobDetail().getJobClass();returnReflectionUtils.accessibleConstructor(jobClass,newClass[0]).newInstance(newObject[0]);}

【4】解决方案:重写创建 Job 的方式:并进行实例化 @Component;

@ComponentpublicclassMyAdaptableJobFactoryextendsAdaptableJobFactory{//将对象添加到SpringIoc容器中,并且完成该对象的属性注入@AutowiredprivateAutowireCapableBeanFactory autowireCapableBeanFactory;/**
     * 该方法需要将实例化的 job 对象手动添加到SpringIOC 容器中并且完成实例化;
     */@OverridepublicObjectcreateJobInstance(TriggerFiredBundle bundle)throwsException{Object jobInstance =super.createJobInstance(bundle);//将该对象加入 IOC 容器中
        autowireCapableBeanFactory.autowireBean(jobInstance);return jobInstance;}}

【5】 将其注入到 Quartz 的配置类中,注入到 SchedulerFactoryBean 中;

// 修改 SchedulerFactoryBean 类,set 创建 job 的factory 类@BeanpublicSchedulerFactoryBeanschedulerFactoryBean(MyAdaptableJobFactory myAdaptableJobFactory){SchedulerFactoryBean schedulerFactoryBean =newSchedulerFactoryBean();//关联 Trigger
    schedulerFactoryBean.setTriggers(cronTriggerFactoryBean().getObject());
    schedulerFactoryBean.setJobFactory(myAdaptableJobFactory);return schedulerFactoryBean;}

【6】测试结果:

【7】解决方案:在 SSM 的项目中可以通过如下方式获取依赖对象;

//根据spring的配置文件得到ioc容器对象ApplicationContext context =newClassPathXmlApplicationContext("spring.xml");Person person = context.getBean(Person.class);
标签: spring boot 后端 java

本文转载自: https://blog.csdn.net/zhengzhaoyang122/article/details/134745417
版权归原作者 程序猿进阶 所有, 如有侵权,请联系我们删除。

“SpringBoot——Quartz 定时任务”的评论:

还没有评论