SpringBoot2.0集成Quartz实现动态定时任务
多任务情况下,quartz更容易管理,可以实现动态配置 执行时间表达式: 表达式示例: 微服务启动时 必须加上@EnableScheduling下面是单纯schedule 用法,简单@Scheduled(cron="0/5 * * * * ?")public void job(){System.out.println("每五秒执行一次");...
·
多任务情况下,quartz更容易管理,可以实现动态配置
执行时间表达式:
表达式示例:
微服务启动时 必须加上@EnableScheduling
下面是单纯schedule 用法,简单
@Scheduled(cron="0/5 * * * * ?")
public void job(){
System.out.println("每五秒执行一次");
}
集成Quartz
pom依赖 因为已经有这个日志文件,所以排除掉
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
下面直接上代码,其实都比较好理解
/**
*
*/
package com.matrix.cloud.service.impl;
import java.util.Map;
import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* @author lmc
* 2018年12月14日
* ApplicationContextAware 两个地方都实现了此接口,初始化工作
* 任务的删除和修改停止等方法都有, 然后封装一下对外提供接口就行 在controller写接口
*/
@Component
@Scope("singleton")
public class QuartzManager implements ApplicationContextAware {
private Logger logger = LoggerFactory.getLogger(QuartzManager.class);
private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
private static final String JOB_DEFAULT_GROUP_NAME = "JOB_DEFAULT_GROUP_NAME";
private static final String TRIGGER_DEFAULT_GROUP_NAME = "TRIGGER_DEFAULT_GROUP_NAME";
private ApplicationContext applicationContext;
private Scheduler scheduler;
@Autowired
private AutowiringSpringBeanJobFactory autowiringSpringBeanJobFactory;
public void start() {
//启动所有任务
try {
this.scheduler = schedulerFactory.getScheduler();
scheduler.setJobFactory(autowiringSpringBeanJobFactory);
//启动所有任务,这里获取AbstractTask的所有子类,继承的关系,取得所有子任务
Map<String, AbstractTask> tasks = applicationContext.getBeansOfType(AbstractTask.class);
tasks.forEach((k, v) -> {
String cronExpression = v.getCronExpression();
if (cronExpression != null) {
addJob(k, v.getClass().getName(), cronExpression);
}
});
logger.info("start jobs finished.");
} catch (SchedulerException e) {
logger.error(e.getMessage(), e);
throw new RuntimeException("init Scheduler failed");
}
}
/*
* 增加定时任务
*/
public boolean addJob(String jobName, String jobClass, String cronExp) {
boolean result = false;
if (!CronExpression.isValidExpression(cronExp)) {
logger.error("Illegal cron expression format({})", cronExp);
return result;
}
try {
JobDetail jobDetail = JobBuilder.newJob().withIdentity(new JobKey(jobName, JOB_DEFAULT_GROUP_NAME))
.ofType((Class<Job>) Class.forName(jobClass))
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withSchedule(CronScheduleBuilder.cronSchedule(cronExp))
.withIdentity(new TriggerKey(jobName, TRIGGER_DEFAULT_GROUP_NAME))
.build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
} catch (Exception e) {
logger.error(e.getMessage(), e);
logger.error("QuartzManager add job failed");
}
return result;
}
/*
* 更新定时任务
*/
public boolean updateJob(String jobName, String cronExp) {
boolean result = false;
if (!CronExpression.isValidExpression(cronExp)) {
logger.error("Illegal cron expression format({})", cronExp);
return result;
}
JobKey jobKey = new JobKey(jobName, JOB_DEFAULT_GROUP_NAME);
TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_DEFAULT_GROUP_NAME);
try {
if (scheduler.checkExists(jobKey) && scheduler.checkExists(triggerKey)) {
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
Trigger newTrigger = TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withSchedule(CronScheduleBuilder.cronSchedule(cronExp))
.withIdentity(new TriggerKey(jobName, TRIGGER_DEFAULT_GROUP_NAME))
.build();
scheduler.rescheduleJob(triggerKey, newTrigger);
result = true;
} else {
logger.error("update job name:{},group name:{} or trigger name:{},group name:{} not exists..",
jobKey.getName(), jobKey.getGroup(), triggerKey.getName(), triggerKey.getGroup());
}
} catch (SchedulerException e) {
logger.error(e.getMessage(), e);
logger.error("update job name:{},group name:{} failed!", jobKey.getName(), jobKey.getGroup());
}
return result;
}
/*
* 删除定时任务
*/
public boolean deleteJob(String jobName) {
boolean result = false;
JobKey jobKey = new JobKey(jobName, JOB_DEFAULT_GROUP_NAME);
try {
if (scheduler.checkExists(jobKey)) {
result = scheduler.deleteJob(jobKey);
} else {
logger.error("delete job name:{},group name:{} not exists.", jobKey.getName(), jobKey.getGroup());
}
} catch (SchedulerException e) {
logger.error(e.getMessage(), e);
logger.error("delete job name:{},group name:{} failed!", jobKey.getName(), jobKey.getGroup());
}
return result;
}
/*
* 接口实现 初始化
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
交给spring IOC管理的方法
/**
*
*/
package com.matrix.cloud.service.impl;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import org.springframework.stereotype.Component;
/**
* @author lmc
* 2018年12月14日
* Job默认由Quartz管理,如果需要使用Spring容器管理bean,也就是依赖注入,
* 需要指定JobFactory,也就是指定将Job由Spring容器管理。
*/
@Component
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
final Object jobInstance = super.createJobInstance(bundle);
beanFactory.autowireBean(jobInstance);
return jobInstance;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
}
服务启动后,加载所有定时任务的接口
/**
*
*/
package com.matrix.cloud.service.impl;
import javax.annotation.PostConstruct;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
* @author lmc
* 2018年12月14日
*
* 此方法是为了启动服务的时候,自动运行定时任务start(),其中 还可以利用@PostConstruct启动,还有CommandLineRunner 接口实现也可以
*/
@Component
public class ApplicationStartQuartzJobListener implements ApplicationListener<ContextRefreshedEvent>{
@Autowired
private QuartzManager quartzManager;
/**
* 初始启动quartz
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
try {
quartzManager.start();
System.out.println("任务已经启动...");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 初始注入scheduler
* @return
* @throws SchedulerException
*/
@Bean
public Scheduler scheduler() throws SchedulerException{
SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
return schedulerFactoryBean.getScheduler();
}
}
必须要实现 的接口,也就是任务的入口,为了后续好加载,我这里写在抽象类,任务启动直接获取所有子类任务
package com.matrix.cloud.service.impl;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author lmc
* 2018年12月14日
* 定义抽象任务类AbstractTask,实现Job接口,子类Job实例需实现executeInternal方法。
*
* 子类继承此方法,定时任务启动时可以拿到所有子类的方法,不需要去配置文件拿或者是数据库加定时任务
*/
public abstract class AbstractTask implements Job{
/*
*/
private Logger logger = LoggerFactory.getLogger(AbstractTask.class);
protected abstract void executeInternal(JobExecutionContext context);
protected String cronExpression;
@Override
public void execute(JobExecutionContext context) {
try {
executeInternal(context);
} catch (Exception e) {
logger.error(e.getMessage(), e);
logger.error("job execute failed!");
}
}
/*
* 定时任务表达式
*/
public String getCronExpression() {
return cronExpression;
}
}
下面就是测试的TestDemo
/**
*
*/
package com.matrix.cloud.service.impl;
import javax.annotation.PostConstruct;
import org.quartz.JobExecutionContext;
import org.springframework.stereotype.Component;
/**
* @author lmc
* 2018年12月14日
* 第二个定时任务, 继承AbstractTask实现 , 在任务启动的时候会去拿到所有子任务
* 交给springIOC管理的话, 必须要注入进来,实例对象其实也就是定时任务名
*/
@Component("TestDemo2")
public class TestDemo2 extends AbstractTask {
/*
* 默认需要quartzManager.start();开启,然后默认是2秒执行一次
*/
@PostConstruct
public void init() {
this.cronExpression = "0/2 * * * * ? ";
}
@Override
protected void executeInternal(JobExecutionContext context) {
System.out.println("第二个任务的开始");
}
}
下面是测试的类
@RunWith(SpringRunner.class)
@SpringBootTest
public class ElectronicFenceControllerTest {
private Logger logger = LoggerFactory.getLogger(ElectronicFenceControllerTest.class);
@Autowired
RedisTemplate<String, String> redisTemplate;
@Autowired
private QuartzManager quartzManager;
@Autowired
private TestTask testTask;
@Test
public void tasksTest() throws Exception {
quartzManager.start();
TimeUnit.SECONDS.sleep(10);
logger.info("start update job");
//修改任务
quartzManager.updateJob("testTask", "0/3 * * * * ? ");
logger.info("end update job");
TimeUnit.SECONDS.sleep(10);
logger.info("start delete job");
}
}
主要还是写代码去理解运行原理,然后去实现各种不同场景的业务,
更多推荐
已为社区贡献3条内容
所有评论(0)