可以使用quartz等任務框架實現動態任務,但其實spring本身就支持
springboot簡單定時任務執行方式:
@Configuration
@EnableScheduling
public class SaticScheduleTask {
//添加定時任務
@Scheduled(cron = "0/5 * * * * ?")
//或直接指定時間間隔,例如:5秒
//@Scheduled(fixedRate=5000)
private void configureTasks() {
System.err.println("執行定時任務: " + LocalDateTime.now());
}
}
動態定時任務就複雜一些。但功能強大
1、編寫定時任務配置類
package com.iscas.biz.schedule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* 定時任務配置類
*
* @author zhuquanwen
* @vesion 1.0
* @date 2020/2/25 18:14
* @since jdk1.8
*/
@Configuration
public class SchedulingConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
// 定時任務執行線程池核心線程數
taskScheduler.setPoolSize(2);
taskScheduler.setRemoveOnCancelPolicy(true);
taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
return taskScheduler;
}
}
2、編寫定時任務註冊類
package com.iscas.biz.schedule;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 定時任務註冊類
*
* @author zhuquanwen
* @vesion 1.0
* @date 2020/2/25 18:15
* @since jdk1.8
*/
@Component
public class CronTaskRegister implements DisposableBean {
private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);
@Autowired
private TaskScheduler taskScheduler;
public TaskScheduler getScheduler() {
return this.taskScheduler;
}
/**
* 新增定時任務
* @param task
* @param cronExpression
*/
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));
}
}
/**
* 移除定時任務
* @param task
*/
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();
}
}
3、編寫定時任務執行類
package com.iscas.biz.schedule;
import com.iscas.base.biz.service.common.SpringService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* 定時任務執行類
*
* @author zhuquanwen
* @vesion 1.0
* @date 2020/2/25 18:16
* @since jdk1.8
*/
public class SchedulingRunnable implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);
private String beanName;
private String methodName;
private Object[] params;
public SchedulingRunnable(String beanName, String methodName) {
this(beanName, methodName, null);
}
public SchedulingRunnable(String beanName, String methodName, Object...params ) {
this.beanName = beanName;
this.methodName = methodName;
this.params = params;
}
@Override
public void run() {
logger.info("定時任務開始執行 - bean:{},方法:{},參數:{}", beanName, methodName, params);
long startTime = System.currentTimeMillis();
try {
Object target = SpringService.getBean(beanName);
Method method = null;
if (null != params && params.length > 0) {
Class<?>[] paramCls = new Class[params.length];
for (int i = 0; i < params.length; i++) {
paramCls[i] = params[i].getClass();
}
method = target.getClass().getDeclaredMethod(methodName, paramCls);
} else {
method = target.getClass().getDeclaredMethod(methodName);
}
ReflectionUtils.makeAccessible(method);
if (null != params && params.length > 0) {
method.invoke(target, params);
} else {
method.invoke(target);
}
} catch (Exception ex) {
logger.error(String.format("定時任務執行異常 - bean:%s,方法:%s,參數:%s ", beanName, methodName, params), ex);
}
long times = System.currentTimeMillis() - startTime;
logger.info("定時任務執行結束 - bean:{},方法:{},參數:{},耗時:{} 毫秒", 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);
}
}
4、編寫定時任務控制類
package com.iscas.biz.schedule;
import java.util.concurrent.ScheduledFuture;
/**
* 定時任務控制類
*
* @author zhuquanwen
* @vesion 1.0
* @date 2020/2/25 18:18
* @since jdk1.8
*/
public final class ScheduledTask {
public volatile ScheduledFuture<?> future;
/**
* 取消定時任務
*/
public void cancel() {
ScheduledFuture<?> future = this.future;
if (future != null) {
future.cancel(true);
}
}
}
5、測試
編寫一個任務執行類和執行函數
package com.iscas.biz.schedule;
import com.iscas.base.biz.config.Constants;
import com.iscas.base.biz.model.EquipSubscribeVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.user.SimpUser;
import org.springframework.messaging.simp.user.SimpUserRegistry;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* 編寫一個任務類和執行函數
*
* @author zhuquanwen
* @vesion 1.0
* @date 2020/2/25 18:31
* @since jdk1.8
*/
@Component("equipSubscribeClearTask")
public class EquipSubscribeClearTask {
@Autowired
private SimpUserRegistry userRegistry;
/**
* 清理訂閱的subscribe
* */
public void clearEquipSubscribe() {
Set<SimpUser> users = userRegistry.getUsers();
Map<String, List<EquipSubscribeVO>> subscribeQuip = Constants.SUBSCRIBE_QUIP;
Set<String> keys = Constants.SUBSCRIBE_QUIP.keySet();
if (CollectionUtils.isNotEmpty(keys)) {
for (String username : keys) {
if (CollectionUtils.isNotEmpty(users)) {
boolean flag = false;
for (SimpUser user : users) {
String name = user.getName();
if (Objects.equals(username, name)) {
flag = true;
break;
}
}
if (!flag) {
//清除
Constants.SUBSCRIBE_QUIP.remove(username);
}
}
}
}
}
}
使用spring調用
CronTaskRegister cronTaskRegister = applicationContext.getBean(CronTaskRegister.class);
//定時清理硬件屬性訂閱
SchedulingRunnable task = new SchedulingRunnable("equipSubscribeClearTask", "clearEquipSubscribe", null);
//每30S執行一次任務
cronTaskRegister.addCronTask(task, "0/30 * * * * ?");
執行結果在控制檯打印
2020-02-25 18:39:00.000 INFO com.iscas.biz.schedule.SchedulingRunnable Line:41 - 定時任務開始執行 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null
2020-02-25 18:39:03.076 INFO com.iscas.biz.schedule.SchedulingRunnable Line:69 - 定時任務執行結束 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null,耗時:3076 毫秒
2020-02-25 18:39:30.000 INFO com.iscas.biz.schedule.SchedulingRunnable Line:41 - 定時任務開始執行 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null
2020-02-25 18:47:17.137 INFO com.iscas.biz.schedule.SchedulingRunnable Line:69 - 定時任務執行結束 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null,耗時:467137 毫秒
2020-02-25 18:47:30.001 INFO com.iscas.biz.schedule.SchedulingRunnable Line:41 - 定時任務開始執行 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null
2020-02-25 18:47:33.494 INFO com.iscas.biz.schedule.SchedulingRunnable Line:69 - 定時任務執行結束 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null,耗時:3492 毫秒
2020-02-25 18:48:00.001 INFO com.iscas.biz.schedule.SchedulingRunnable Line:41 - 定時任務開始執行 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null
2020-02-25 18:48:00.001 INFO com.iscas.biz.schedule.SchedulingRunnable Line:69 - 定時任務執行結束 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null,耗時:0 毫秒
2020-02-25 18:48:30.000 INFO com.iscas.biz.schedule.SchedulingRunnable Line:41 - 定時任務開始執行 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null
2020-02-25 18:48:30.000 INFO com.iscas.biz.schedule.SchedulingRunnable Line:69 - 定時任務執行結束 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null,耗時:0 毫秒