Quartz 学习笔记

it2024-11-02  7

Quartz

quartz是什么quartz能做什么quartz的核心API编写代码测试原生的quartzquartz的cron表达式整合spring(spring mvc) - 单机版、集群版整合springboot - 单机版 集群版springboot整合spring task实现任务调度

1.Quartz是什么?

Quartz官方网站:http://www.quartz-scheduler.org

Quartz是一个功能丰富的开源任务调度框架,几乎可以集成到任何java应用中,小到单体应用,大到大型电子商务系统;

Quartz可以用来执行成千上万的简单或复杂的调度任务;

Quartz的任务被定义成一组标准的java组件,几乎可以执行任何编程任务;

Quartz包含了一些企业级功能,包括JTA事务和集群;

2.Quartz能做什么?

相当于定时器 某时间点做某一件事

定时调度 定时邮件短信;

定时数据同步 ; 点赞数据一般存在redis定时存到关系型数据库

3.Quartz核心api

1.job:定义一个任务必须要实现的接口

2.jobDetail:用于描述任务 (属于什么任务组。任务名)

3.Trigger:定义任务执行时间、规则 simpleTrigger:定义任务和实质性、何时停止执行拼率 ​cornTrigger:使用Corn表达式定义执行规则时间

4.Scheduler:调度器(使用Trigger定义的规则调度Job)

5.JobKey:定义任务组和任务名称

6.TriggerKey:定义Trigger组合Trigger名称

7.JobExecutionContext:任务执行上下文

8.JobBuilder、TriggerBuilder

4.使用代码测试SimpleTrigger

1.maven依赖

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

2.测试任务

每隔5秒打印一次hello任务5秒后执行,之后每隔五秒执行一次重复10次任务5秒后执行,之后每隔5秒执行一次,30秒后停止执行 定义任务 HelloJob.java 测试类 创建jobDetail 创建trigger 创建scheduler

定义任务 HelloJob.java

public class HelloJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss SSS"); String current = dateFormat.format(new Date()); System.out.println(current); } }

测试一:

//每隔5秒打印一次hello public class First { public static void main(String[] args) throws SchedulerException { //创建jobDetail JobDetail jobDetail = JobBuilder.newJob(HelloJob.class) //任务组 任务名 .withIdentity("hello", "hello").build(); //创建trigger SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("", "") .startNow()//调度时间:立即执行 .withSchedule( SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(5)//5秒执行一次 .repeatForever()//永远执行 )//任务调度规则 .build(); //创建Scheduler Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.scheduleJob(jobDetail,trigger); scheduler.start(); } }

测试二:

//任务5秒后执行,之后每隔五秒执行一次 public class Second { public static void main(String[] args) throws SchedulerException { JobKey jobKey = new JobKey("hello", "hello"); JobDetail jobDetail = JobBuilder.newJob(HelloJob.class) .withIdentity(jobKey) .build(); Date current = new Date(); System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:ss:mm SSS").format(current)); Date fiveSecondsAfter = new Date(current.getTime() + 5000L); TriggerKey triggerKey = new TriggerKey("hello", "hello"); SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(triggerKey) .startAt(fiveSecondsAfter)//5秒后执行 .withSchedule( SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(5)//每隔5秒执行一次 .withRepeatCount(10)//重复10次 ).build(); Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.scheduleJob(jobDetail, trigger); scheduler.start(); } }

测试三:

//任务5秒后执行,之后每隔5秒执行一次,30秒后停止执行 public class Third { public static void main(String[] args) throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(HelloJob.class) .withIdentity("hello", "hello") .build(); System.out.println(LocalDateTime.now()); Date date = new Date(); Date fiveSecondsAfter = new Date(date.getTime()+5000L); Date thirtySecondsAfter = new Date(date.getTime() + 1000*30L); SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("hello") .startAt(fiveSecondsAfter) .endAt(thirtySecondsAfter) .withSchedule( SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(5) .repeatForever() ).build(); Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.scheduleJob(jobDetail,trigger); scheduler.start(); } }

5.Quartz的Cron表达式

5.1 Quartz的Cron表达式(Cron Expression)

Quartz的Cron表达式 1.1 Quartz的Cron表达式(Cron Expression)

Quartz Cron表达式用于配置CronTrigger实例

