在我们进行软件项目开发的过程中,相信大家在很多时候都会遇到如下业务场景:每天、每周或每月生成相应的业务报表;每天统计系统注册人数;定期清理平台长久不登录的用户等等。遇到这种业务场景需要怎样去处理?人为定时去数据库操作来统计?别开玩笑了,这种事情哪用得着人来做,如果像这种任务还需要专人每天都去做统计,那估计很多人就要疯掉了。针对于这种业务情况,采用定时任务是个非常不错的选择。在Java领域中,定时任务的开源工具也非常多,小到一个Timer类,大到Quartz框架。总体来说,个人比较喜欢的还是Quartz,功能强大而且使用方便。接下来我们就看一下如何通过Spring和Quartz来实现业务系统中的定时任务。
Spring整合Quartz实现定时任务步骤很简单,大致需要经过如下几步:创建任务(Job)、配置JobDetail、配置触发器(Trigger)、配置SchedulerFactoryBean
1.Maven创建一个Springboot项目并引入Spring和quartz的依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>spring-quartz2</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-quartz2</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>3.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>3.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.2.4.RELEASE</version> </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> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>一、创建2个任务类(Job)
继承implements接口实现 Job类的这种形式,创建一个任务类MyJob1,并实现里面的抽象方法execute
package com.example.job; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.text.SimpleDateFormat; import java.util.Date; /** * 定时任务MyJob1 * @author: wangxiaobo * @create: 2020-09-04 12:26 **/ public class MyJob1 implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { Date date = new Date (); SimpleDateFormat sf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); JobDataMap dataMap = context.getJobDetail ().getJobDataMap (); System.out.println (""+sf.format (date)+"任务1执行了,"+dataMap.getString ("gupao")); } }继承implements接口实现 Job类的这种形式,创建一个任务类MyJob2,并实现里面的抽象方法execute
package com.example.job; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.text.SimpleDateFormat; import java.util.Date; /**定时任务MyJob2 * * @author: wangxiaobo * @create: 2020-09-04 12:48 **/ public class MyJob2 implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { Date date = new Date (); SimpleDateFormat sf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); JobDataMap dataMap = context.getJobDetail ().getJobDataMap (); System.out.println (""+sf.format (date)+"任务2执行了,"+dataMap.getString ("gupao")); } }为了演示方便,executeInternal方法中没有写复杂的业务逻辑,只简单的输出一句话,真正的生产环境中在该方法中实现你所需要的业务逻辑即可。
二、在spring-quartz.xml配置文件中配置JobDetailFactoryBean
<!-- 1:定义任务的bean , 这里使用MethodInvokingJobDetailFactoryBean,也可以使用JobDetailFactoryBean--> <bean name="myJob1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- 指定job的名称 --> <property name="name" value="my_job_1"/> <!-- 指定job的分组 --> <property name="group" value="my_group"/> <!-- 指定具体的job类 --> <property name="jobClass" value="com.example.job.MyJob1"/> <!-- 必须设置为true,如果为false,当没有活动的触发器与之关联时会在调度器中会删除任务 --> <property name="durability" value="true"/> </bean> <bean name="myJob2" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- 指定job的名称 --> <property name="name" value="my_job_2"/> <!-- 指定job的分组 --> <property name="group" value="my_group"/> <!-- 指定具体的job类 --> <property name="jobClass" value="com.example.job.MyJob2"/> <!-- 必须设置为true,如果为false,当没有活动的触发器与之关联时会在调度器中会删除任务 --> <property name="durability" value="true"/> </bean>三、配置触发器(Trigger)
Spring提供了两种触发器,如下: 1、org.springframework.scheduling.quartz.SimpleTriggerFactoryBean(此种方式是很隔多长时间进行触发一次,比如每隔24小时触发一次) 2、org.springframework.scheduling.quartz.CronTriggerFactoryBean(此种方式是在指定的时间进行触发,比如只在周一进行触发。不过根据配置也很方便的实现类似SimpleTriggerFactoryBean形式的定时任务) Spring所提供的这两种触发器方式和前面提到的任务创建方式均可以相互之间混用,很灵活。 这里我们先使用SimpleTriggerFactoryBean这个trigger来配置
<!-- 2.1:定义触发器的bean。定义Simple的Trigger,一个触发器只能和一个任务绑定 --> <!-- 一个Job可以绑定多个Trigger--> <bean name="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> <!--指定Trigger的名称 --> <property name="name" value="my_trigger_1"/> <!-- 指定Trigger的组别--> <property name="group" value="my_group"/> <!-- 指定Trigger绑定的job类 --> <property name="jobDetail" ref="myJob1"/> <!-- 指定Trigger的延迟时间为1s 后运行--> <property name="startDelay" value="1000"/> <!-- 指定Trigger的重复间隔5s--> <property name="repeatInterval" value="5000"/> <!-- 指定Trigger的重复次数 --> <property name="repeatCount" value="2"/> </bean> <!-- 2.2:定义触发器的bean。定义Cron的Trigger,一个触发器只能和一个任务绑定 --> <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <!--指定Trigger的名称 --> <property name="name" value="my_trigger_2"/> <!--指定Trigger的名称 --> <property name="group" value="my_group"/> <!-- 指定Trigger绑定的job类 --> <property name="jobDetail" ref="myJob2"/> <!--指定Cron的表达试,当前是每隔10s运行一次 --> <property name="cronExpression" value="0/10 * * * * ?"/> </bean>四、配置SchedulerFactoryBean
<!--3.1 定义调度器。并将Trigger注册到调度器中,这种方式。任务朱慧存储到RAM --> <bean name="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="simpleTrigger"/> <ref bean="cronTrigger"/> </list> </property> </bean>好了,配置完之后我们再启动一下程序,看看定时任务时否运行良好(这里我们使用的Trigger是两种CronTriggerFactoryBean,也可以使用SimpleTriggerFactoryBean)
启动测试效果:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author: wangxiaobo * @create: 2020-09-04 13:30 **/ public class QuartzTest { private static Scheduler scheduler; public static void main(String[] args) throws SchedulerException{ //获取容器 ApplicationContext ac = new ClassPathXmlApplicationContext ("spring-quartz.xml"); //从容器中获取调度器 scheduler = (Scheduler) ac.getBean (" scheduler"); //启动调度器 scheduler.start (); } }
可以看到定时任务正常运行了,达到我们需要的效果
