一、背景
在项目中需要定时的往Kafka中推送数据,但是推送的数据分为两类:一类是基础数据;另一类是配置数据;实现上打算使用Quartz来完成,Quartz是什么不是这篇文章的重点,本文的重点是如何在Quartz中为这两类数据指定不同的Scheduler,让这两类数据使用不同的线程池去定时推送数据。(通过实验,发现如果使用同一个Scheduler,那么这两类数据会使用同一个线程池中的线程去推送数据)
二、实施过程
2.1 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
2.2 为两类数据分别定义两个Job
定义第一个Job:
@Component
public class FirstJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 在这里补充需要定时执行的任务
sendMessage();
}
}
定义第二个Job:
@Component
public class SecondJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 在这里补充需要定时执行的任务
sendMessage();
}
}
2.3 分别为两类数据定义 JobDetail、CronTrigger以及Scheduler
第一类数据的JobDetail、CronTrigger以及Scheduler:
@Component
public class FirstSender {
//这里通过读取配置文件来获取定时时间
@Value("${cronExp}")
private String cronExp;
public void schedulerFirst() throws SchedulerException {
try {
// 构建JobDetail,注意这里withIdentity方法中的名称需要唯一
JobDetail jobDetail = JobBuilder.newJob(FirstJob.class).withIdentity("firstJob").build();
// 构建CronTrigger,注意这里的withIdentity中的名称和group名称要唯一
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("firstTrigger", "first")
.withSchedule(cronSchedule(cronExp))
.build();
// 创建Scheduler,这里通过StdSchedulerFactory来创建
StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
Properties props = new Properties();
props.put("org.quartz.threadPool.threadCount", "10");
schedulerFactory.initialize(props);
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.scheduleJob(jobDetail, cronTrigger);
scheduler.start();
} catch (Exception e) {
log.error("FirstSender start failure!", e);
}
}
}
第二类数据的JobDetail、CronTrigger以及Scheduler:
@Component
public class SecondSender{
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
@Value("${cronExp}")
private String cronExp;
public void schedulerSecond() throws SchedulerException {
try {
// 构建JobDetail,注意这里withIdentity方法中的名称需要唯一
JobDetail jobDetail = JobBuilder.newJob(QuartsConfigJob.class).withIdentity("second").build();
// 构建CronTrigger,注意这里的withIdentity中的名称和group名称要唯一
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("secondTrigger", "second")
.withSchedule(cronSchedule(cronExp))
.build();
// 创建Scheduler,这里通过SchedulerFactoryBean来创建
Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduler.scheduleJob(jobDetail, cronTrigger);
scheduler.start();
} catch (Exception e) {
logger.error("SecondSender start failure!", e);
}
}
}
特别注意:上述一定要使用两种不同的方式来创建Scheduler,否则创建出来的Scheduler是同一个,那么调度的时候两个Job会使用同一个线程池中的线程
2.4 定义上述第二种创建Scheduler方式中的SchedulerFactoryBean的Bean
public class BeanConfig {
@Bean
public SchedulerFactoryBean schedulerFactoryBean () {
return new SchedulerFactoryBean();
}
}
2.4 定义启动类
定义启动类来启动定时任务:
@Component
public class StartupRunner implements CommandLineRunner {
@Autowired
private FirstSender firstSender ;
@Autowired
private SecondSender secondSender;
@Override
public void run(String... args) throws Exception {
firstSender.schedulerFirst();
secondSender.schedulerSecond();
}
}
经过上述过程之后,在我们启动spring boot项目之后,定时任务就会开始执行:
image.png
其中eduler_
开头的线程是第一类数据的线程池中的线程;ryBean_
开头的线程是第二类数据的线程池中的线程。经过一段时间后,可以发现两个任务的线程数量均达到了我们设置的10个线程
网友评论