[秒] [分] [小时] [天、日期] [月] [周] [年](可选) seconds Minutes Hours Day-of-Month Month Day-of-Week YEAR 时间字段是否必 填取值范围允许的特殊 字符秒是0-59, * - /分是0-59, * - /小时是0-23, * - /天/日期(每月的几 号)是1-31, * - / ? L W月是1-12(JAN-DEC), * - /周(星期几)是1-7(SUN-SAT)(1周天,7 周六), * - / ? L #年否空、1970-2099, * - / 特 殊 字 符解释,表示或的关系。如用在分钟:1,5 - 表示在第一分钟和第5分钟执行*每秒、每分、每小时、每天、每月等。在秒上写*,表示每秒钟都要执行-表示范围。如用在秒上:1-20 - 表示在1-20秒都要执行/表示每隔多长时间执行。用在秒上:*/5或0/5 - 表示每隔5秒执行一次?只能用到天和周上 1.如果[天]字段上用了或确切的某一天,那么[周]只能用? 2.如果[周]字段上用了或确切的某一个周几,那么[天]只能用?L表示每个月的最后一天或者每个月的最后星期几,[周]写6L - 表示每个月 最后一个星期5W只能用在[天、日期]的字段,表示离这个日期最近的一个工作日 比如: 1. 25W:表示离这个月25号最近的一个工作日 如果25号是一个工作日,那么就是这天执行 如果25号是周六,那么应该是24号周五执行 如果25号是周天,那么应该是下周一26号执行 2.日期不能夸月 1W:离1号最近的工作日,如果1号是周六,那么离1号最近的工作日 应该是当月3号,而不是上个月的最后一天; 3.只能指定单一日期,不能用范围#用在[周]上,表示每个月第几个周几,例如在[周上]写SUN#2 - 表示每个 月第二个周天 母亲节的例子:母亲节当天8点执行一个短信发送任务 0 0 8 ? 5 SUN#2 举例表达式周一到周五8:50提醒打卡0 50 8 ? * MON-FRI每天凌晨1点到1点59分,每隔5分钟执行一次0 0/5 1 * * ?每隔5秒执行一次*/5 * * * * ?每天5-15点整点触发0 0 5-15 * * ?表示每个星期三中午12点 0 0 12 ? * WED每月最后一天23点执行一次0 0 23 L * ?每月的最后一个星期五上午10:15触发0 15 10 ? * 6L每月的第三个星期五上午10:15触发0 15 10 ? * FRI#3

5.2 cron表达式例子

CronTest

