Spring Boot 定時任務(wù),怎么實(shí)現(xiàn)任務(wù)動態(tài)增刪啟停?

作者:jessehua
鏈接:https://www.jianshu.com/p/0f68936393fd


@Configuration
public?class?SchedulingConfig?{
????@Bean
????public?TaskScheduler?taskScheduler()?{
????????ThreadPoolTaskScheduler?taskScheduler?=?new?ThreadPoolTaskScheduler();
????????//?定時任務(wù)執(zhí)行線程池核心線程數(shù)
????????taskScheduler.setPoolSize(4);
????????taskScheduler.setRemoveOnCancelPolicy(true);
????????taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
????????return?taskScheduler;
????}
}
添加ScheduledFuture的包裝類。ScheduledFuture是ScheduledExecutorService定時任務(wù)線程池的執(zhí)行結(jié)果。
public?final?class?ScheduledTask?{
????volatile?ScheduledFuture>?future;
????/**
?????*?取消定時任務(wù)
?????*/
????public?void?cancel()?{
????????ScheduledFuture>?future?=?this.future;
????????if?(future?!=?null)?{
????????????future.cancel(true);
????????}
????}
}
添加Runnable接口實(shí)現(xiàn)類,被定時任務(wù)線程池調(diào)用,用來執(zhí)行指定bean里面的方法。
public?class?SchedulingRunnable?implements?Runnable?{
????private?static?final?Logger?logger?=?LoggerFactory.getLogger(SchedulingRunnable.class);
????private?String?beanName;
????private?String?methodName;
????private?String?params;
????public?SchedulingRunnable(String?beanName,?String?methodName)?{
????????this(beanName,?methodName,?null);
????}
????public?SchedulingRunnable(String?beanName,?String?methodName,?String?params)?{
????????this.beanName?=?beanName;
????????this.methodName?=?methodName;
????????this.params?=?params;
????}
????@Override
????public?void?run()?{
????????logger.info("定時任務(wù)開始執(zhí)行?- bean:{},方法:{},參數(shù):{}",?beanName,?methodName,?params);
????????long?startTime?=?System.currentTimeMillis();
????????try?{
????????????Object?target?=?SpringContextUtils.getBean(beanName);
????????????Method?method?=?null;
????????????if?(StringUtils.isNotEmpty(params))?{
????????????????method?=?target.getClass().getDeclaredMethod(methodName,?String.class);
????????????}?else?{
????????????????method?=?target.getClass().getDeclaredMethod(methodName);
????????????}
????????????ReflectionUtils.makeAccessible(method);
????????????if?(StringUtils.isNotEmpty(params))?{
????????????????method.invoke(target,?params);
????????????}?else?{
????????????????method.invoke(target);
????????????}
????????}?catch?(Exception?ex)?{
????????????logger.error(String.format("定時任務(wù)執(zhí)行異常?- bean:%s,方法:%s,參數(shù):%s ",?beanName,?methodName,?params),?ex);
????????}
????????long?times?=?System.currentTimeMillis()?-?startTime;
????????logger.info("定時任務(wù)執(zhí)行結(jié)束?- bean:{},方法:{},參數(shù):{},耗時:{}?毫秒",?beanName,?methodName,?params,?times);
????}
????@Override
????public?boolean?equals(Object?o)?{
????????if?(this?==?o)?return?true;
????????if?(o?==?null?||?getClass()?!=?o.getClass())?return?false;
????????SchedulingRunnable?that?=?(SchedulingRunnable)?o;
????????if?(params?==?null)?{
????????????return?beanName.equals(that.beanName)?&&
????????????????????methodName.equals(that.methodName)?&&
????????????????????that.params?==?null;
????????}
????????return?beanName.equals(that.beanName)?&&
????????????????methodName.equals(that.methodName)?&&
????????????????params.equals(that.params);
????}
????@Override
????public?int?hashCode()?{
????????if?(params?==?null)?{
????????????return?Objects.hash(beanName,?methodName);
????????}
????????return?Objects.hash(beanName,?methodName,?params);
????}
}
添加定時任務(wù)注冊類,用來增加、刪除定時任務(wù)。
@Component
public?class?CronTaskRegistrar?implements?DisposableBean?{
????private?final?Map?scheduledTasks?=?new?ConcurrentHashMap<>(16);
????@Autowired
????private?TaskScheduler?taskScheduler;
????public?TaskScheduler?getScheduler()?{
????????return?this.taskScheduler;
????}
????public?void?addCronTask(Runnable?task,?String?cronExpression)?{
????????addCronTask(new?CronTask(task,?cronExpression));
????}
????public?void?addCronTask(CronTask?cronTask)?{
????????if?(cronTask?!=?null)?{
????????????Runnable?task?=?cronTask.getRunnable();
????????????if?(this.scheduledTasks.containsKey(task))?{
????????????????removeCronTask(task);
????????????}
????????????this.scheduledTasks.put(task,?scheduleCronTask(cronTask));
????????}
????}
????public?void?removeCronTask(Runnable?task)?{
????????ScheduledTask?scheduledTask?=?this.scheduledTasks.remove(task);
????????if?(scheduledTask?!=?null)
????????????scheduledTask.cancel();
????}
????public?ScheduledTask?scheduleCronTask(CronTask?cronTask)?{
????????ScheduledTask?scheduledTask?=?new?ScheduledTask();
????????scheduledTask.future?=?this.taskScheduler.schedule(cronTask.getRunnable(),?cronTask.getTrigger());
????????return?scheduledTask;
????}
????@Override
????public?void?destroy()?{
????????for?(ScheduledTask?task?:?this.scheduledTasks.values())?{
????????????task.cancel();
????????}
????????this.scheduledTasks.clear();
????}
}
@Component("demoTask")
public?class?DemoTask?{
????public?void?taskWithParams(String?params)?{
????????System.out.println("執(zhí)行有參示例任務(wù):"?+?params);
????}
????public?void?taskNoParams()?{
????????System.out.println("執(zhí)行無參示例任務(wù)");
????}
}
定時任務(wù)數(shù)據(jù)庫表設(shè)計(jì)

