mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
commit
f6d19d19ea
@ -0,0 +1,149 @@
|
|||||||
|
package cn.hutool.extra.spring;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import org.springframework.scheduling.TaskScheduler;
|
||||||
|
import org.springframework.scheduling.support.CronTrigger;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring 动态定时任务封装
|
||||||
|
* <ol>
|
||||||
|
* <li>创建定时任务</li>
|
||||||
|
* <li>修改定时任务</li>
|
||||||
|
* <li>取消定时任务</li>
|
||||||
|
* <li>高级操作</li>
|
||||||
|
* </ol>
|
||||||
|
* 参考:<a href="https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling">Spring doc</a>
|
||||||
|
*
|
||||||
|
* @author JC
|
||||||
|
* @date 03/13
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SpringCronUtil {
|
||||||
|
/**
|
||||||
|
* 任务调度器
|
||||||
|
*/
|
||||||
|
private static TaskScheduler taskScheduler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID 与 Future 绑定
|
||||||
|
*/
|
||||||
|
private static final Map<Serializable, ScheduledFuture<?>> TASK_FUTURE = MapUtil.newConcurrentHashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID 与 Runnable 绑定
|
||||||
|
*/
|
||||||
|
private static final Map<Serializable, Runnable> TASK_RUNNABLE = MapUtil.newConcurrentHashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加入定时任务
|
||||||
|
*
|
||||||
|
* @param task 任务
|
||||||
|
* @param expression 定时任务执行时间的cron表达式
|
||||||
|
* @return 定时任务ID
|
||||||
|
*/
|
||||||
|
public static String schedule(Runnable task, String expression) {
|
||||||
|
String id = IdUtil.fastUUID();
|
||||||
|
return schedule(id, task, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加入定时任务
|
||||||
|
*
|
||||||
|
* @param id 定时任务ID
|
||||||
|
* @param expression 定时任务执行时间的cron表达式
|
||||||
|
* @param task 任务
|
||||||
|
* @return 定时任务ID
|
||||||
|
*/
|
||||||
|
public static String schedule(Serializable id, Runnable task, String expression) {
|
||||||
|
ScheduledFuture<?> schedule = taskScheduler.schedule(task, new CronTrigger(expression));
|
||||||
|
TASK_FUTURE.put(id, schedule);
|
||||||
|
TASK_RUNNABLE.put(id, task);
|
||||||
|
return id.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改定时任务
|
||||||
|
*
|
||||||
|
* @param id 定时任务ID
|
||||||
|
* @param expression 定时任务执行时间的cron表达式
|
||||||
|
* @return 是否修改成功,{@code false}表示未找到对应ID的任务
|
||||||
|
*/
|
||||||
|
public static boolean update(Serializable id, String expression) {
|
||||||
|
if (!TASK_FUTURE.containsKey(id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ScheduledFuture<?> future = TASK_FUTURE.get(id);
|
||||||
|
if (future == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
future.cancel(true);
|
||||||
|
schedule(id, TASK_RUNNABLE.get(id), expression);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除任务
|
||||||
|
*
|
||||||
|
* @param schedulerId 任务ID
|
||||||
|
* @return 是否移除成功,{@code false}表示未找到对应ID的任务
|
||||||
|
*/
|
||||||
|
public static boolean cancel(Serializable schedulerId) {
|
||||||
|
if (!TASK_FUTURE.containsKey(schedulerId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ScheduledFuture<?> future = TASK_FUTURE.get(schedulerId);
|
||||||
|
boolean cancel = future.cancel(false);
|
||||||
|
if (cancel) {
|
||||||
|
TASK_FUTURE.remove(schedulerId);
|
||||||
|
TASK_RUNNABLE.remove(schedulerId);
|
||||||
|
}
|
||||||
|
return cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
public void setTaskScheduler(TaskScheduler taskScheduler) {
|
||||||
|
SpringCronUtil.taskScheduler = taskScheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 获得Scheduler对象
|
||||||
|
*/
|
||||||
|
public static TaskScheduler getScheduler() {
|
||||||
|
return taskScheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得当前运行的所有任务
|
||||||
|
*
|
||||||
|
* @return 所有任务
|
||||||
|
*/
|
||||||
|
public static List<Serializable> getAllTask() {
|
||||||
|
if (CollUtil.isNotEmpty(TASK_FUTURE.keySet())) {
|
||||||
|
return new ArrayList<>(TASK_FUTURE.keySet());
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消所有的任务
|
||||||
|
*/
|
||||||
|
public static void destroy() {
|
||||||
|
for (ScheduledFuture<?> future : TASK_FUTURE.values()) {
|
||||||
|
if (future != null) {
|
||||||
|
future.cancel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TASK_FUTURE.clear();
|
||||||
|
TASK_RUNNABLE.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package cn.hutool.extra.spring.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.TaskScheduler;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 可自行配置任务线程池, 修改默认参数
|
||||||
|
*
|
||||||
|
* @author JC
|
||||||
|
* @date 03/13
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
public class SpringCronConfig {
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(value = TaskScheduler.class)
|
||||||
|
public TaskScheduler taskScheduler() {
|
||||||
|
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||||
|
// 任务线程池初始化
|
||||||
|
scheduler.setThreadNamePrefix("TaskScheduler-");
|
||||||
|
scheduler.setPoolSize(Runtime.getRuntime().availableProcessors() / 3 + 1);
|
||||||
|
|
||||||
|
// 保证能立刻丢弃运行中的任务
|
||||||
|
scheduler.setRemoveOnCancelPolicy(true);
|
||||||
|
return scheduler;
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
# Auto Configure
|
# Auto Configure
|
||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
cn.hutool.extra.spring.SpringUtil
|
cn.hutool.extra.spring.SpringUtil,\
|
||||||
|
cn.hutool.extra.spring.config.SpringCronConfig,\
|
||||||
|
cn.hutool.extra.spring.SpringCronUtil
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
package cn.hutool.extra.spring;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.extra.spring.config.SpringCronConfig;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.scheduling.TaskScheduler;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JC
|
||||||
|
* @date 03/13
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@SpringBootTest(classes = {SpringCronConfig.class, SpringCronUtil.class})
|
||||||
|
public class SpringCronUtilTest {
|
||||||
|
/**
|
||||||
|
* 创建一个定时任务
|
||||||
|
* 观察日志可进行验证
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void registerTask() {
|
||||||
|
String ID1 = SpringCronUtil.schedule(this::task, "0/1 * * * * ?");
|
||||||
|
String ID2 = SpringCronUtil.schedule(888, this::task, "0/1 * * * * ?");
|
||||||
|
log.info("taskId: {},{}", ID1, ID2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改一个定时任务
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@SneakyThrows
|
||||||
|
public void updateTask() {
|
||||||
|
SpringCronUtil.schedule(888, this::task, "0/1 * * * * ?");
|
||||||
|
Thread.sleep(5000);
|
||||||
|
boolean update = SpringCronUtil.update(888, "0/5 * * * * ?");
|
||||||
|
log.info("update task result: {}", update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消一个定时任务
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@SneakyThrows
|
||||||
|
public void cancelTask() {
|
||||||
|
SpringCronUtil.schedule(888, this::task, "0/1 * * * * ?");
|
||||||
|
Thread.sleep(5000);
|
||||||
|
boolean cancel = SpringCronUtil.cancel(888);
|
||||||
|
log.info("cancel task result: {}", cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高级用法
|
||||||
|
* 参考:<a href="https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling">Spring doc</a>
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void senior() {
|
||||||
|
TaskScheduler scheduler = SpringCronUtil.getScheduler();
|
||||||
|
// 给定时间 开始, 间隔时间..
|
||||||
|
scheduler.scheduleAtFixedRate(this::task, Instant.now(), Duration.ofMinutes(10));
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消全部定时任务
|
||||||
|
* 查看当前所有的任务
|
||||||
|
*/
|
||||||
|
@After
|
||||||
|
@SneakyThrows
|
||||||
|
public void cancelAll() {
|
||||||
|
Thread.sleep(10000);
|
||||||
|
List<Serializable> allTask = SpringCronUtil.getAllTask();
|
||||||
|
log.info("allTask: {}", allTask);
|
||||||
|
|
||||||
|
SpringCronUtil.destroy();
|
||||||
|
|
||||||
|
allTask = SpringCronUtil.getAllTask();
|
||||||
|
log.info("allTask: {}", allTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void task() {
|
||||||
|
log.info("information only.. (date:{})", DateUtil.now());
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user