public class CronTest { public static void main(String[] args) throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(HelloJob.class) .withIdentity("hello") .build(); //cron表达式测试每隔五秒执行一次 CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("hello") .withSchedule( CronScheduleBuilder .cronSchedule("*/5 * * * * ?")//cron表达式 ).build(); Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.scheduleJob(jobDetail,trigger); scheduler.start(); } }

6. 整合spring(spring mvc) - 单机版 集群版

6.1单机版

1.maven依赖

<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.6.RELEASE</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency>

2.配置quartz

创建任务类 //仅仅打印一句“发送邮件” public class EmailJob { public void send(){ System.out.println("发送邮件"); } } 正常配置spring-mvc.xml、web.xml、spring-root.xml并在spring-root中追加quartz的相关配置

web.xml

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <!--spring root 容器--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-root.xml</param-value> </context-param> <!--Post编码过滤器--> <filter> <filter-name>encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>

spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd"> <context:component-scan base-package="com.etoak"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/> </context:component-scan> <mvc:default-servlet-handler/> <mvc:annotation-driven></mvc:annotation-driven> </beans>

spring-root.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd"> <context:component-scan base-package="com.etoak"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/> </context:component-scan> <!--导入quartz配置--> <import resource="classpath:standalone.xml" /> </beans>

standalone.xml 配置quartz

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd"> <bean id="emailJob" class="com.etoak.job.EmailJob"/> <!--配置jobDetail:MethodInvokingJobDetailFactoryBean--> <bean id="emailJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <!--name group targetObject targetMethod--> <property name="name" value="emailJob"/> <property name="group" value="emailJob"/> <property name="targetObject" ref="emailJob"/> <property name="targetMethod" value="send"/> </bean> <!--配置CronTrigger:CronTriggerFactoryBean--> <bean id="emailTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <!--name group jobDetail cronExpression--> <property name="name" value="emailTrigger"/> <property name="group" value="emailTrigger"/> <property name="jobDetail" ref="emailJobDetail" /> <property name="cronExpression" value="0/5 * * ? * *" /> </bean> <!-- 配置scheduler:SchedulerFactoryBean --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="emailTrigger"/> </list> </property> </bean> </beans>

这样一来,开启服务器后就会自动启动调度任务(每五秒打印"发送邮件") 该任务我们设置的是永远执行 ,但我们可以通过在页面发送请求来停止这一任务 创建JobController

@RestController @RequestMapping("/job") public class JobController { @Autowired Scheduler scheduler; //停止调度任务 @RequestMapping(value = "/pause", produces = "text/plain;charset=UTF-8") public String pauseJob(@RequestParam String jobName, @RequestParam String jobGroup) throws SchedulerException { JobKey jobKey = new JobKey(jobName, jobGroup); if (!scheduler.checkExists(jobKey)) { return "任务不存在"; } scheduler.pauseJob(jobKey); return "success"; } }

如此,在页面上发送请求 job/pause?jobName=emailJob&jobGroup=emailJob 即可停止任务

6.2. 集群版

​ 利用JDBC将任务持久化到关系型数据中

当集群中的一个节点执行任务的时候,其它的节点的任务不会执行;当集群中的一个节点宕机之后,集群中的其它节点会接管这个任务;

6.2.1 创建数据库和表结构

数据库:使用mysql数据库数据表:quartz提供

6.2.2 编写quartz配置(把quartz.properties拷贝到classpath下)

​ 集群名称、集群中的任务实例ID的生成方式、线程 quartz.properties

#可以设置为任意,用在 JDBC JobStore中来唯一标识实例,所有集群节点中必须相同。 org.quartz.scheduler.instanceName=QuartzCluster # 属性为 AUTO即可,基于主机名和时间戳来产生实例 ID org.quartz.scheduler.instanceId=AUTO ## 线程 org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 20 org.quartz.threadPool.threadPriority = 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true ## 存储 org.quartz.jobStore.misfireThreshold = 60000 #JobStoreTX,将任务持久化到数据库中。因为集群中节点依赖于数据库来传播 Scheduler实例的状态,你只能在使用 JDBC JobStore 时应用 Quartz 集群。这意味着你必须使用 JobStoreTX 或是 JobStoreCMT 作为 Job 存储,不能在集群中使用 RAMJobStore。 org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.tablePrefix=QRTZ_ org.quartz.jobStore.maxMisfiresToHandleAtATime=10 #值 true,表示 Scheduler实例要参与到一个集群当中。这一属性会贯穿于调度框架的始终,用于修改集群环境中操作的默认行为。 org.quartz.jobStore.isClustered=true #定义了Scheduler实例检入到数据库中的频率(单位:毫秒)。Scheduler 检查是否其他的实例到了它们应当检入的时候未检入;这能指出一个失败的 Scheduler 实例,且当前 Scheduler 会以此来接管任何执行失败并可恢复的 Job。通过检入操作,Scheduler 也会更新自身的状态记录。clusterChedkinInterval 越小,Scheduler 节点检查失败的 Scheduler 实例就越频繁。默认值是 15000 (即15 秒)。 org.quartz.jobStore.clusterCheckinInterval=5000

6.2.3 创建任务类

​ 任务类需要继承QuartzJobBean

OrderJob

public class DataSyncJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("删除超时订单"); } }

6.2.4 配置spring bean

数据源

事务管理器

JobDetailFactoryBean

name、group、jobClass(Class对象)、durability(持久化任务)

CronTriggerFactoryBean

name、group、jobDetail、cronExpression

SchedulerFactoryBean

triggers、dataSource、transactionManager、configLocation

