Spring Boot中实现定时任务应用实践

前言

在Spring Boot中实现定时任务功能,可以通过Spring自带的定时任务调度,也可以通过集成经典开源组件Quartz实现任务调度。

本文将详细介绍关于Spring Boot实现定时任务应用的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

一、Spring定时器

1、cron表达式方式

使用自带的定时任务,非常简单,只需要像下面这样,加上注解就好,不需要像普通定时任务框架那样继承任何定时处理接口 ,简单示例代码如下:

package com.power.demo.scheduledtask.simple;
import com.power.demo.util.DateTimeUtil;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
@EnableScheduling
public class SpringTaskA {
 /**
 * CRON表达式参考:http://cron.qqe2.com/
 **/
 @Scheduled(cron = "*/5 * * * * ?", zone = "GMT+8:00")
 private void timerCron() {

 try {
 Thread.sleep(100);
 } catch (Exception e) {
 e.printStackTrace();
 }

 System.out.println(String.format("(timerCron)%s 每隔5秒执行一次,记录日志", DateTimeUtil.fmtDate(new Date())));

 }

}

SpringTaskA

上述代码中,在一个类上添加@EnableScheduling注解,在方法上加上@Scheduled,配置下 cron 表达式,一个最最简单的cron定时任务就完成了。cron表达式的各个组成部分,可以参考下面:

@Scheduled(cron = "[Seconds] [Minutes] [Hours] [Day of month] [Month] [Day of week] [Year]")

2、fixedRate和fixedDelay

@Scheduled注解除了cron表达式,还有其他配置方式,比如fixedRate和fixedDelay,下面这个示例通过配置方式的不同,实现不同形式的定时任务调度,示例代码如下:

package com.power.demo.scheduledtask.simple;
import com.power.demo.util.DateTimeUtil;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
@EnableScheduling
public class SpringTaskB {

 /*fixedRate:上一次开始执行时间点之后5秒再执行*/
 @Scheduled(fixedRate = 5000)
 public void timerFixedRate() {
 try {
 Thread.sleep(100);
 } catch (Exception e) {
 e.printStackTrace();
 }
 System.out.println(String.format("(fixedRate)现在时间:%s", DateTimeUtil.fmtDate(new Date())));
 }

 /*fixedDelay:上一次执行完毕时间点之后5秒再执行*/
 @Scheduled(fixedDelay = 5000)
 public void timerFixedDelay() {
 try {
 Thread.sleep(100);
 } catch (Exception e) {
 e.printStackTrace();
 }
 System.out.println(String.format("(fixedDelay)现在时间:%s", DateTimeUtil.fmtDate(new Date())));

 }

 /*第一次延迟2秒后执行,之后按fixedDelay的规则每5秒执行一次*/
 @Scheduled(initialDelay = 2000, fixedDelay = 5000)
 public void timerInitDelay() {
 try {
 Thread.sleep(100);
 } catch (Exception e) {
 e.printStackTrace();
 }
 System.out.println(String.format("(initDelay)现在时间:%s", DateTimeUtil.fmtDate(new Date())));
 }
}
SpringTaskB

注意一下主要区别:

@Scheduled(fixedRate = 5000)  :上一次开始执行时间点之后5秒再执行

@Scheduled(fixedDelay = 5000)  :上一次执行完毕时间点之后5秒再执行

@Scheduled(initialDelay=2000, fixedDelay=5000)  :第一次延迟2秒后执行,之后按fixedDelay的规则每5秒执行一次

有时候,很多项目我们都需要配置好定时任务后立即执行一次,initialDelay就可以不用配置了。

3、zone

@Scheduled注解还有一个熟悉的属性zone,表示时区,通常,如果不写,定时任务将使用服务器的默认时区;如果你的任务想在特定时区特定时间点跑起来,比如常见的多语言系统可能会定时跑脚本更新数据,就可以设置一个时区,如东八区,就可以设置为:

zone = "GMT+8:00"

二、Quartz

Quartz是应用最为广泛的开源任务调度框架之一,有很多公司都根据它实现自己的定时任务管理系统。Quartz提供了最常用的两种定时任务触发器,即SimpleTrigger和CronTrigger,本文以最广泛使用的CronTrigger为例。

1、添加依赖

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

2、配置cron表达式

示例代码需要,在application.properties文件中新增如下配置:

## Quartz定时job配置
job.taska.cron=*/3 * * * * ?
job.taskb.cron=*/7 * * * * ?
job.taskmail.cron=*/5 * * * * ?

