本篇内容介绍了“如何实现集成定时任务SchedulingConfigurer”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
背景:
项目需要启动一个定时执行的任务,该任务的执行可以随时停止执行,要求在数据库配置执行规律。
调研:使用scheduling定时任务与springboot集成;
实例:
第一步:创建一个数据表,保存执行的任务
/*DDL 信息*/------------
CREATE TABLE `hk_sys_task` (
`id` bigint(21) NOT NULL AUTO_INCREMENT COMMENT '主键',
`task_uuid` varchar(50) DEFAULT NULL COMMENT '任务UUID',
`task_name` varchar(50) DEFAULT NULL COMMENT '任务名称',
`task_cron` varchar(50) DEFAULT NULL COMMENT '任务定时表达式',
`class_name` varchar(100) DEFAULT NULL COMMENT '任务类',
`method_name` varchar(100) DEFAULT NULL COMMENT '任务方法',
`task_type` int(1) DEFAULT NULL COMMENT '任务类型',
`remark` varchar(250) DEFAULT NULL,
`del_mark` int(1) DEFAULT '1',
`flag` int(1) DEFAULT '1',
`create_user` varchar(50) DEFAULT NULL,
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`modify_user` varchar(50) DEFAULT NULL,
`modify_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
2、创建springboot的SpringUtil用户获取bean
/**
* @Author: Liu Yue
* @Descripition:
* @Date; Create in 2021/5/14 11:19
**/
@Component
@Slf4j
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(SpringUtil.applicationContext == null) {
SpringUtil.applicationContext = applicationContext;
}
log.info("========ApplicationContext配置成功,在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象,applicationContext={},",SpringUtil.applicationContext+"========");
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过name获取 Bean.
public static Object getBean(String name){
return 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);
}
}
3、配置执行任务的类SysTaskConfig
/**
* @Author: Liu Yue
* @Descripition:
* @Date; Create in 2021/5/14 9:34
**/
@Lazy(value = false)
@Component
@Slf4j
public class SysTaskConfig implements SchedulingConfigurer {
@Resource
private HkSysTaskMapper hkSysTaskMapper;
private static ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
private static Map<String,ScheduledFuture<?>> scheduledFutureMap = new HashMap<>();
//从数据库里取得所有要执行的定时任务
private List<HkSysTask> getAllTasks() {
LambdaQueryWrapper<HkSysTask> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HkSysTask::getDelMark,1)
.eq(HkSysTask::getFlag,1);
return hkSysTaskMapper.selectList(wrapper);
}
static {
threadPoolTaskScheduler.initialize();
}
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
List<HkSysTask> allTasks = getAllTasks();
log.info("定时任务启动,预计启动任务数量={},; time={}",allTasks.size(),LocalDateTime.now());
//校验数据(这个步骤主要是为了打印日志,可以省略)
checkDataList(allTasks);
//通过校验的数据执行定时任务
int count = 0;
if(allTasks.size()>0) {
for (int i = 0; i < allTasks.size(); i++) {
try {
scheduledTaskRegistrar.addTriggerTask(getRunnable(allTasks.get(i)), getTrigger(allTasks.get(i)));
count++;
} catch (Exception e) {
log.error("定时任务启动错误:" + allTasks.get(i).getClassName() + ";" + allTasks.get(i).getMethodName() + ";" + e.getMessage());
}
}
}
log.info("定时任务实际启动数量="+count+"; time="+LocalDateTime.now());
}
private static Trigger getTrigger(HkSysTask task){
return new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
//将Cron 0/1 * * * * ? 输入取得下一次执行的时间
CronTrigger trigger = new CronTrigger(task.getTaskCron());
Date nextExec = trigger.nextExecutionTime(triggerContext);
return nextExec;
}
};
}
private static Runnable getRunnable(HkSysTask task){
return new Runnable() {
@Override
public void run() {
Class<?> clazz;
try {
clazz = Class.forName(task.getClassName());
String className = lowerFirstCapse(clazz.getSimpleName());
Object bean = SpringUtil.getBean(className);
Method method = ReflectionUtils.findMethod(bean.getClass(), task.getMethodName());
ReflectionUtils.invokeMethod(method, bean);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
};
}
private List<HkSysTask> checkDataList(List<HkSysTask> list) {
String errMsg="";
for(int i=0;i<list.size();i++){
if(!checkOneData(list.get(i)).equalsIgnoreCase("success")){
errMsg+=list.get(i).getTaskName()+";";
list.remove(list.get(i));
i--;
};
}
if(!StringUtils.isBlank(errMsg)){
errMsg="未启动的任务:"+errMsg;
log.error(errMsg);
}
return list;
}
private String checkOneData(HkSysTask task){
String result="success";
Class clazz= null;
try {
clazz = Class.forName(task.getClassName());
//String className = lowerFirstCapse(clazz.getSimpleName());
Object obj =SpringUtil.getBean(clazz);
Method method = obj.getClass().getMethod(task.getMethodName(),null);
String cron=task.getTaskCron();
if(StringUtils.isBlank(cron)){
result="定时任务启动错误,无cron:"+task.getTaskName();
log.error(result);
}
} catch (ClassNotFoundException e) {
result="定时任务启动错误,找不到类:"+task.getClassName()+ e.getMessage();
log.error(result);
} catch (NoSuchMethodException e) {
result="定时任务启动错误,找不到方法,方法必须是public:"+task.getClassName()+";"+task.getMethodName()+";"+ e.getMessage();
log.error(result);
} catch (Exception e) {
log.error(e.getMessage());
}
return result;
}
/**
* 转换首字母小写
*
* @param str
* @return
*/
public static String lowerFirstCapse(String str) {
char[] chars = str.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
/**
* 启动定时任务
* @param task
* @param
*/
public static void start(HkSysTask task){
ScheduledFuture<?> scheduledFuture = threadPoolTaskScheduler.schedule(getRunnable(task),getTrigger(task));
scheduledFutureMap.put(task.getTaskUuid(),scheduledFuture);
log.info("启动定时任务" + task.getId() );
}
/**
* 取消定时任务
* @param task
*/
public static void cancel(HkSysTask task){
ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(task.getId());
if(scheduledFuture != null && !scheduledFuture.isCancelled()){
scheduledFuture.cancel(Boolean.FALSE);
}
scheduledFutureMap.remove(task.getId());
log.info("取消定时任务" + task.getId() );
}
/**
* 编辑
* @param task
* @param
*/
public static void reset(HkSysTask task){
log.info("修改定时任务开始" + task.getId() );
cancel(task);
start(task);
log.info("修改定时任务结束" + task.getId());
}
}
4、定时执行的测试类
......
public void test(){
iHkUserService.userTaskRun();
}
......
5、console输出的日志
“如何实现集成定时任务SchedulingConfigurer”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/maojindaoGG/blog/5056197