cluseter.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd"> <!--配置数据源--> <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/et2004" /> <property name="username" value="root"/> <property name="password" value="etoak"/> </bean> <!--配置事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <constructor-arg name="dataSource" ref="dataSource" /> </bean> <!--配置JobDetail:JobDetailFactoryBean--> <bean id="orderJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- name group jobClass durability--> <property name="name" value="orderJob" /> <property name="group" value="orderJob"/> <property name="JobClass" value="com.etoak.job.OrderJob"/> <!--持久化任务--> <property name="durability" value="true"/> </bean> <!--配置CronTrigger:CronTriggerFactoryBean--> <bean id="orderTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <!-- name group jobDetail cronExpression--> <property name="name" value="orderTrigger"/> <property name="group" value="orderTrigger"/> <property name="jobDetail" ref="orderJobDetail"/> <property name="cronExpression" value="0/5 * * * * ?"/> </bean> <!--配置scheduler: SchedulerFactoryBean--> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="orderTrigger" /> </list> </property> <!--引入集群后增加的配置项 配置数据源 事务管理器 quartz配置 --> <property name="dataSource" ref="dataSource" /> <property name="transactionManager" ref="transactionManager"/> <property name="configLocation" value="classpath:quartz.properties"/> </bean> </beans>

然后将配置好的cluseter.xml文件引入到spring mvc的spring-root.xml 中并注释掉单机配置

<!--导入quartz配置 <import resource="classpath:standalone.xml" />--> <import resource="classpath:cluseter.xml"/>

启动服务器就可以自动开启任务 将工程打包后配置到另一个服务器上后两台服务器同时启动只会有一个服务器执行任务 当正在执行任务的服务器宕机后另一服务器启动任务

6.3 解决集群版中任务类无法使用spring bean的问题

Quartz初始化是自己的JobContext,不同于Spring的ApplicationContext,所以无法直接注入,导致使用时产生空指针异常! 在集群的任务类中使用springbean 的两种方式

首先我们创建一个Service用来执行具体的业务逻辑,而任务类中只需要调用该Service方法即可,接下来我们解决任务类拿到springbeanOrderService OrderService

@Service public class OrderService { public void deleteOrder(){ System.out.println("OrderService del order"); } } 方法一:将spring ioc容器添加到Scheduler执行上下文

cluseter.xml

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="orderTrigger" /> </list> </property> <!-- 以下配置是引入集群之后增加的配置项 --> <property name="dataSource" ref="dataSource" /> <property name="transactionManager" ref="transactionManager" /> <property name="configLocation" value="classpath:quartz.properties" /> <!-- **第一种解决任务对象无法使用spring bean的方式: schedulerContext {spring=ioc容器} --> <property name="applicationContextSchedulerContextKey" value="spring" /> </bean>

OrderJob(通过执行器上下文来获得IOC容器)