添加定時任務(wù)實(shí)體類
public class SysJobPO {
/**
* 任務(wù)ID
*/
private Integer jobId;
/**
* bean名稱
*/
private String beanName;
/**
* 方法名稱
*/
private String methodName;
/**
* 方法參數(shù)
*/
private String methodParams;
/**
* cron表達(dá)式
*/
private String cronExpression;
/**
* 狀態(tài)(1正常 0暫停)
*/
private Integer jobStatus;
/**
* 備注
*/
private String remark;
/**
* 創(chuàng)建時間
*/
private Date createTime;
/**
* 更新時間
*/
private Date updateTime;
public Integer getJobId() {
return jobId;
}
public void setJobId(Integer jobId) {
this.jobId = jobId;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getMethodParams() {
return methodParams;
}
public void setMethodParams(String methodParams) {
this.methodParams = methodParams;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public Integer getJobStatus() {
return jobStatus;
}
public void setJobStatus(Integer jobStatus) {
this.jobStatus = jobStatus;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
}
boolean?success?=?sysJobRepository.addSysJob(sysJob);
if?(!success)
????return?OperationResUtils.fail("新增失敗");
else?{
????if?(sysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal()))?{
????????SchedulingRunnable?task?=?new?SchedulingRunnable(sysJob.getBeanName(),?sysJob.getMethodName(),?sysJob.getMethodParams());
????????cronTaskRegistrar.addCronTask(task,?sysJob.getCronExpression());
????}
}
return?OperationResUtils.success();
修改定時任務(wù),先移除原來的任務(wù),再啟動新任務(wù)
boolean?success?=?sysJobRepository.editSysJob(sysJob);
if?(!success)
????return?OperationResUtils.fail("編輯失敗");
else?{
????//先移除再添加
????if?(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal()))?{
????????SchedulingRunnable?task?=?new?SchedulingRunnable(existedSysJob.getBeanName(),?existedSysJob.getMethodName(),?existedSysJob.getMethodParams());
????????cronTaskRegistrar.removeCronTask(task);
????}
????if?(sysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal()))?{
????????SchedulingRunnable?task?=?new?SchedulingRunnable(sysJob.getBeanName(),?sysJob.getMethodName(),?sysJob.getMethodParams());
????????cronTaskRegistrar.addCronTask(task,?sysJob.getCronExpression());
????}
}
return?OperationResUtils.success();
boolean?success?=?sysJobRepository.deleteSysJobById(req.getJobId());
if?(!success)
????return?OperationResUtils.fail("刪除失敗");
else{
????if?(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal()))?{
????????SchedulingRunnable?task?=?new?SchedulingRunnable(existedSysJob.getBeanName(),?existedSysJob.getMethodName(),?existedSysJob.getMethodParams());
????????cronTaskRegistrar.removeCronTask(task);
????}
}
return?OperationResUtils.success();
if?(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal()))?{
????SchedulingRunnable?task?=?new?SchedulingRunnable(existedSysJob.getBeanName(),?existedSysJob.getMethodName(),?existedSysJob.getMethodParams());
????cronTaskRegistrar.addCronTask(task,?existedSysJob.getCronExpression());
}?else?{
????SchedulingRunnable?task?=?new?SchedulingRunnable(existedSysJob.getBeanName(),?existedSysJob.getMethodName(),?existedSysJob.getMethodParams());
????cronTaskRegistrar.removeCronTask(task);
}
?jobList?=?sysJobRepository.getSysJobListByStatus(SysJobStatus.NORMAL.ordinal());????????if?(CollectionUtils.isNotEmpty(jobList))?{????????????for?(SysJobPO?job?:?jobList)?{????????????????SchedulingRunnable?task?=?new?SchedulingRunnable(job.getBeanName(),?job.getMethodName(),?job.getMethodParams());????????????????cronTaskRegistrar.addCronTask(task,?job.getCronExpression());????????????}????????????logger.info("定時任務(wù)已加載完畢...");????????}????}}工具類SpringContextUtils,用來從spring容器里獲取bean" data-itemshowtype="0" tab="innerlink" data-linktype="2" wah-hotarea="click" hasload="1" style="outline: 0px; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); cursor: pointer; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">@Service
public?class?SysJobRunner?implements?CommandLineRunner?{
????private?static?final?Logger?logger?=?LoggerFactory.getLogger(SysJobRunner.class);
????@Autowired
????private?ISysJobRepository?sysJobRepository;
????@Autowired
????private?CronTaskRegistrar?cronTaskRegistrar;
????@Override
????public?void?run(String...?args)?{
????????//?初始加載數(shù)據(jù)庫里狀態(tài)為正常的定時任務(wù)
????????List?jobList?=?sysJobRepository.getSysJobListByStatus(SysJobStatus.NORMAL.ordinal());
????????if?(CollectionUtils.isNotEmpty(jobList))?{
????????????for?(SysJobPO?job?:?jobList)?{
????????????????SchedulingRunnable?task?=?new?SchedulingRunnable(job.getBeanName(),?job.getMethodName(),?job.getMethodParams());
????????????????cronTaskRegistrar.addCronTask(task,?job.getCronExpression());
????????????}
????????????logger.info("定時任務(wù)已加載完畢...");
????????}
????}
}
工具類SpringContextUtils,用來從spring容器里獲取bean
@Component
public?class?SpringContextUtils?implements?ApplicationContextAware?{
????private?static?ApplicationContext?applicationContext;
????@Override
????public?void?setApplicationContext(ApplicationContext?applicationContext)
????????????throws?BeansException?{
????????SpringContextUtils.applicationContext?=?applicationContext;
????}
????public?static?Object?getBean(String?name)?{
????????return?applicationContext.getBean(name);
????}
????public?static??T?getBean(Class?requiredType) ?{
????????return?applicationContext.getBean(requiredType);
????}
????public?static??T?getBean(String?name,?Class?requiredType) ?{
????????return?applicationContext.getBean(name,?requiredType);
????}
????public?static?boolean?containsBean(String?name)?{
????????return?applicationContext.containsBean(name);
????}
????public?static?boolean?isSingleton(String?name)?{
????????return?applicationContext.isSingleton(name);
????}
????public?static?Class?extends?Object>?getType(String?name)?{
????????return?applicationContext.getType(name);
????}
} 評論
圖片
表情
