首先导入配置类(项目启动预加载)
-
背景:项目启动后,SpringBoot 通过数据库配置实现可配置job任务工作,目前的功能算个半自动,更改数据库配置信息的话 就需要重新重启服务了。
SpringBoot整合quartz(支持多任务和job,支持spring管理) 框架:SpringBoot + quartz 所需要的依赖: <!--quartz--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
- 1.导入配置类
package xxx;
import xxx.entity.ScheduleJob;
import xxx.repository.ScheduleJobRepository;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import java.util.List;
@Configuration
public class SchedulerListener implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
Scheduler Scheduler;
@Autowired
JobFactory JobFactory;
@Autowired
ScheduleJobRepository ScheduleJobRepository;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//数据库查询配置信息 换你自己的逻辑
List<ScheduleJob> ScheduleJobAll = ScheduleJobRepository.findAll();
try {
Scheduler.schedulerJob(ScheduleJobAll);
System.out.println("SynchronizedData job start...");
} catch (SchedulerException | ClassNotFoundException e) {
e.printStackTrace();
}
}
@Bean(name ="mySchedulerFactoryBean")
public SchedulerFactoryBean mySchedulerFactory() {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setOverwriteExistingJobs(true);
bean.setStartupDelay(1);
bean.setJobFactory(JobFactory);
return bean;
}
}
- 2.导入应用程序启动时自动扫描并加载的组件1
package xxx.conf.quartz;
import xxx.entity.ScheduleJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdScheduler;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j
@Component
public class Scheduler {
public static JobKey getJobKey(String jobId, String jobGroup) {
return JobKey.jobKey(jobId, jobGroup);
}
public void schedulerJob(List<ScheduleJob> scheduleJobList) throws SchedulerException, ClassNotFoundException {
ApplicationContext annotationContext = SpringUtil.getApplicationContext();
StdScheduler stdScheduler = (StdScheduler) annotationContext.getBean("mySchedulerFactoryBean");//获得上面创建的bean
org.quartz.Scheduler myScheduler =stdScheduler;
dataCheck(myScheduler,scheduleJobList);
myScheduler.start();
}
public void dataCheck(org.quartz.Scheduler scheduler, List<ScheduleJob> scheduleJobList) throws SchedulerException, ClassNotFoundException {
//只有首次启动才会进入此函数
//scheduleJobList这个东西是我在数据库添加的配置类,我会在结尾添加具体数据库配置截图
a:for (ScheduleJob info :scheduleJobList) {
//添加了一个状态,如果是已关闭的状态,先杀掉已运行的任务
if(info.getStartOrNot().equals("N")){
checkExistsDelete(scheduler, info);
continue a;
}
//检查你的程序是否正在运行,如果正在运行,那么先杀掉,避免重复调用
checkExistsDelete(scheduler, info);
//即将开始你的自动化JOB逻辑
startScheduler(scheduler, info);
/* if(info.getCurrentState().equals(JobType.STARTUP.jobType)){
//开启状态 -- 先检查是否存在,存在关闭再开
checkExistsDelete(scheduler, info);
startScheduler(scheduler, info);
}else if(info.getCurrentState().equals(JobType.SUSPEND.jobType)){
//暂停状态,
if (scheduler.checkExists(getJobKey(info.getId(), info.getTaskName()))) {
pauseJobScheduler(scheduler, info);
}
}else if(info.getCurrentState().equals(JobType.RESTORE.jobType)){
if (scheduler.checkExists(getJobKey(info.getId(), info.getTaskName()))) {
resumeJobScheduler(scheduler,info);
}else{
startScheduler(scheduler, info);
}
}else if(info.getCurrentState().equals(JobType.CLOSE.jobType)){
if (scheduler.checkExists(getJobKey(info.getId(), info.getTaskName()))) {
deleteJobScheduler(scheduler, info);
}
}*/
}
}
public void startScheduler(org.quartz.Scheduler scheduler, ScheduleJob jobInfo) throws SchedulerException, ClassNotFoundException {
log.info(jobInfo.toString());
/**
这些参数都配置在数据库里(后面我会贴图)
jobInfo.getInvokeTarget() //你要运行的Class 位置
jobInfo.getTaskName() //任务名称
jobInfo.getCronExpression()//你的运行时间 例如:0 0 19-23 * * ?
jobInfo.getId() //任务的id
**/
JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(jobInfo.getInvokeTarget())).withIdentity("job_"+jobInfo.getTaskName(), "jobGroup_"+jobInfo.getTaskName()).build();
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression());
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger_"+jobInfo.getId(), "triggerGroup_"+jobInfo.getTaskName())
.withSchedule(cronScheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}
public void checkExistsDelete(org.quartz.Scheduler scheduler, ScheduleJob info) throws SchedulerException{
if (scheduler.checkExists(getJobKey(info.getId(), info.getTaskName()))) {
scheduler.deleteJob(getJobKey(info.getId(), info.getTaskName()));
}
}
public void deleteJobScheduler(org.quartz.Scheduler scheduler, ScheduleJob jobInfo) throws SchedulerException{
scheduler.deleteJob(getJobKey(jobInfo.getId(), jobInfo.getTaskName()));
}
public void pauseJobScheduler(org.quartz.Scheduler scheduler, ScheduleJob jobInfo) throws SchedulerException{
scheduler.pauseJob(getJobKey(jobInfo.getId(), jobInfo.getTaskName()));
}
public void resumeJobScheduler(org.quartz.Scheduler scheduler, ScheduleJob jobInfo) throws SchedulerException{
scheduler.resumeJob(getJobKey(jobInfo.getId(), jobInfo.getTaskName()));
}
}
- 3.导入应用程序启动时自动扫描并加载的组件2
package xxx.conf.quartz;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
@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;
}
}
- 4.导入util 初始化类
package xxx.conf.quartz;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringUtil implements ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(SpringUtil.class);
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtil.applicationContext == null) {
SpringUtil.applicationContext = applicationContext;
}
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
// 通过name获取 Bean.
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) getApplicationContext().getBean(name);
}
// 通过class获取Bean.
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
// 通过name,以及Clazz返回指定的Bean
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
- 5.你要运行的 Class 任务1
package com.xxx.job;
import com.xxx.service.NationalFaceToFaceService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
public class MySchedulerJob implements Job {
//这里就可以成功注入Server了
@Autowired
private xxxService xxxService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("SchedulerJob 111111 event number: ********************************************************" );
}
}
- 6.你要运行的 Class 任务2
package com.xxx.job;
import com.xxx.entity.ScheduleJob;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
@Slf4j
@DisallowConcurrentExecution
public class xxx implements Job {
@Autowired
private OtherService otherService;
@SneakyThrows
@Override
public void execute(JobExecutionContext jobExecutionContext){
log.info("SchedulerJob 222222 event number: ************************* SubmitDataCleansing *******************************");
//打印开始时间
String invokeTarget = SubmitDataCleansing.class.getName();
//获取数据库资源配置
ScheduleJob scheduleJob = otherService.findByInvokeTarget(invokeTarget);
if(scheduleJob != null){
//获取数据库配置信息(固定)
JSONObject parameter = JSONObject.parseObject(scheduleJob.getParameter());
//业务逻辑开始
}else{
//状态回库 这个可以不需要
otherService.updateCurrentState(JobType.FAIL.jobType,"Error -- Class configuration not found",scheduleJob.getId());
log.error("xxx : Error -- Class configuration not found");
}
}
}
- 7.实体类 (获取数据库配置信息的) 你可以用你自己的也可以
package com.xxx.data.entity;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "ScheduleJob")
public class ScheduleJob{
@Id
private String Id;
private String TaskName;
private String InvokeTarget;
private String StartOrNot;
private String CronExpression;
private String CurrentState;
private String Parameter;
private String CreateBy;
private String CreateTime;
private String UpdateBy;
private String UpdateTime;
private String Remarks;
public String getId() {
return Id;
}
public void setId(String id) {
Id = id;
}
public String getTaskName() {
return TaskName;
}
public void setTaskName(String taskName) {
TaskName = taskName;
}
public String getInvokeTarget() {
return InvokeTarget;
}
public void setInvokeTarget(String invokeTarget) {
InvokeTarget = invokeTarget;
}
public String getStartOrNot() {
return StartOrNot;
}
public void setStartOrNot(String startOrNot) {
StartOrNot = startOrNot;
}
public String getCronExpression() {
return CronExpression;
}
public void setCronExpression(String cronExpression) {
CronExpression = cronExpression;
}
public String getCurrentState() {
return CurrentState;
}
public void setCurrentState(String currentState) {
CurrentState = currentState;
}
public String getParameter() {
return Parameter;
}
public void setParameter(String parameter) {
Parameter = parameter;
}
public String getCreateBy() {
return CreateBy;
}
public void setCreateBy(String createBy) {
CreateBy = createBy;
}
public String getCreateTime() {
return CreateTime;
}
public void setCreateTime(String createTime) {
CreateTime = createTime;
}
public String getUpdateBy() {
return UpdateBy;
}
public void setUpdateBy(String updateBy) {
UpdateBy = updateBy;
}
public String getUpdateTime() {
return UpdateTime;
}
public void setUpdateTime(String updateTime) {
UpdateTime = updateTime;
}
public String getRemarks() {
return Remarks;
}
public void setRemarks(String remarks) {
Remarks = remarks;
}
public String toString() {
return "ScheduleJob [CreateBy=" + CreateBy + ", CreateTime="
+ CreateTime + ", CronExpression=" + CronExpression
+ ", CurrentState=" + CurrentState + ", Id=" + Id
+ ", InvokeTarget=" + InvokeTarget + ", Parameter=" + Parameter
+ ", Remarks=" + Remarks + ", StartOrNot=" + StartOrNot + ", TaskName=" + TaskName
+ ", UpdateBy=" + UpdateBy + ", UpdateTime=" + UpdateTime + "]";
}
}
- 8.数据库字段配置信息
图解1:
第三列是 你要运行class的位置(第5步和第6步)
第四列是 是否开启的一个开关选项,可以没有这个字段
第五列是 你要运行的具体时间 (Cron表达式)
图解2:
第二列是 程序正在运行状态,记录一下类似日志(也可以不要)
第三列是 配置的请求参数,我写的是JSON, 你也可以写List,set.... 后期在代码里连接数库取值 能解析出来就行
最后几列我也是为了记录,也可以没有
- 9.到这里你的配置都完成了,直接启动项目就行了,然后等待自动化程序运行,就可以了