写的一个简单的可以在页面进行配置的定时任务,存在不少问题。现在勉强能用。还是需要改进
定义一个任务接口:
public interface Task {
public void start();
public void stop();
public void restart();
public boolean isAlive();
}
抽象实现:
public abstract class BusinessTask implements Runnable, BeanNameAware, Task {
@Autowired(required = false)
protected ThreadPoolTaskScheduler threadPoolTaskScheduler;
@Autowired
TaskInfoDao taskInfoDao;
// 接收生成的定时计划
protected ScheduledFuture<?> future;
// 任务名称
protected String taskName;
TaskInfo taskInfo;
// 处理你的业务
public abstract void doBusiness();
@Override
public void run() {
// 检测配置有无更新
TaskInfo dbTaskInfo = getTaskInfo();
if (!dbTaskInfo.equals(this.taskInfo)) {
// 有更新重启定时任务
restart();
return;
}
// 未启用状态,不执行任务
if (this.taskInfo.getIsusing()) {
return;
}
//需要锁没有获取到锁就不执行
if(this.taskInfo.getNeedLock()&&!allowRun(taskInfo.getTimeout())) {
return;
}
excuteBusiness();
}
@Override
public void start() {
this.taskInfo = getTaskInfo();
this.future = threadPoolTaskScheduler.schedule(this, new CronTrigger(taskInfo.getCron()));
}
@Override
public void stop() {
if (future != null) {
future.cancel(true);
this.taskInfo = null;
}
}
@Override
public void restart() {
stop();
start();
}
@Override
public boolean isAlive() {
if (future == null) {
return false;
}
return !future.isCancelled();
}
@Override
public void setBeanName(String name) {
this.taskName = name;
}
// 分布式锁,利用redis的setne指令
private boolean allowRun(int timeout) {
return RedisUtils.tryLock(taskName, timeout);
}
// 获取taskInfo信息
private TaskInfo getTaskInfo() {
try {
TaskInfo taskInfo = taskInfoDao.get(taskName, null);
if (null == taskInfo) {
// 数据库没有配置,给一个默认配置的
TaskInfo newTask = new TaskInfo();
//把当前的bean名设置成主键
newTask.setCode(taskName);
newTask.setCron("0/30 * * * * ?");
newTask.setIsusing(1);// 启用状态
newTask.setTimeout(1);// 锁的过期时间
newTask.setName(taskName + "任务");
newTask.setNeedLock(0);
taskInfoDao.insertSelective(newTask);
taskInfo = newTask;
}
return taskInfo;
} catch (Exception e) {
log.error("获取taskInfo信息失败:" + taskName, e);
}
return null;
}
private synchronized void excuteBusiness() {
try {
doBusiness();
} catch (Exception e) {
log.warn("任务执行失败:class={},message={}", e.getClass().getName(), e.getMessage());
}
}
}
任务启动
public class TaskLauncher implements EasySpringListener {
@Override
public void doSome(ApplicationContext applicationContext) {
String systemType = System.getProperty("os.name");
String lowerCase = systemType.toLowerCase();
if (lowerCase.indexOf("linux") == -1) {
return;
}
Map<String, Task> tasks = applicationContext.getBeansOfType(Task.class);
tasks.forEach((k, task) -> task.start());
}
}
启动开关
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@EnableScheduling
@Import(TaskLauncher.class)
public @interface EnableBusinessTask {
}
页面配置:
使用示例:
public class SameUserTask extends BusinessTask {
@Override
public void doBusiness() {
pullUsers();
}
}