定时任务两种方式,Spring很好的封装使用Quartz的细节,第一种方式是利用SPring封装的Quartz类进行特定方法的实现,第二种是通过透明的使用Quartz达到定时任务开发的目的,总体说第二种对开发人员更方便!
配置Spring的任务调度抽象层简化了任务调度,在Quartz的基础上提供了更好的调度对象。Spring使用Quartz框架来完成任务调度,创建Quartz的作业Bean(JobDetail)
Quartz编码思路
1)编写Job(任务) - 你想做什么?
2)编码Trigger(触发器) - 你想什么时候做?
3)编码Scheduler(任务调度): 你想什么时候做什么?
使用Java程序演示Quartz
1.导入quartz坐标
<!-- quartz任务调度 -->
<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>
2.定义一个Job(任务)
/**
* 该类须实现Job接口并重写execute方法
* execute:任务触发就调用此方法
*/
public class MyJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("任务被触发啦...."+sdf.format(new Date()));
}
}
3.编写代码创建任务调度
在Quartz分为两种触发器:
1)简单触发器(SimpleTrigger):简单地按照秒,分,小时重复。
例如:每5分钟来触发一次任务
2)日历触发器(CronTrigger):按照日历规则进行触发。(比较常用)
例如:每个星期2,4,5凌晨2点触发任务。
1).简单触发器例子
public class Demo1 {
public static void main(String[] args) throws Exception {
//1.创建Job任务
JobDetail job = JobBuilder.newJob(MyJob.class).build();
//2.创建Trigger触发器,这里使用的SimpleTrigger类
//repeatSecondlyForever: 按照秒重复,每秒重复一次
Trigger trigger = TriggerBuilder.newTrigger().withSchedule(
SimpleScheduleBuilder.repeatSecondlyForever()
).build();
//3.创建任务调度对象
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//关联Job和trigger
scheduler.scheduleJob(job, trigger);
//启动任务
scheduler.start();
}
}
2).日历触发器
public class Demo2 {
public static void main(String[] args) throws Exception {
//1.创建Job任务
JobDetail job = JobBuilder.newJob(MyJob.class).build();
//2.创建Trigger触发器
//withSchedule:指定触发器
Trigger trigger = TriggerBuilder.newTrigger().withSchedule(
//cronSchedule:指定日历规则字符串
CronScheduleBuilder.cronSchedule("0/3 * * * * ? *")
).build();
//3.创建任务调度对象
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//关联Job和trigger
scheduler.scheduleJob(job, trigger);
//启动任务
scheduler.start();
//scheduler.shutdown();结束任务
}
}
Quartz有两大触发器,除了上面的Simpletrigger外,还有CronTrigger。CronTrigger能够提供对复杂的触发器表达式的支持。CronTrigger时基于Unix Cron守护进程的,它是一个调度程序,支持简单而强大的触发器语法。
使用Cron Trigger主要的是掌握Cron表达式。Cron表达式包含6个必要组件和1个可选组件,如下表所示。
CronTrigger组件
位置 | 含义 | 允许的特殊字符 |
---|---|---|
1 | 秒(0-59) | , - * / |
2 | 分(0-59) | , - * / |
3 | 小时(0-24) | , - * / |
4 | 日期(1-31) | , - * / ? L W C |
5 | 月(JAN-DEC或1-12) | , - * / |
6 | 星期(SUN-SAT或1-7) | , - * / ? L C # |
7 | 年(可选,1970-2099),若为空,表示全部时间范围 | , - * / |
特殊字符含义
特殊字符 | 说明 |
---|---|
* | 通配符,任意值 |
? | 无特定值。通常和其他指定的值一起使用,表示必须显示该值但不能检查 |
- | 范围。e.g.小时域中10-12表示10:00,11:00,12:00 |
, | 列分隔符。可以让你指定一系列的值。e.g.在星期域中指定MON,TUE和WED |
/ | 增量。表示一个值的增量。e.g.分钟域中0/1表示从0开始,每次增加1min |
L | 表示Last。它在日期域和星期域中表示有所不同。在日期域中,表示这个月的最后一天,而在星期域中永远是7(即星期六)。当你希望使用星期域中的某一天时,L字符非常有用。e.g.星期域中6L表示每个月的最后一个星期五 |
W | 在本月内里当天最近的工作日出发,所谓的最近工作日,即当天到工作日的前后最短距离,如果当天即为工作日,则距离为0;所谓本月内是指不能跨月渠道最近工作日,即使前/后月份的最后一天或者第一天满足最近工作日的条件。e.g.LW表示这个月的追后一个工作日触发,W强烈依赖于月份 |
# | 表示该月的第几个星期,e.g.1#2表示每个月第一个星期的星期一 |
C | 日历值。日历值时更具一个给定的日历计算出来的。在日历值域中给定一个20C将在20日(日历包括20日)或20日后日历中包含的第一天(不包括20日)激活触发器。e.g.在星期域中使用6C表示日历中星期五(日历包括星期五)或者第一天(日历不包括星期五) |
Cron表达式举例:
“30 * * * * ?”每半分钟触发任务
“30 10 * * * ?"每小时的10分30秒触发任务
”30 10 1 * * ?“每天的1点10分30秒触发任务
”30 10 1 20 * ?“每月20号的1点10分30秒触发任务
”30 10 1 20 10 ? *“每年的10月20号的1点10分30秒触发任务
”30 10 1 30 10 ? 2011“2011年的10月20号1点10分30秒触发任务
”30 10 1 ? 10 * 2011“2011年的10月每天1点10分30秒触发任务
”30 10 1 ? 10 SUN 2011“2011年的10月的每个星期天的1点10分30秒触发任务
”15,30,45 * * * * ?“每15秒,30秒,45秒触发任务
”15-45 * * * *?“在15到45秒内,每秒都触发任务
”15/5 * * * *?“每分钟的15秒开始触发,每隔5秒触发一次
”15-30/5 * * * * ?“每分钟的15秒到30秒之间触发任务,每隔五秒触发一次
”0 0/3 * * * ?"每小时的0分0秒开始,每隔3分钟触发任务
“0 15 10 ? * MON-FRI"星期一到星期五的10点15分触发任务
”0 15 10 L * ?“每个月的最后一天的10点15分触发任务
”0 15 10 LW * ?"每个月的最后一个工作日的10点5分触发任务
“0 15 10 ? * 5L"每个月的最后一个星期四的10点15分触发任务
”0 15 10 ? * 5#3“每月的第3个星期的星期四的10点15分触发任务
使用Web应用Spring整合Quartz
导入quartz和spring坐标:
quartz:
<!-- quartz任务调度 -->
<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>
spring:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
定义一个任务
/**
* 该类须实现Job接口并重写execute方法
* execute:任务触发就调用此方法
*/
public class MyJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("任务被触发啦...."+sdf.format(new Date()));
}
}
1)编写applicationContext-quartz-simple.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Spring整合Quartz的配置 -->
<!-- 1.创建Job -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 关联自己的任务 -->
<property name="jobClass" value="com.jobs.MyJob"/>
</bean>
<!-- 2.创建Trigger -->
<bean id="trigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<!-- 关联JobDetail -->
<property name="jobDetail" ref="jobDetail"/>
<!-- 简单地重复( 单位:毫秒 ) -->
<!-- 重复间隔时间 -->
<property name="repeatInterval" value="3000"/>
<!-- 重复次数 -->
<property name="repeatCount" value="3"/>
</bean>
<!-- 3.创建Scheduler -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 关联trigger -->
<property name="triggers">
<array>
<ref bean="trigger"/>
</array>
</property>
</bean>
</beans>
在主配置导入
<import resource="classpath:applicationContext-quartz-simple.xml"/>
以下是第二种方式,也是比较常用的方式。CronTrigger配置
2)编写applicationContext-quartz-cron.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Spring整合Quartz的配置 -->
<!-- 1.创建Job -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 关联自己的任务 -->
<property name="jobClass" value="com.jobs.MyJob"/>
</bean>
<!-- 2.创建Trigger: CronTrigger -->
<bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 关联JobDetail -->
<property name="jobDetail" ref="jobDetail"/>
<!-- 配置cron表达式 -->
<property name="cronExpression" value="0/5 * * * * ? *"/>
</bean>
<!-- 3.创建Scheduler -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 关联trigger -->
<property name="triggers">
<array>
<ref bean="trigger"/>
</array>
</property>
</bean>
</beans>
在实际开发中,我们使用定时任务经常会遇到一个问题:quartz的job中使用autowired注解注入的对象为空,这时候我们就要使用spring-quartz提供的AdaptableJobFactory类。
解决方法:
第一步:自定义一个类:
public class MyJobFactory extends AdaptableJobFactory {
//这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入,这属于Spring的技术,不清楚的可以查看Spring的API.
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
第二步:在quartz.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 创建一个JOB -->
<bean id="JobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 关联自己的任务 -->
<property name="jobClass" value="com.jobs.PromotionJob"></property>
</bean>
<!-- 创建Trigger:ConTrigger-->
<bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 关联JobDetail -->
<property name="JobDetail" ref="JobDetail"></property>
<!-- 配置cron表达式 -->
<property name="cronExpression" value="0/5 * * * * ? *"></property>
</bean>
<!-- com.jobs.MyJobFactory -->
<bean id="jobFactory" class="com.jobs.MyJobFactory"></bean>
<!-- 创建Scheduler对象 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 覆盖原有的jobFactory -->
<property name="jobFactory" ref="jobFactory"></property>
<!-- 关联trigger -->
<property name="triggers">
<array>
<ref bean="trigger"/>
</array>
</property>
</bean>
</beans>