简介
Job
- Job:实现业务逻辑的任务接口。job接口很容易实现,只有一个execute方法,类似TimerTask的run方法,在里面编写业务逻辑。
- Job实例在quartz中的生命周期:每次调度器执行job时,它在调用execute方法前会创建一个新的job实例。当调用完成后,关联的job对象实例会被释放,释放的实例会被垃圾回收机制回收。
JobDetail
- JobDetail为Job实例提供了许多设置属性,以及JobDataMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例。
- name:名称
- group:所在组
- jobClass:任务类
- jobDataMap:
JobExecutionContext
- 当Scheduler调用一个job,就会将JobExecutionContext传递给job的execute方法
- job能通过JobExecutionContext对象访问到quartz运行时候的环境以及job本身的明细数据
JobDataMap
-
属于JobDetail的一部分,可以在构建JobDetail时传递参数
- 在进行job任务调度时JobDataMap存储在execute方法的入参JobExecutionContext中,非常方便获取。
- JobDataMap可以用来装载任何可序列化的对象,当job实例对象被执行时这些参数对象会传递给它
- JobDataMap实现了JDK中的Map接口,并且添加了一些非常方便的方法来存取基本数据类型。
public class MyJob implements Job {
@Setter@Getter
private String msg;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
LocalTime localTime = LocalTime.now();
System.out.println(localTime.toString()+",msg="+msg);
}
}
public class QuartzDemo {
public static void main(String[] args) throws SchedulerException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity("jobDetail1","group1")
.usingJobData("name","value")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.startNow()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervallnSeconds(10)
.repeatForever()
)
.build();
scheduler.scheduleJob(jobDetail,trigger);
try {
Thread.sleep(600000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.shutdown();
}
}
- 可以使用@PersistJobDataAfterExecution注解更新JobDataMap
@PersistJobDataAfterExecution
public class MyJob implements Job {
@Setter@Getter
private int count;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
LocalTime localTime = LocalTime.now();
count++;
context.getJobDetail().getJobDataMap().put("count"+count);
System.out.println(localTime.toString()+",count="+count);
}
}
JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity("jobDetail1","group1")
.usingJobData("count",new Random().nextInt(10))
.build();
Trigger
-
quartz中的触发器用来告诉调度程序作业什么时候触发。即Trigger对象是用来触发执行job的
-
三个属性:
- JobKey:表示job实例的标识,触发器被触发时,该指定的job实例会执行。
- StartTime:表示触发器的时间表首次被触发的时间。类型是java.util.Date
- EndTime:指定触发器的不再被触发的时间,类型是java.util.Date
- 优先级:当同一时间有多个Trigger同时触发时需要判断优先级,优先级别越高越先执行
-
SimpleTrigger:在一个指定时间段内执行一次作业任务,或是在指定的时间间隔内多次执行作业任务
- 重复次数可以为0,正整数或SimpleTrigger.REPEAT_INDEFINITELY常量值。
- 重复执行间隔必须为0或长整数
- 一旦被指定了endTime参数,那么它会重复次数参数的效果
-
CronTrigger:基于日历的作业调度器,而不是像SimpleTrigger那样精确指定时间间隔,比SimpleTrigger更常用。
-
Cron表达式:用于配置CronTrigger实例,是由七个子表达式组成的字符串,描述了时间表的详细信息。格式为:【秒】【分】【小时】【日】【月】【周】【年】
-
字段 是否必填 允许值 允许的字符 秒 是 0~59 ,- * / 分 是 0~59 ,- * / 小时 是 0~23 ,- * / 日 是 0~31 ,- * ? / L W C 月 是 0~12或JAN-DEC ,- * / 周 是 1~7或SUN-SAT ,- * ? / L # C 年 否 empty,1970~2099 ,- * / -
表达式 含义 0 15 10 ? * * 每天10点15分触发 0 0/15 14 * * ? 每天下午的2点到2点59分(整点开始,每隔5分触发) 0 15 10 ? * MON-FRI 从周一到周五每天上午的10点15分触发 0 15 10 ? * 6#3 每月的第三周的星期五开始触发 0 15 10 ? * 6L 2016~2017 从2016~2017年每月最后一周的星期五的10点15分触发 - 可借助在线生成器进行规则生成
-
Scheduler
- 调度器,所有的Scheduler实例应该由SchedulerFactory来创建
- 主要函数:
- Date scheduleJob(JobDetail jobDetail,Trigger trigger);绑定任务和触发器
- void start();开启调度器
- void standby();暂停任务,挂起,再次start可继续执行任务
- void shutdown(true/false);终止任务,参数为true时等待任务全部执行完毕后关闭,参数为false直接关闭。
- StdSchedulerFactory:
- 使用一组参数(java.util.Properties)来创建和初始化Quartz调度器。
- 配置参数一般存储在quartz.properties中
- 调用getScheduler方法就能创建和初始化调度器对象。
SchedulerFactory sfact = new StdSchedulerFactory();
Scheduler scheduler = sfact.getScheduler();
DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();
Scheduler scheduler = factory.getScheduler();
配置文件
- quartz.properties文件组成部分:
- 调度器属性:
- org.quartz.scheduler.instanceName属性用来区分特定的调度器实例,可以按照功能用途来给调度器起名
- org.quartz.scheduler.instanceId属性和前者一样,也允许任何字符串,但这个值必须是在所有调度器实例中是唯一的,尤其是在一个集群中,作为集群的唯一key。假如想让quartz自动生成这个值得话,可以设置为AUTO
- 作业存储设置:描述了在调度器实例的生命周期中,Job和Trigger信息是如何被存储的。
- 线程池属性:
- threadCount
- threadPriority
- org.quartz.threadPool.class
- 插件配置:满足特定需求用到的quartz插件配置
- 调度器属性:
定时任务并发
- 比如一个任务需要执行7s,但是任务每5s执行一次
- 使用@DisallowConcurrentExecution防止并发
- 把注解加在job类上
错过机制
- Misfire机制:
整合WEB
<dependencies>
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
- quartz.properties
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# ===========================================================================
# Configure Main Scheduler Properties 调度器属性
# ===========================================================================
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.instanceid:AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
# ===========================================================================
# Configure ThreadPool 线程池属性
# ===========================================================================
#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
#指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
org.quartz.threadPool.threadCount: 10
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority: 5
#设置SimpleThreadPool的一些属性
#设置是否为守护线程
#org.quartz.threadpool.makethreadsdaemons = false
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
#org.quartz.threadpool.threadsinheritgroupofinitializingthread=false
#线程前缀默认值是:[Scheduler Name]_Worker
#org.quartz.threadpool.threadnameprefix=swhJobThead;
# 配置全局监听(TriggerListener,JobListener) 则应用程序可以接收和执行 预定的事件通知
# ===========================================================================
# Configuring a Global TriggerListener 配置全局的Trigger监听器
# MyTriggerListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串)
# ===========================================================================
#org.quartz.triggerListener.NAME.class = com.swh.MyTriggerListenerClass
#org.quartz.triggerListener.NAME.propName = propValue
#org.quartz.triggerListener.NAME.prop2Name = prop2Value
# ===========================================================================
# Configuring a Global JobListener 配置全局的Job监听器
# MyJobListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串)
# ===========================================================================
#org.quartz.jobListener.NAME.class = com.swh.MyJobListenerClass
#org.quartz.jobListener.NAME.propName = propValue
#org.quartz.jobListener.NAME.prop2Name = prop2Value
# ===========================================================================
# Configure JobStore 存储调度信息(工作,触发器和日历等)
# ===========================================================================
# 信息保存时间 默认值60秒
org.quartz.jobStore.misfireThreshold: 60000
#保存job和Trigger的状态信息到内存中的类
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
# ===========================================================================
# Configure SchedulerPlugins 插件属性 配置
# ===========================================================================
# 自定义插件
#org.quartz.plugin.NAME.class = com.swh.MyPluginClass
#org.quartz.plugin.NAME.propName = propValue
#org.quartz.plugin.NAME.prop2Name = prop2Value
#配置trigger执行历史日志(可以看到类的文档和参数列表)
org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin
org.quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}
org.quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}
#配置job调度插件 quartz_jobs(jobs and triggers内容)的XML文档
#加载 Job 和 Trigger 信息的类 (1.8之前用:org.quartz.plugins.xml.JobInitializationPlugin)
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
#指定存放调度器(Job 和 Trigger)信息的xml文件,默认是classpath下quartz_jobs.xml
org.quartz.plugin.jobInitializer.fileNames = my_quartz_job2.xml
#org.quartz.plugin.jobInitializer.overWriteExistingJobs = false
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
#自动扫描任务单并发现改动的时间间隔,单位为秒
org.quartz.plugin.jobInitializer.scanInterval = 10
#覆盖任务调度器中同名的jobDetail,避免只修改了CronExpression所造成的不能重新生效情况
org.quartz.plugin.jobInitializer.wrapInUserTransaction = false
# ===========================================================================
# Sample configuration of ShutdownHookPlugin ShutdownHookPlugin插件的配置样例
# ===========================================================================
#org.quartz.plugin.shutdownhook.class = \org.quartz.plugins.management.ShutdownHookPlugin
#org.quartz.plugin.shutdownhook.cleanShutdown = true
#
# Configure RMI Settings 远程服务调用配置
#
#如果你想quartz-scheduler出口本身通过RMI作为服务器,然后设置“出口”标志true(默认值为false)。
#org.quartz.scheduler.rmi.export = false
#主机上rmi注册表(默认值localhost)
#org.quartz.scheduler.rmi.registryhost = localhost
#注册监听端口号(默认值1099)
#org.quartz.scheduler.rmi.registryport = 1099
#创建rmi注册,false/never:如果你已经有一个在运行或不想进行创建注册
# true/as_needed:第一次尝试使用现有的注册,然后再回来进行创建
# always:先进行创建一个注册,然后再使用回来使用注册
#org.quartz.scheduler.rmi.createregistry = never
#Quartz Scheduler服务端端口,默认是随机分配RMI注册表
#org.quartz.scheduler.rmi.serverport = 1098
#true:链接远程服务调度(客户端),这个也要指定registryhost和registryport,默认为false
# 如果export和proxy同时指定为true,则export的设置将被忽略
#org.quartz.scheduler.rmi.proxy = false
- Job
public class HelloJob implements Job {
public void execute(JobExecutionContext context)
throws JobExecutionException {
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 打印当前的执行时间,格式为2017-01-01 00:00:00
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Exec Time Is : " + sf.format(date));
System.out.println("Hello World");
}
}
- Scheduler
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException, InterruptedException {
// 打印当前的时间,格式为2017-01-01 00:00:00
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time Is : " + sf.format(date));
// 创建一个JobDetail实例,将该实例与HelloJob Class绑定
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob").build();
CronTrigger trigger = (CronTrigger) TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("* * * * * ?"))
.build();
// 创建Scheduler实例
SchedulerFactory sfact = new StdSchedulerFactory();
Scheduler scheduler = sfact.getScheduler();
scheduler.start();
System.out.println("scheduled time is :"
+ sf.format(scheduler.scheduleJob(jobDetail, trigger)));
//scheduler执行两秒后挂起
Thread.sleep(2000L);
//shutdown(true)表示等待所有正在执行的job执行完毕之后,再关闭scheduler
//shutdown(false)即shutdown()表示直接关闭scheduler
scheduler.shutdown(false);
System.out.println("scheduler is shut down? " + scheduler.isShutdown());
}
}
整合spring
- 整合spring有两种方式:MethodInvokingJobDetailFactoryBean,JobDetailFactoryBean
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
- web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Archetype Created Web Application</display-name>
<!-- spring MVC的核心就是DispatcherServlet,使用springMVC的第一步就是将下面的servlet放入web.xml
servlet-name属性非常重要,默认情况下,DispatchServlet会加载这个名字-servlet.xml的文件,如下,就会加载 dispather-servlet.xml,也是在WEN-INF目录下。 -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 设置dispatchservlet的匹配模式,通过把dispatchservlet映射到/,默认servlet会处理所有的请求,包括静态资源 -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
- dispatcher-servlet.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" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
default-lazy-init="true">
<!-- 通过mvc:resources设置静态资源,这样servlet就会处理这些静态资源,而不通过控制器 -->
<!-- 设置不过滤内容,比如:css,jquery,img 等资源文件 -->
<mvc:resources location="/*.html" mapping="/**.html" />
<mvc:resources location="/css/*" mapping="/css/**" />
<mvc:resources location="/js/*" mapping="/js/**" />
<mvc:resources location="/images/*" mapping="/images/**" />
<!-- 设定消息转换的编码为utf-8防止controller返回中文乱码 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
<!-- 添加注解驱动 -->
<mvc:annotation-driven />
<!-- 默认扫描的包路径 -->
<context:component-scan base-package="com.imooc.springquartz" />
<!-- mvc:view-controller可以在不需要Controller处理request的情况,转向到设置的View -->
<!-- 像下面这样设置,如果请求为/,则不通过controller,而直接解析为/index.jsp -->
<mvc:view-controller path="/" view-name="index" />
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView"></property>
<!-- 配置jsp路径前缀 -->
<property name="prefix" value="/"></property>
<!-- 配置URl后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 第一种作业 -->
<bean id="simpleJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myBean" />
<property name="targetMethod" value="printMessage" />
</bean>
<!-- 第二种作业 -->
<bean id="firstComplexJobDetail"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass"
value="com.imooc.springquartz.quartz.FirstScheduledJob" />
<property name="jobDataMap">
<map>
<entry key="anotherBean" value-ref="anotherBean" />
</map>
</property>
<property name="Durability" value="true"/>
</bean>
<!-- 简单触发器,距离当前时间1秒之后执行,之后每隔两秒钟执行一次 -->
<bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="simpleJobDetail"/>
<property name="startDelay" value="1000"/>
<property name="repeatInterval" value="2000"/>
</bean>
<!-- cron触发器,每隔5秒钟执行一次 -->
<bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="firstComplexJobDetail"/>
<property name="cronExpression" value="0/5 * * ? * *"/>
</bean>
<!-- 绑定作业任务和触发器 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="simpleJobDetail"/>
<ref bean="firstComplexJobDetail"/>
</list>
</property>
<property name="triggers">
<list>
<ref bean="mySimpleTrigger"/>
<ref bean="myCronTrigger"/>
</list>
</property>
</bean>
</beans>
- AnotherBean
@Component("anotherBean")
public class AnotherBean {
public void printAnotherMessage() {
System.out.println("AnotherMessage");
}
}
- FirstScheduledJob
public class FirstScheduledJob extends QuartzJobBean{
private AnotherBean anotherBean;
public void setAnotherBean(AnotherBean anotherBean){
this.anotherBean = anotherBean;
}
@Override
protected void executeInternal(JobExecutionContext arg0)
throws JobExecutionException {
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("FirstScheduledJob Executes!" + sf.format(date));
this.anotherBean.printAnotherMessage();
}
}
- MyBean
@Component("myBean")
public class MyBean {
public void printMessage() {
// 打印当前的执行时间,格式为2017-01-01 00:00:00
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("MyBean Executes!" + sf.format(date));
}
}
整合springboot
- maven
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
- 配置文件
spring.quartz.scheduler-name=mySpringbootQuartz
spring.quartz.job-store-type=jdbc
spring.quartz.overwrite-existing-jobs=true
spring.quartz.jdbc.initialize-schema=never
spring.quartz.jdbc.comment-prefix=#
spring.quartz.wait-for-jobs-to-complete-on-shutdown=true
spring.datasource.url=jdbc:mysql://localhost:3306/order?serverTimezone=Asia/Shanghai&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
logging.pattern.dateformat=HH:mm:ss
mybatis.mapper-locations=mybatis/*.xml
- 作业
@Slf4j
public class MyJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
log.info("我正在执行!");
}
}
- quartz配置类
@Configuration
public class QuartzConfig {
@Bean
public JobDetail myJobDetail(){
JobDetail detail = JobBuilder.newJob(MyJob.class)
.withIdentity("myjob","group1")
.storeDurably()
.build();
return detail;
}
@Bean
public Trigger myTrigger1(){
Trigger trigger = TriggerBuilder.newTrigger()
.startNow()
.withIdentity("myjobTrigger1","group1")
.forJob(myJobDetail())
.withSchedule(CronScheduleBuilder.cronSchedule("0/15 * * * * ?")
).build();
return trigger;
}
}
TriggerListener详解
- 监听与监听器(trigger)有关的事件
- 触发器开始:triggerFired
- 触发器结束:triggerComplete
- 触发器否决:vetoJobExecution
API
- trigger监听器,实际案例:节假日不执行任务
public class MyTriggerListener extends TriggerListenerSupport {
@Override
public String getName() {
return "myTriggerListener";
}
@Override
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
System.out.println("vetoJobExecution正在执行!!");
//如果时间是5,15,25,尾数是5的时间点,就不执行
Calendar now = Calendar.getInstance();
int second = now.get(Calendar.SECOND);
if (second % 10 ==5){
System.out.println("本次Trigger不触发!!");
return true;
}
return false;
}
}
- 主程序类
scheduler.getListenerManager().addTriggerListener(new MyTriggerListener());
spring
- trigger
public class MyListener extends TriggerListenerSupport {
@Override
public String getName() {
return "myTriggerListener";
}
@Override
public void triggerFired(Trigger trigger, JobExecutionContext context) {
super.triggerFired(trigger, context);
LocalTime now = LocalTime.now();
System.out.println(now.toString()+"Trigger is fired!!");
}
}
- xml
<bean id="myTriggerListener" class="com.example.job.listener.MyListener"/>
<bean id="schedule" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" destroy-method="destroy">
<property name="dataSource" ref="datasource"/>
<property name="triggers">
<list>
<ref bean="trigger1"/>
<ref bean="trigger2"/>
</list>
</property>
<property name="globalTriggerListeners">
<list>
<ref bean="myTriggerListener"/>
</list>
</property>
</bean>
JobListener详解
- 监听job相关事件
- 主要事件:job即将执行,job完成执行
API
- 实际案例:记录作业的执行时间
- 引入dbcp2和mysql的pom
- 编写监听器
public class MyJobListener extends JobListenerSupport {
@Override
public String getName() {
return "myJobListener";
}
@Override
public void jobToBeExecuted(JobExecutionContext context) {
super.jobToBeExecuted(context);
LocalTime now = LocalTime.now();
System.out.println(now.toString()+"jobToBeExecuted");
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setUrl("jdbc:mysql://localhost:3306/order?serverTimezone=Asia/Shanghai&useSSL=false");
try {
dataSource.setDriver(new Driver());
} catch (SQLException e) {
e.printStackTrace();
}
DataSourceConnectionFactory connectionFactory = new DataSourceConnectionFactory(dataSource);
try {
Connection connection = connectionFactory.createConnection();
PreparedStatement preparedStatement = connection.prepareStatement("insert into quartz_job_log (job_name,type,time) values (?,?,?)");
preparedStatement.setString(1,context.getJobDetail().getKey().toString());
preparedStatement.setInt(2,1);
preparedStatement.setTime(3,new Time(new Date().getTime()));
preparedStatement.execute();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
dataSource.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
super.jobWasExecuted(context, jobException);
LocalTime now = LocalTime.now();
System.out.println(now.toString()+"jobWasExecuted");
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setUrl("jdbc:mysql://localhost:3306/order?serverTimezone=Asia/Shanghai&useSSL=false");
try {
dataSource.setDriver(new Driver());
} catch (SQLException e) {
e.printStackTrace();
}
DataSourceConnectionFactory connectionFactory = new DataSourceConnectionFactory(dataSource);
try {
Connection connection = connectionFactory.createConnection();
PreparedStatement preparedStatement = connection.prepareStatement("insert into quartz_job_log (job_name,type,time) values (?,?,?)");
preparedStatement.setString(1,context.getJobDetail().getKey().toString());
preparedStatement.setInt(2,2);
preparedStatement.setTime(3,new Time(new Date().getTime()));
preparedStatement.execute();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
dataSource.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 注册监听器
scheduler.getListenerManager().addJobListener(new MyJobListener());
spring
- 编写监听器
public class MyJobListener extends JobListenerSupport {
@Override
public String getName() {
return "myJobListener";
}
private DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void jobToBeExecuted(JobExecutionContext context) {
super.jobToBeExecuted(context);
LocalTime now = LocalTime.now();
System.out.println(now.toString()+"jobToBeExecuted");
DataSourceConnectionFactory connectionFactory = new DataSourceConnectionFactory(dataSource);
try {
Connection connection = connectionFactory.createConnection();
PreparedStatement preparedStatement = connection.prepareStatement("insert into quartz_job_log (job_name,type,time) values (?,?,?)");
preparedStatement.setString(1,context.getJobDetail().getKey().toString());
preparedStatement.setInt(2,1);
preparedStatement.setTime(3,new Time(new Date().getTime()));
preparedStatement.execute();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
super.jobWasExecuted(context, jobException);
LocalTime now = LocalTime.now();
System.out.println(now.toString()+"jobWasExecuted");
DataSourceConnectionFactory connectionFactory = new DataSourceConnectionFactory(dataSource);
try {
Connection connection = connectionFactory.createConnection();
PreparedStatement preparedStatement = connection.prepareStatement("insert into quartz_job_log (job_name,type,time) values (?,?,?)");
preparedStatement.setString(1,context.getJobDetail().getKey().toString());
preparedStatement.setInt(2,2);
preparedStatement.setTime(3,new Time(new Date().getTime()));
preparedStatement.execute();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- xml
<bean id="datasource" destroy-method="close" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="url" value="jdbc:mysql://localhost:3306/order?serverTimezone=Asia/Shanghai&useSSL=false"/>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>
<bean id="myJobListener" class="com.example.job.listener.MyJobListener">
<property name="dataSource" ref="datasource"/>
</bean>
<bean id="schedule" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" destroy-method="destroy">
<property name="dataSource" ref="datasource"/>
<property name="triggers">
<list>
<ref bean="trigger1"/>
<ref bean="trigger2"/>
</list>
</property>
<property name="globalJobListeners">
<list>
<ref bean="myJobListener"/>
</list>
</property>
</bean>
SchedulerListener详解
API
- 记录定时任务的启停
- 编写监听器
public class MySchedulerListener extends SchedulerListenerSupport {
@Override
public void schedulerStarting() {
super.schedulerStarting();
LocalTime now = LocalTime.now();
System.out.println(now.toString()+",schedulerStarting!!");
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setUrl("jdbc:mysql://localhost:3306/order?serverTimezone=Asia/Shanghai&useSSL=false");
try {
dataSource.setDriver(new Driver());
} catch (SQLException e) {
e.printStackTrace();
}
DataSourceConnectionFactory connectionFactory = new DataSourceConnectionFactory(dataSource);
try {
Connection connection = connectionFactory.createConnection();
PreparedStatement preparedStatement = connection.prepareStatement("insert into quartz_scheduler_log (ip,type,time) values (?,?,?)");
String ip = InetAddress.getLocalHost().getHostAddress();
preparedStatement.setString(1,ip);
preparedStatement.setInt(2,1);
preparedStatement.setTime(3,new Time(new Date().getTime()));
preparedStatement.execute();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
}
try {
dataSource.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void schedulerShuttingdown() {
super.schedulerShuttingdown();
LocalTime now = LocalTime.now();
System.out.println(now.toString()+",schedulerShuttingdown!!");
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setUrl("jdbc:mysql://localhost:3306/order?serverTimezone=Asia/Shanghai&useSSL=false");
try {
dataSource.setDriver(new Driver());
} catch (SQLException e) {
e.printStackTrace();
}
DataSourceConnectionFactory connectionFactory = new DataSourceConnectionFactory(dataSource);
try {
Connection connection = connectionFactory.createConnection();
PreparedStatement preparedStatement = connection.prepareStatement("insert into quartz_scheduler_log (ip,type,time) values (?,?,?)");
String ip = InetAddress.getLocalHost().getHostAddress();
preparedStatement.setString(1,ip);
preparedStatement.setInt(2,2);
preparedStatement.setTime(3,new Time(new Date().getTime()));
preparedStatement.execute();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
}
try {
dataSource.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 注册监听器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.getListenerManager().addSchedulerListener(new MySchedulerListener());
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
super.run();
try {
scheduler.shutdown();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
});
scheduler.start();
spring
- 编写监听器
public class MySchedulerListener extends SchedulerListenerSupport {
@Override
public void schedulerStarting() {
super.schedulerStarting();
LocalTime now = LocalTime.now();
System.out.println(now.toString()+",schedulerStarting!!");
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setUrl("jdbc:mysql://localhost:3306/order?serverTimezone=Asia/Shanghai&useSSL=false");
try {
dataSource.setDriver(new Driver());
} catch (SQLException e) {
e.printStackTrace();
}
DataSourceConnectionFactory connectionFactory = new DataSourceConnectionFactory(dataSource);
try {
Connection connection = connectionFactory.createConnection();
PreparedStatement preparedStatement = connection.prepareStatement("insert into quartz_scheduler_log (ip,type,time) values (?,?,?)");
String ip = InetAddress.getLocalHost().getHostAddress();
preparedStatement.setString(1,ip);
preparedStatement.setInt(2,1);
preparedStatement.setTime(3,new Time(new Date().getTime()));
preparedStatement.execute();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
}
try {
dataSource.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void schedulerShutdown() {
super.schedulerShuttingdown();
LocalTime now = LocalTime.now();
System.out.println(now.toString()+",schedulerShuttingdown!!");
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setUrl("jdbc:mysql://localhost:3306/order?serverTimezone=Asia/Shanghai&useSSL=false");
try {
dataSource.setDriver(new Driver());
} catch (SQLException e) {
e.printStackTrace();
}
DataSourceConnectionFactory connectionFactory = new DataSourceConnectionFactory(dataSource);
try {
Connection connection = connectionFactory.createConnection();
PreparedStatement preparedStatement = connection.prepareStatement("insert into quartz_scheduler_log (ip,type,time) values (?,?,?)");
String ip = InetAddress.getLocalHost().getHostAddress();
preparedStatement.setString(1,ip);
preparedStatement.setInt(2,2);
preparedStatement.setTime(3,new Time(new Date().getTime()));
preparedStatement.execute();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
}
try {
dataSource.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- xml
<bean id="mySchedulerListener" class="com.example.job.listener.MySchedulerListener"/>
<bean id="schedule" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" destroy-method="destroy">
<property name="dataSource" ref="datasource"/>
<property name="triggers">
<list>
<ref bean="trigger1"/>
<ref bean="trigger2"/>
</list>
</property>
<property name="schedulerListeners">
<list>
<ref bean="mySchedulerListener"/>
</list>
</property>
</bean>
<bean id="datasource" destroy-method="close" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="url" value="jdbc:mysql://localhost:3306/order?serverTimezone=Asia/Shanghai&useSSL=false"/>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>
quartz集群
- 支持失效转义,不支持分布式
- 案例:按小时统计订单数量