设计思路参考于jeecgboot,因 jeecgboot 中引入了 quartz 框架,要建许多表,我只需要简单的定时任务即可,所以写了个简化版的定时任务。先上代码,再分析。
CREATE TABLE `sys_quartz_job` (
`id` varchar(32) NOT NULL,
`create_by` varchar(32) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`del_flag` int(1) DEFAULT NULL COMMENT '删除状态',
`update_by` varchar(32) DEFAULT NULL COMMENT '修改人',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
`job_class_name` varchar(255) DEFAULT NULL COMMENT '任务类名',
`cron_expression` varchar(255) DEFAULT NULL COMMENT 'cron表达式',
`parameter` varchar(255) DEFAULT NULL COMMENT '参数',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
`status` int(1) DEFAULT NULL COMMENT '状态 0正常 -1停止',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uniq_job_class_name` (`job_class_name`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
INSERT INTO `sys_quartz_job`
(`id`,`create_by`,`create_time`,`del_flag`,`update_by`,`update_time`,`job_class_name`,`cron_expression`,`parameter`,`description`,`status`)VALUES
('df26ecacf0f75d219d746750fe84bbee', NULL, NULL, '0', 'admin', '2020-05-02 15:40:35', 'org.jeecg.modules.quartz.job.SampleParamJob', '0/1 * * * * ?', 'scott', '带参测试 后台将每隔1秒执行输出日志', '-1');
public interface Job {
void execute(String paramsJson);
}
@Component
public class ScheduleUtil {
private static final Logger logger = LoggerFactory.getLogger(ScheduleUtil.class);
private static ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
private static Map<String, ScheduledFuture<?>> scheduledFutureMap = new HashMap<>();
static {
threadPoolTaskScheduler.initialize();
logger.info("init threadPoolTaskScheduler");
}
private void start(SysTaskJob task) {
String cronExpression = task.getCronExpression();
String jobClassName = task.getJobClassName();
String parameter = task.getParameter();
ScheduledFuture<?> scheduledFuture = threadPoolTaskScheduler.schedule(() -> {
try {
executeByClassName(jobClassName, parameter);
} catch (Exception e) {
e.printStackTrace();
}
}, (TriggerContext triggerContext) -> {
if ("".equals(cronExpression) || cronExpression == null)
return null;
CronTrigger trigger = new CronTrigger(cronExpression);
Date nextExecDate = trigger.nextExecutionTime(triggerContext);
return nextExecDate;
});
scheduledFutureMap.put(task.getId(), scheduledFuture);
logger.info("start timed task id=" + task.getId());
}
public void start(List<SysTaskJob> list) {
List<String> ids = list.stream().map(SysTaskJob::getId).collect(Collectors.toList());
Map<String, ScheduledFuture<?>> map = this.filterMapKeyNotInIds(ids);
this.cancle(map);
for (SysTaskJob sysTaskJob : list) {
if (scheduledFutureMap.get(sysTaskJob.getId()) == null) {
this.start(sysTaskJob);
}
}
}
private void cancle(Map<String, ScheduledFuture<?>> map) {
for (Map.Entry<String, ScheduledFuture<?>> entry : map.entrySet()) {
ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(entry.getKey());
if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
scheduledFuture.cancel(false);
}
scheduledFutureMap.remove(entry.getKey());
logger.info("cancel timed task id=" + entry.getKey());
}
}
// 利用反射获取需要执行的方法
private void executeByClassName(String className, String parameter) throws Exception {
Class<?> clazz = Class.forName(className);
Job entity = (Job) clazz.newInstance();
entity.execute(parameter);
}
private Map<String, ScheduledFuture<?>> filterMapKeyNotInIds(List<String> ids) {
return scheduledFutureMap.entrySet().stream().filter(e -> !ids.contains(e.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
}
public class SoutTask implements Job {
@Override
public void execute(String paramsJson) {
if (StringUtils.isNotEmpty(paramsJson)) {
System.out.println(paramsJson);
} else {
System.out.println("no params");
}
}
}
@Component
public class SysTaskJobFacadeImpl {
private static final Logger logger = LoggerFactory.getLogger(SysTaskJobFacadeImpl.class);
@Autowired
private SysTaskJobDAO sysTaskJobDAO;
@Autowired
private ScheduleUtil scheduleUtil;
// 执行任务
// @Scheduled(cron = "0 0/1 * * * ? ")//每1分执行一次
@Scheduled(cron = "0/10 * * * * ? ")//每10秒执行一次
public void execute() {
List<SysTaskJob> taskJobList = sysTaskJobDAO.listTaskJob();
logger.info("flush timed task");
scheduleUtil.start(taskJobList);
}
}
1,建表 与jeecgboot中的表一致。
2,Job 接口 所有需要做定时执行的任务都需要 implements 该接口。做扩展只需要新建一个类,在数据库中插入一条数据即可。
3,ScheduleUtil 工具类 启动关闭定时任务
4,SoutTask 为测试类,implements Job 接口并实现 execute 方法,可以在 execute 方法中调用需要定时执行的方法即可。
5,调用 这里用了另一个定时任务定时获取数据库任务,这样当定时任务关闭时,可以自动停止定时任务。如果不考虑这些因素,也可以不要这个定时任务在初始化时,启动即可。
此处省略了 entity 实体类以及 dao 查询类