其实,我们完全可以不用配置,直接在代码里面写或者持久化在DB中然后读取也可以。

3、添加定时任务实现

任务1:

package com.power.demo.scheduledtask.quartz;
import com.power.demo.util.DateTimeUtil;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;

@DisallowConcurrentExecution
public class QuartzTaskA implements Job {
 @Override
 public void execute(JobExecutionContext var1) throws JobExecutionException {
 try {
 Thread.sleep(1);
 } catch (Exception e) {
 e.printStackTrace();
 }
 System.out.println(String.format("(QuartzTaskA)%s 每隔3秒执行一次,记录日志", DateTimeUtil.fmtDate(new Date())));
 }
}
QuartzTaskA

任务2:

package com.power.demo.scheduledtask.quartz;
import com.power.demo.util.DateTimeUtil;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
@DisallowConcurrentExecution
public class QuartzTaskB implements Job {
 @Override
 public void execute(JobExecutionContext var1) throws JobExecutionException {
 try {
 Thread.sleep(100);
 } catch (Exception e) {
 e.printStackTrace();
 }
 System.out.println(String.format("(QuartzTaskB)%s 每隔7秒执行一次,记录日志", DateTimeUtil.fmtDate(new Date())));
 }
}
QuartzTaskB

定时发送邮件任务:

package com.power.demo.scheduledtask.quartz;
import com.power.demo.service.contract.MailService;
import com.power.demo.util.DateTimeUtil;
import com.power.demo.util.PowerLogger;
import org.joda.time.DateTime;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
@DisallowConcurrentExecution
public class MailSendTask implements Job {
 @Autowired
 private MailService mailService;
 @Override
 public void execute(JobExecutionContext var1) throws JobExecutionException {
 System.out.println(String.format("(MailSendTask)%s 每隔5秒发送邮件", DateTimeUtil.fmtDate(new Date())));
 try {
 //Thread.sleep(1);
 DateTime dtNow = new DateTime(new Date());
 Date startTime = dtNow.minusMonths(1).toDate();//一个月前
 Date endTime = dtNow.plusDays(1).toDate();
 mailService.autoSend(startTime, endTime);
 PowerLogger.info(String.format("发送邮件,开始时间:%s,结束时间:%s"
  , DateTimeUtil.fmtDate(startTime), DateTimeUtil.fmtDate(endTime)));

 } catch (Exception e) {
 e.printStackTrace();
 PowerLogger.info(String.format("发送邮件,出现异常:%s,结束时间:%s", e));
 }

 }
}
MailSendTask

实现任务看上去非常简单,继承Quartz的Job接口,重写execute方法即可。

4、集成Quartz定时任务

怎么让Spring自动识别初始化Quartz定时任务实例呢?这就需要引用Spring管理的Bean,向Spring容器暴露所必须的bean,通过定义Job Factory实现自动注入。

首先,添加Spring注入的Job Factory类:

package com.power.demo.scheduledtask.quartz.config;
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;
public final class AutowireBeanJobFactory extends SpringBeanJobFactory
 implements ApplicationContextAware {
 private transient AutowireCapableBeanFactory beanFactory;

 /**
 * Spring提供了一种机制让你可以获取ApplicationContext,即ApplicationContextAware接口
 * 对于一个实现了ApplicationContextAware接口的类,Spring会实例化它的同时调用它的
 * public voidsetApplicationContext(ApplicationContext applicationContext) throws BeansException;接口,
 * 将该bean所属上下文传递给它。
 **/
 @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;
 }
}
AutowireBeanJobFactory

定义QuartzConfig:

package com.power.demo.scheduledtask.quartz.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configuration
public class QuartzConfig {
 @Autowired
 @Qualifier("quartzTaskATrigger")
 private CronTriggerFactoryBean quartzTaskATrigger;
 @Autowired
 @Qualifier("quartzTaskBTrigger")
 private CronTriggerFactoryBean quartzTaskBTrigger;
 @Autowired
 @Qualifier("mailSendTrigger")
 private CronTriggerFactoryBean mailSendTrigger;
 //Quartz中的job自动注入spring容器托管的对象
 @Bean
 public AutowireBeanJobFactory autoWiringSpringBeanJobFactory() {
 return new AutowireBeanJobFactory();
 }