public class OrderJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { System.out.println("删除超时订单"); Scheduler scheduler = context.getScheduler(); try { SchedulerContext schedulerContext = scheduler.getContext(); ApplicationContext ioc = (ApplicationContext) schedulerContext.get("spring"); //通过IOC容器获得SpringBean OrderService orderService = ioc.getBean(OrderService.class); orderService.deleteOrder(); } catch (SchedulerException e) { e.printStackTrace(); } } }

通过阅读源码了解到 SchedulerFactoryBean通过applicationContextSchedulerContextKey属性来将spring的IOC容器添加到scheduler上下文中该属性的值就是我们在scheduler上下文中拿到IOC容器的key值

//SchedulerFactoryBean部分源码 if (this.applicationContextSchedulerContextKey != null) { if (this.applicationContext == null) { throw new IllegalStateException( "SchedulerFactoryBean needs to be set up in an ApplicationContext " + "to be able to handle an 'applicationContextSchedulerContextKey'"); } scheduler.getContext().put(this.applicationContextSchedulerContextKey, this.applicationContext); } 方法二:将Quartz创建的任务注入到spring容器中

ClusterJobFactory

@Service public class ClusterJobFactory extends SpringBeanJobFactory { @Autowired AutowireCapableBeanFactory ioc; @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { //任务对象 Object job = super.createJobInstance(bundle); ioc.autowireBean(job); return job; } } <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="orderTrigger" /> </list> </property> <!-- 以下配置是引入集群之后增加的配置项 --> <property name="dataSource" ref="dataSource" /> <property name="transactionManager" ref="transactionManager" /> <property name="configLocation" value="classpath:quartz.properties" /> <!-- 第二种解决任务对象无法使用spring bean的方式 --> <property name="jobFactory" ref="clusterJobFactory" /> </bean>

OrderJob

public class OrderJob extends QuartzJobBean { @Autowired OrderService orderService; @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { orderService.deleteOrder(); } }

通过读源码可以了解到scheduler中需要一个任务类的工厂来创建任务类,如果不配置会有一个默认的工厂

AdaptableJobFactory implements JobFactory

我们仿照其写一个工程类来创建我们的任务类,并在创建好后将其加入到springbean中 这样一来我们就可以在springbean中直接使用 @Autowired 自动注入了。

7.整合springboot - 单机版 集群版

我们使用spring boot写一遍,请对比上面进行学习

7.1单机版

任务类EmailJob

public class EmailJob { public void send(){ System.out.println("下发邮件"); } }

配置文件StandaloneConfig

//@Configuration public class StandaloneConfig { @Bean public EmailJob emailJob(){ return new EmailJob(); } @Bean public MethodInvokingJobDetailFactoryBean emailJobDetail(){ MethodInvokingJobDetailFactoryBean factoryBean = new MethodInvokingJobDetailFactoryBean(); factoryBean.setBeanName("emailJob"); factoryBean.setGroup("emailGroup"); factoryBean.setTargetObject(this.emailJob()); factoryBean.setTargetMethod("send"); return factoryBean; } @Bean public CronTriggerFactoryBean emailTrigger(){ CronTriggerFactoryBean trigger = new CronTriggerFactoryBean(); trigger.setName("emailTrigger"); trigger.setGroup("emailTrigger"); trigger.setJobDetail( this.emailJobDetail().getObject()); trigger.setCronExpression("0/5 * * * * ?"); return trigger; } @Bean public SchedulerFactoryBean emailScheduler(){ SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setTriggers(this.emailTrigger().getObject()); return schedulerFactoryBean; } }

7.2集群版

quartz.properties与springmvc版 相同

application.yml

server: port: 8080 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/XXX?serverTimezone=UTC username: root password: XXX

任务类DataSyncJob

public class DataSyncJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("同步数据"); } }

配置文件 ClusterConfig

@Configuration public class ClusterConfig { @Autowired DataSource dataSource; @Bean public PlatformTransactionManager transactionManager(){ return new DataSourceTransactionManager(this.dataSource); } @Bean public JobDetailFactoryBean dataSyncJobDetail(){ JobDetailFactoryBean jobDetail = new JobDetailFactoryBean(); jobDetail.setName("dataJob"); jobDetail.setGroup("dataJob"); jobDetail.setJobClass(DataSyncJob.class); jobDetail.setDurability(true); return jobDetail; } @Bean public CronTriggerFactoryBean dataSyncTrigger(){ CronTriggerFactoryBean cronTrigger = new CronTriggerFactoryBean(); cronTrigger.setName("dataTrigger"); cronTrigger.setGroup("dataTrigger"); cronTrigger.setJobDetail(this.dataSyncJobDetail().getObject()); cronTrigger.setCronExpression("0/5 * * * * ?"); return cronTrigger; } @Bean public SchedulerFactoryBean dataSyncScheduler(){ SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setTriggers(this.dataSyncTrigger().getObject()); schedulerFactoryBean.setDataSource(this.dataSource); schedulerFactoryBean.setTransactionManager(this.transactionManager()); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource resource = resolver.getResource("classpath:quartz.properties"); schedulerFactoryBean.setConfigLocation(resource); return schedulerFactoryBean; } }

8. springboot整合spring task实现任务调度

springboot启动类SpringTaskApp

@SpringBootApplication @EnableScheduling public class SpringTaskApp { public static void main(String[] args) { SpringApplication.run(SpringTaskApp.class,args); } @Scheduled(cron = "0/5 * * * * ?") public void sendEmail(){ System.out.println(Thread.currentThread().getName()+" 发送邮件"); } @Scheduled(cron = "0/5 * * * * ?") public void sendSms(){ System.out.println(Thread.currentThread().getName()+" 发送短信"); } }

启动后发现这两个任务是同一个线程来执行,想要设置多线程就要在配置文件中设置 application.yml

spring: task: scheduling: pool: size: 5 #线程数
最新回复(0)