SpringBoot 整合 Quartz 实现 JAVA 定时任务的动态配置
参考地址:https://mp.weixin.qq.com/s/3_8yfRMzpJ5ZrRTiOOeP5w
一、maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
补充:此处采用的内嵌数据库H2+spring data jpa
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
二、配置信息
1、application.yml
server:
port: 8081
spring:
datasource:
#数据库存储路径(./database/job表示和项目代码同级)
url: jdbc:h2:./database/job
driver-class-name: org.h2.Driver
username: yzh
password: 123456
jpa:
database: h2
hibernate:
ddl-auto: update
show-sql: true
h2:
console:
path: /h2-console
enabled: true
2、配置类(QuartzConfig)
@Configuration public class QuartzConfig { @Autowired private JobFactory jobFactory; @Bean public SchedulerFactoryBean schedulerFactoryBean() throws IOException { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setOverwriteExistingJobs(true); schedulerFactoryBean.setQuartzProperties(quartzProperties()); schedulerFactoryBean.setJobFactory(jobFactory); return schedulerFactoryBean; } /** * 指定quartz.properties,可在配置文件中配置相关属性 * @return * @throws IOException */ public Properties quartzProperties() throws IOException { PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); propertiesFactoryBean.setLocation(new ClassPathResource("/config/quartz.properties")); propertiesFactoryBean.afterPropertiesSet(); return propertiesFactoryBean.getObject(); } /** * 创建schedule * @return * @throws IOException */ @Bean(name = "scheduler") public Scheduler scheduler() throws IOException { return schedulerFactoryBean().getScheduler(); } }
3、实体类(SysTask)
@Entity public class SysTask implements Serializable { private static final long serialVersionUID = -560378047531235168L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /** * 任务名 */ private String jobName; /** * 任务描述 */ private String description; /** * cron表达式 */ private String cronExpression; /** * 任务执行时调用哪个类的方法 包名+类名 */ private String beanClass; /** * 任务状态 */ private String jobStatus; /** * 任务分组 */ private String jobGroup; /** * 创建者 */ private String createUser; /** * 创建时间 */ private Date createTime; /** * 更新者 */ private String updateUser; /** * 更新时间 */ private Date update_time;
对应的dao(ISysTaskDao)
@Component public interface ISysTaskDao extends JpaRepository<SysTask,Long> { }
4、添加监听器(ScheduleJobInitListener)
项目启动时,初始化任务
@Component
@Order(1)
public class ScheduleJobInitListener implements CommandLineRunner {
@Autowired
private ISysTakService takService;
@Override
public void run(String... args) throws Exception {
takService.initSchedule();
}
}
5、读取数据库,加载scheduler调度器
(1)、获取数据库中的任务
@Service
public class SysTakServiceImpl implements ISysTakService {
@Autowired
private ISysTaskDao sysTaskDao;
@Autowired
private QuartzManager quartzManager;
@Transactional(readOnly = true,propagation = Propagation.NOT_SUPPORTED)
@Override
public void initSchedule() throws Exception {
//获取任务信息
List<SysTask> all = sysTaskDao.findAll();
/**
* 正在运行的
*/
for (SysTask sysTask : all) {
if (JobStatusEnum.RUNNING.getStatus().equals(sysTask.getJobStatus())){
quartzManager.addJob(sysTask);
}
}
}
}
(2)、添加任务到Quartz调度器
@Component
public class QuartzManager {
private static final Logger LOGGER = LoggerFactory.getLogger(QuartzManager.class);
@Autowired
private Scheduler scheduler;
/**
* 添加并启动任务
* @param task
*/
@SuppressWarnings("unchecked")
public void addJob(SysTask task) throws Exception {
//创建jobDetail实例,绑定job实现类
Class<? extends Job> jobClass = (Class<? extends Job>) (Class.forName(task.getBeanClass()).newInstance()
.getClass());
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(task.getJobName(), task.getJobGroup()).build();
//定义调度触发规则
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(task.getJobName(), task.getJobGroup())// 触发器key
.startAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.SECOND))
.withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression())).startNow().build();
//把作业和触发器注册到任务调度中
scheduler.scheduleJob(jobDetail,trigger);
//启动
if (!scheduler.isShutdown()){
scheduler.start();
}
}
}
6、实例化job类,注入要运行的service
(1)、工厂类(JobFactory)
@Component
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
(2)、具体任务类
@DisallowConcurrentExecution //不允许多线程运行 @Component public class HelloWorldJob implements Job { private static final Logger LOGGER = LoggerFactory.getLogger(HelloWorldJob.class); @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { JobKey key = jobExecutionContext.getJobDetail().getKey(); LOGGER.info("任务【{}】-【{}】执行开始了--:{}",key.getName(),key.getGroup(),new Date()); } }