一、quartz的简单配置
1、引入定时器的maven包
<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>
<!-- >>>>SpringBoot替换为:>>>>-->
<!--quartz依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2、加注解简单实用
@Component
@Configurable
@EnableScheduling //启动定时任务
public class SendMailQuartz {
//日志对象
private static final Logger logger = LogManager.getLogger(SendMailQuartz.class);
//每5秒执行一次
@Scheduled(cron = "*/5 * * * * * ")
public void reportCurrentByCron(){
logger.info("定时器运行五秒一次!!!");
}
@Scheduled(fixedDelay = 100*30)
public void test() {
System.out.println("定时器第一个执行");
}
//每5秒执行一次
@Scheduled(cron = "*/5 * * * * * ")
public void test2() {
System.out.println("定时器第二个执行");
}
//每1分针执行一次
@Scheduled(cron = "0 */1 * * * * ")
public void test3() {
System.out.println("定时器第三个执行");
}
}
二、实用xml方式引入定时器Quartz
1、上面引入了Quartz的依赖,下面的方法都实用上面的依赖,开始引入spring-mvc.xml,里面引入spring-quartz.xml
<import resource="spring-quartz.xml"/>
完整的spring-mvc.xml如下所示
<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:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd">
<context:annotation-config/>
<!-- 利用import引入定时器的文件 -->
<import resource="spring-quartz.xml"/>
</beans>
2、引入spring-quartz.xml文件
(1)、这个引入所执行的类,并注入到Spring容器中, 中间的这个,如果要做动态调度执行时间,则不能缺少,<property name="scheduler" ref="scheduler"></property>
<bean id="taskJob" class="com.nswi.quartz.TestTask">
<property name="scheduler" ref="scheduler"></property>
</bean>
(2)、通过Id引入上面的类,并 导入需要执行的类中的方法
<bean id="jobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="taskJob"/>
</property>
<!-- 执行的方法-->
<property name="targetMethod">
<value>run</value>
</property>
<!-- 上一次未执行完成的,要等待有再执行。 -->
<property name="concurrent" value="false"></property>
</bean>
(3)、执行调度方法的执行时间,和执行次数都可以在这个里面配置,配置的value是毫秒,一秒等于1000毫秒,以及执行重复次数repeatCount,调用间隔时间repeatInterval
<bean id="testTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"></property>
<!-- 启动开始时间延迟一秒-->
<property name="startDelay" value="1000"></property>
<!-- 每次时间间隔2秒 2000 -->
<!-- 时间间隔俩分钟-->
<property name="repeatInterval" value="20000"></property>
<!-- 执行重复次数-->
<!-- <property name="repeatCount" value="0" />-->
</bean>
(4)、调度工厂执行调度任务
<bean id="scheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="testTrigger"/>
</list>
</property>
</bean>
完整的spring-quartz.xml如下所示
<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-3.0.xsd">
<!-- <bean id="taskJob" class="com.nswi.quartz.TestTask"/>-->
<bean id="taskJob" class="com.nswi.quartz.TestTask">
<property name="scheduler" ref="scheduler"></property>
</bean>
<bean id="jobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="taskJob"/>
</property>
<!-- 执行的方法-->
<property name="targetMethod">
<value>run</value>
</property>
<!-- 上一次未执行完成的,要等待有再执行。 -->
<property name="concurrent" value="false"></property>
</bean>
<!-- 调度触发器 -->
<!-- <bean id="myTrigger"-->
<!-- class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">-->
<!-- <property name="jobDetail">-->
<!-- <ref bean="jobDetail" />-->
<!-- </property>-->
<!-- <property name="cronExpression">-->
<!-- <value>0/5 * * * * ?</value>-->
<!-- </property>-->
<!-- </bean>-->
<bean id="testTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"></property>
<!-- 启动开始时间延迟一秒-->
<property name="startDelay" value="1000"></property>
<!-- 每次时间间隔2秒 2000 -->
<!-- 时间间隔俩分钟-->
<property name="repeatInterval" value="20000"></property>
<!-- 执行重复次数-->
<!-- <property name="repeatCount" value="0" />-->
</bean>
<!-- 调度工厂 -->
<bean id="scheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="testTrigger"/>
</list>
</property>
</bean>
</beans>
3、在启动器上面引入spring-mvc.xml,间接引入spring-quartz.xml
@SpringBootApplication
@ImportResource(locations={"classpath:spring-mvc.xml"})
public class QuartzCgqApplication {
public static void main(String[] args) {
SpringApplication.run(QuartzCgqApplication.class, args);
}
}
4、配置执行类,和执行方法,这样,启动后会自动执行,这个类下面标记的方法,这里设置的是run方法,
package com.nswi.quartz;
import com.nswi.entity.CgqCall;
import com.nswi.entity.CgqType;
import com.nswi.entity.CgqTypeDetails;
import com.nswi.mapper.CgqTypeMapper;
import com.nswi.mod.ModbusRtuMaster;
import com.nswi.service.ICgqCallService;
import com.nswi.service.ICgqTypeDetailsService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerKey;
import org.quartz.impl.triggers.SimpleTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* 描述:定时器类
*/
public class TestTask {
public void run() {
System.out.println("执行了这个方法");
}
private Scheduler scheduler;
public Scheduler getScheduler() {
return scheduler;
}
public void setScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
public void restJob(long time) {
TriggerKey triggerKey = new TriggerKey("testTrigger", Scheduler.DEFAULT_GROUP);
SimpleTriggerImpl simpleTrigger = null;
try {
simpleTrigger = (SimpleTriggerImpl) scheduler.getTrigger(triggerKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
simpleTrigger.setRepeatInterval(time);
try {
scheduler.rescheduleJob(triggerKey, simpleTrigger);
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
下面的配置,是为了动态调用方法,用来改变quartz执行的间隔时间
private Scheduler scheduler;
public Scheduler getScheduler() {
return scheduler;
}
public void setScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
public void restJob(long time) {
TriggerKey triggerKey = new TriggerKey("testTrigger", Scheduler.DEFAULT_GROUP);
SimpleTriggerImpl simpleTrigger = null;
try {
simpleTrigger = (SimpleTriggerImpl) scheduler.getTrigger(triggerKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
simpleTrigger.setRepeatInterval(time);
try {
scheduler.rescheduleJob(triggerKey, simpleTrigger);
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
5、动态调用接口,来改变quartz的执行间隔
其中value的taskJob来自于xml中的配置
@Autowired
@Qualifier(value = "taskJob")
private TestTask job;
<bean id="taskJob" class="com.nswi.quartz.TestTask">
<property name="scheduler" ref="scheduler"></property>
</bean>
6、 完整的接口配置,如下所示,通过简单调用接口方式,动态调节定时器执行时间
@Autowired
@Qualifier(value = "taskJob")
private TestTask job;
//两分钟一次
private static Long Time1 = 120000L;
//五分钟一次
private static Long Time2 = 300000L;
//10分钟一次
private static Long Time3 = 600000L;
@GetMapping("/job/{time}/{key}")
@ResponseBody
public Result job(@PathVariable("time") Long time,@PathVariable("key") String key) {
if (key.equals("wwjsj")&& time!=null) {
if(time==2){
System.out.println("调整为2分钟");
job.restJob(Time1);
}else if(time==5){
System.out.println("调整为5分钟");
job.restJob(Time2);
}else {
System.out.println("调整为10分钟");
job.restJob(Time3);
}
}
System.out.println(time);
return Result.ok(key);
}
三、自定义定时器的启动,删除,暂停
工具类如下所示
1、定时器的增加的方法
private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
/**
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param jobClass 任务
* @param cron 时间设置,参考quartz说明文档
* @Description: 添加一个定时任务
*/
//SuppressWarnings 用于抑制编译器产生警告信息
@SuppressWarnings({"unchecked", "rawtypes"})
public static void addJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName, Class jobClass, String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
// 任务名,任务组,任务执行类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
sched.scheduleJob(jobDetail, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
2、定时器修改触发时间
/**
* @param jobName
* @param jobGroupName
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param cron 时间设置,参考quartz说明文档
* @Description: 修改一个任务的触发时间
*/
public static void modifyJobTime(String jobName,
String jobGroupName, String triggerName, String triggerGroupName, String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
/** 方式一 :调用 rescheduleJob 开始 */
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
sched.rescheduleJob(triggerKey, trigger);
/** 方式一 :调用 rescheduleJob 结束 */
/** 方式二:先删除,然后在创建一个新的Job */
//JobDetail jobDetail = sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
//Class<? extends Job> jobClass = jobDetail.getJobClass();
//removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
//addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);
/** 方式二 :先删除,然后在创建一个新的Job */
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
3、移除某一任务
/**
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
* @Description: 移除一个任务
*/
public static void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
4、启动所有定时任务
/**
* @Description:启动所有定时任务
*/
public static void startJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
5、关闭所有定时器
/**
* @Description:关闭所有定时任务
*/
public static void shutdownJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
这个工具类完整的如下
package com.nswi.quartz;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzManager {
private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
/**
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param jobClass 任务
* @param cron 时间设置,参考quartz说明文档
* @Description: 添加一个定时任务
*/
//SuppressWarnings 用于抑制编译器产生警告信息
@SuppressWarnings({"unchecked", "rawtypes"})
public static void addJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName, Class jobClass, String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
// 任务名,任务组,任务执行类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
sched.scheduleJob(jobDetail, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @param jobName
* @param jobGroupName
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param cron 时间设置,参考quartz说明文档
* @Description: 修改一个任务的触发时间
*/
public static void modifyJobTime(String jobName,
String jobGroupName, String triggerName, String triggerGroupName, String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
/** 方式一 :调用 rescheduleJob 开始 */
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
sched.rescheduleJob(triggerKey, trigger);
/** 方式一 :调用 rescheduleJob 结束 */
/** 方式二:先删除,然后在创建一个新的Job */
//JobDetail jobDetail = sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
//Class<? extends Job> jobClass = jobDetail.getJobClass();
//removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
//addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);
/** 方式二 :先删除,然后在创建一个新的Job */
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
* @Description: 移除一个任务
*/
public static void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:启动所有定时任务
*/
public static void startJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:关闭所有定时任务
*/
public static void shutdownJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
执行的方法如下所示
1、执行的类继承Job类,然后实现它的excute方法
MyJob implements Job
public class MyJob implements Job {
@Autowired
CgqTypeMapper cgqTypeMapper;
int i = 1;
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Date date = new Date();
System.out.println(date);
i++;
System.out.println(i);
cgqTypeMapper = (CgqTypeMapper) SpringContextJobUtil.getBean("cgqTypeMapper");
List<CgqType> cgqTypes = cgqTypeMapper.selectAll();
try {
cgqTypes.forEach(System.out::println);
System.out.println(cgqTypes.size() + "个");
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、调用方法如下
public class Test {
public static String JOB_NAME = "动态任务调度";
public static String TRIGGER_NAME = "动态任务触发器";
public static String JOB_GROUP_NAME = "XLXXCC_JOB_GROUP";
public static String TRIGGER_GROUP_NAME = "XLXXCC_JOB_GROUP";
public static void main(String[] args) {
try {
System.out.println("【系统启动】开始(每5秒输出一次)...");
QuartzManager.addJob(JOB_NAME, JOB_GROUP_NAME, TRIGGER_NAME, TRIGGER_GROUP_NAME, MyJob.class, "0/5 * * * * ?");
// Thread.sleep(5000);
// System.out.println("【修改时间】开始(每5秒输出一次)...");
// QuartzManager.modifyJobTime(JOB_NAME, JOB_GROUP_NAME, TRIGGER_NAME, TRIGGER_GROUP_NAME, "0/5 * * * * ?");
// Thread.sleep(6000);
// System.out.println("【移除定时】开始...");
// QuartzManager.removeJob(JOB_NAME, JOB_GROUP_NAME, TRIGGER_NAME, TRIGGER_GROUP_NAME);
// System.out.println("【移除定时】成功");
} catch (Exception e) {
e.printStackTrace();
}
}
}
四、对比两种动态调用定时器的不同
1、xml 方式比较灵活简单,可以定时执行某个类下面具体的方法
2、采用继承job,只能执行excute的方法,因为输入的是 MyJob.class,这样的class文件,所以如果使用Spring容器中的某个bean,会出现找不到bean的问题。所以我建立了一个方法类如下,上面的excute方法中有使用到这个方法类
@Component
public class SpringContextJobUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
@SuppressWarnings("static-access" )
public void setApplicationContext(ApplicationContext contex)
throws BeansException {
// TODO Auto-generated method stub
this.context = contex;
}
public static Object getBean(String beanName){
return context.getBean(beanName);
}
public static String getMessage(String key){
return context.getMessage(key, null, Locale.getDefault());
}
}
3、引用方式如下(我这里使用MybatisPlus的Mapper层的SelectAll)
@Autowired
CgqTypeMapper cgqTypeMapper;
cgqTypeMapper = (CgqTypeMapper) SpringContextJobUtil.getBean("cgqTypeMapper");
List<CgqType> cgqTypes = cgqTypeMapper.selectAll();