 @Bean
 public SchedulerFactoryBean schedulerFactoryBean() {
 SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
 scheduler.setJobFactory(autoWiringSpringBeanJobFactory()); //配置Spring注入的Job类
 //设置CronTriggerFactoryBean,设定任务Trigger
 scheduler.setTriggers(
 quartzTaskATrigger.getObject(),
 quartzTaskBTrigger.getObject(),
 mailSendTrigger.getObject()
 );
 return scheduler;
 }
}
QuartzConfig

接着配置job明细:

package com.power.demo.scheduledtask.quartz.config;

import com.power.demo.common.AppField;
import com.power.demo.scheduledtask.quartz.MailSendTask;
import com.power.demo.scheduledtask.quartz.QuartzTaskA;
import com.power.demo.scheduledtask.quartz.QuartzTaskB;
import com.power.demo.util.ConfigUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
@Configuration
public class TaskSetting {

 @Bean(name = "quartzTaskA")
 public JobDetailFactoryBean jobDetailAFactoryBean() {
 //生成JobDetail
 JobDetailFactoryBean factory = new JobDetailFactoryBean();
 factory.setJobClass(QuartzTaskA.class); //设置对应的Job
 factory.setGroup("quartzTaskGroup");
 factory.setName("quartzTaskAJob");
 factory.setDurability(false);
 factory.setDescription("测试任务A");
 return factory;
 }

 @Bean(name = "quartzTaskATrigger")
 public CronTriggerFactoryBean cronTriggerAFactoryBean() {
 String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKA_CRON);
 CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
 //设置JobDetail
 stFactory.setJobDetail(jobDetailAFactoryBean().getObject());
 stFactory.setStartDelay(1000);
 stFactory.setName("quartzTaskATrigger");
 stFactory.setGroup("quartzTaskGroup");
 stFactory.setCronExpression(cron);
 return stFactory;
 }

 @Bean(name = "quartzTaskB")
 public JobDetailFactoryBean jobDetailBFactoryBean() {
 //生成JobDetail
 JobDetailFactoryBean factory = new JobDetailFactoryBean();
 factory.setJobClass(QuartzTaskB.class); //设置对应的Job
 factory.setGroup("quartzTaskGroup");
 factory.setName("quartzTaskBJob");
 factory.setDurability(false);
 factory.setDescription("测试任务B");
 return factory;
 }

 @Bean(name = "quartzTaskBTrigger")
 public CronTriggerFactoryBean cronTriggerBFactoryBean() {
 String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKB_CRON);
 CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
 //设置JobDetail
 stFactory.setJobDetail(jobDetailBFactoryBean().getObject());
 stFactory.setStartDelay(1000);
 stFactory.setName("quartzTaskBTrigger");
 stFactory.setGroup("quartzTaskGroup");
 stFactory.setCronExpression(cron);
 return stFactory;
 }

 @Bean(name = "mailSendTask")
 public JobDetailFactoryBean jobDetailMailFactoryBean() {
 //生成JobDetail
 JobDetailFactoryBean factory = new JobDetailFactoryBean();
 factory.setJobClass(MailSendTask.class); //设置对应的Job
 factory.setGroup("quartzTaskGroup");
 factory.setName("mailSendTaskJob");
 factory.setDurability(false);
 factory.setDescription("邮件发送任务");
 return factory;
 }

 @Bean(name = "mailSendTrigger")
 public CronTriggerFactoryBean cronTriggerMailFactoryBean() {
 String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKMAIL_CRON);
 CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
 //设置JobDetail
 stFactory.setJobDetail(jobDetailMailFactoryBean().getObject());
 stFactory.setStartDelay(1000);
 stFactory.setName("mailSendTrigger");
 stFactory.setGroup("quartzTaskGroup");
 stFactory.setCronExpression(cron);
 return stFactory;
 }
}
TaskSetting

最后启动你的Spring Boot定时任务应用,一个完整的基于Quartz调度的定时任务就实现好了。

本文定时任务示例中,有一个定时发送邮件任务MailSendTask,下一篇将分享Spring Boot应用中以MongoDB作为存储介质的简易邮件系统。

扩展阅读:

很多公司都会有自己的定时任务调度框架和系统,在Spring Boot中如何整合Quartz集群,实现动态定时任务配置?

参考:

//www.jb51.net/article/139591.htm

//www.jb51.net/article/139597.htm

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • spring boot整合quartz实现多个定时任务的方法

    最近收到了很多封邮件,都是想知道spring boot整合quartz如何实现多个定时任务的,由于本人生产上并没有使用到多个定时任务,这里给个实现的思路. 1.新建两个定时任务,如下: public class ScheduledJob implements Job{ @Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("sched

  • springboot整合Quartz实现动态配置定时任务的方法

    前言 在我们日常的开发中,很多时候,定时任务都不是写死的,而是写到数据库中,从而实现定时任务的动态配置,下面就通过一个简单的示例,来实现这个功能. 一.新建一个springboot工程,并添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency

  • 详解SpringBoot开发案例之整合定时任务(Scheduled)

    来来来小伙伴们,基于上篇的邮件服务,定时任务就不单独分项目了,天然整合进了邮件服务中. 不知道,大家在工作之中,经常会用到那些定时任务去执行特定的业务,这里列举一下我在工作中曾经使用到的几种实现. 任务介绍 Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务.Timer的优点在于简单易用:缺点是Timer的所有任务都是由同一个线程调度的,因此所有任务都是串行执行的.同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任

  • SpringBoot定时任务两种(Spring Schedule 与 Quartz 整合 )实现方法

    前言 最近在项目中使用到定时任务,之前一直都是使用Quartz 来实现,最近看Spring 基础发现其实Spring 提供 Spring Schedule 可以帮助我们实现简单的定时任务功能. 下面说一下两种方式在Spring Boot 项目中的使用. Spring Schedule 实现定时任务 Spring Schedule 实现定时任务有两种方式 1. 使用XML配置定时任务, 2. 使用 @Scheduled 注解. 因为是Spring Boot 项目 可能尽量避免使用XML配置的形式,

  • spring-boot通过@Scheduled配置定时任务及定时任务@Scheduled注解的方法

    串行的定时任务 @Component public class ScheduledTimer { private Logger logger = Logger.getLogger(this.getClass()); /** * 定时任务,1分钟执行1次,更新潜在客户超时客户共享状态 */ @Scheduled(cron="0 0/1 8-20 * * ?") public void executeUpdateCuTask() { Thread current = Thread.curr

  • 详解Spring Boot中使用@Scheduled创建定时任务

    我们在编写Spring Boot应用中经常会遇到这样的场景,比如:我需要定时地发送一些短信.邮件之类的操作,也可能会定时地检查和监控一些标志.参数等. 创建定时任务 在Spring Boot中编写定时任务是非常简单的事,下面通过实例介绍如何在Spring Boot中创建定时任务,实现每过5秒输出一下当前时间. 在Spring Boot的主类中加入@EnableScheduling注解,启用定时任务的配置 @SpringBootApplication @EnableScheduling publi

  • 详解Spring Boot 定时任务的实现方法

    最近在用SpringBoot写一个关于定时项目的时候遇到一个问题,就是客户端访问服务器的结果实际上是每个一段时间发生一次变化,并且在服务器在每天的某个固定的时间点都要触发一次事件. 我们当然可以在遇到每一个请求时都重新计算结果,但是为了提高效率,我们显然可以让服务器每隔一段时间计算一次结果,并且把这个结果进行保存,对在下一个时间段内的每个请求都直接返回计算后的结果.这样就能较好的提高了服务器的性能. 那么问题就在于如何处理定时任务.其实SpringBoot早就提供了非常方便的接口,但是网上的介绍

  • 详解SpringBoot 创建定时任务(配合数据库动态执行)

    序言:创建定时任务非常简单,主要有两种创建方式:一.基于注解(@Scheduled) 二.基于接口(SchedulingConfigurer). 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库中读取指定时间来动态执行定时任务,这时候基于接口的定时任务就大派用场了. 一.静态定时任务(基于注解) 基于注解来创建定时任务非常简单,只需几行代码便可完成. @Scheduled 除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应

  • SpringBoot 定时任务遇到的坑

    前言 springboot已经支持了定时任务Schedule模块,一般情况已经完全能够满足我们的实际需求.今天就记录一下我使用 schedule 时候踩的坑吧. 想要使用定时,我们首先要开启支持,其实就是在启动类上面加个注解就 Ok. @SpringBootApplication @EnableScheduling public class Application { public static void main(String[] args) { SpringApplication.run(A

  • springboot整合quartz实现定时任务示例

    在做项目时有时候会有定时器任务的功能,比如某某时间应该做什么,多少秒应该怎么样之类的. spring支持多种定时任务的实现.我们来介绍下使用spring的定时器和使用quartz定时器 1.我们使用spring-boot作为基础框架,其理念为零配置文件,所有的配置都是基于注解和暴露bean的方式. 2.使用spring的定时器: spring自带支持定时器的任务实现.其可通过简单配置来使用到简单的定时任务. @Component @Configurable @EnableScheduling p

随机推荐