From 55c9b0c37a6f124f3bd97e15f357de84cc2d7a36 Mon Sep 17 00:00:00 2001 From: jcsun <80867809@qq.com> Date: Sun, 13 Mar 2022 18:14:36 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Spring=20Task=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../extra/spring/config/SpringCronConfig.java | 31 +++++++++++++++++++ .../main/resources/META-INF/spring.factories | 3 +- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 hutool-extra/src/main/java/cn/hutool/extra/spring/config/SpringCronConfig.java diff --git a/hutool-extra/src/main/java/cn/hutool/extra/spring/config/SpringCronConfig.java b/hutool-extra/src/main/java/cn/hutool/extra/spring/config/SpringCronConfig.java new file mode 100644 index 000000000..1f31d0832 --- /dev/null +++ b/hutool-extra/src/main/java/cn/hutool/extra/spring/config/SpringCronConfig.java @@ -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; + } +} diff --git a/hutool-extra/src/main/resources/META-INF/spring.factories b/hutool-extra/src/main/resources/META-INF/spring.factories index 7b08ebdf8..06d39a3ec 100644 --- a/hutool-extra/src/main/resources/META-INF/spring.factories +++ b/hutool-extra/src/main/resources/META-INF/spring.factories @@ -1,3 +1,4 @@ # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -cn.hutool.extra.spring.SpringUtil \ No newline at end of file +cn.hutool.extra.spring.SpringUtil,\ +cn.hutool.extra.spring.config.SpringCronConfig From c73ea53f8f504f0d6e46f7d5c308040158bb090d Mon Sep 17 00:00:00 2001 From: jcsun <80867809@qq.com> Date: Sun, 13 Mar 2022 18:30:34 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=20=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hutool/extra/spring/SpringCronUtil.java | 157 ++++++++++++++++++ .../main/resources/META-INF/spring.factories | 3 +- 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java diff --git a/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java new file mode 100644 index 000000000..01947029a --- /dev/null +++ b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java @@ -0,0 +1,157 @@ +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 动态定时任务封装 + *
    + *
  1. 创建定时任务
  2. + *
  3. 修改定时任务
  4. + *
  5. 取消定时任务
  6. + *
  7. 高级操作
  8. + *
+ * + * @author JC + * @date 03/13 + */ +@Component +public class SpringCronUtil { + /** + * 任务调度器 + */ + private static TaskScheduler taskScheduler; + + /** + * ID 与 Future 绑定 + */ + private static final Map> TASK_FUTURE = MapUtil.newConcurrentHashMap(); + + /** + * ID 与 Runnable 绑定 + */ + private static final Map 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) { + ScheduledFuture future = getScheduledFuture(schedulerId); + if (future == null) { + return false; + } + 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 获得ScheduledFuture对象 + */ + private static ScheduledFuture getScheduledFuture(Serializable id) { + return TASK_FUTURE.get(id); + } + + /** + * 获得当前运行的所有任务 + * + * @return 所有任务 + */ + public static List 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(); + } +} diff --git a/hutool-extra/src/main/resources/META-INF/spring.factories b/hutool-extra/src/main/resources/META-INF/spring.factories index 06d39a3ec..0f0032ef8 100644 --- a/hutool-extra/src/main/resources/META-INF/spring.factories +++ b/hutool-extra/src/main/resources/META-INF/spring.factories @@ -1,4 +1,5 @@ # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ cn.hutool.extra.spring.SpringUtil,\ -cn.hutool.extra.spring.config.SpringCronConfig +cn.hutool.extra.spring.config.SpringCronConfig,\ +cn.hutool.extra.spring.SpringCronUtil From 57212bfdbac019b6e3eb050271ca6ed973585580 Mon Sep 17 00:00:00 2001 From: jcsun <80867809@qq.com> Date: Sun, 13 Mar 2022 18:40:13 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20junit=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/hutool/extra/spring/SpringCronUtil.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java index 01947029a..0599a74fc 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java @@ -97,10 +97,10 @@ public class SpringCronUtil { * @return 是否移除成功,{@code false}表示未找到对应ID的任务 */ public static boolean cancel(Serializable schedulerId) { - ScheduledFuture future = getScheduledFuture(schedulerId); - if (future == null) { + if (!TASK_FUTURE.containsKey(schedulerId)) { return false; } + ScheduledFuture future = TASK_FUTURE.get(schedulerId); boolean cancel = future.cancel(false); if (cancel) { TASK_FUTURE.remove(schedulerId); @@ -121,15 +121,6 @@ public class SpringCronUtil { return taskScheduler; } - /** - * 可在项目中 进行细粒度控制 - * - * @return 获得ScheduledFuture对象 - */ - private static ScheduledFuture getScheduledFuture(Serializable id) { - return TASK_FUTURE.get(id); - } - /** * 获得当前运行的所有任务 * From 0fee267e4a2d2959b390fc59dd707cf6e3d05bd3 Mon Sep 17 00:00:00 2001 From: jcsun <80867809@qq.com> Date: Sun, 13 Mar 2022 18:40:21 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20junit=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../extra/spring/SpringCronUtilTest.java | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 hutool-extra/src/test/java/cn/hutool/extra/spring/SpringCronUtilTest.java diff --git a/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringCronUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringCronUtilTest.java new file mode 100644 index 000000000..a3eb1e615 --- /dev/null +++ b/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringCronUtilTest.java @@ -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); + } + + /** + * 高级用法 + * 参考: + */ + @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 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()); + } +} From b730ccf47070986956173fcca25a4e2d90bbe013 Mon Sep 17 00:00:00 2001 From: jcsun <80867809@qq.com> Date: Sun, 13 Mar 2022 18:44:31 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E5=8F=82=E8=80=83?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/extra/spring/SpringCronUtil.java | 1 + .../test/java/cn/hutool/extra/spring/SpringCronUtilTest.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java index 0599a74fc..29287bdd8 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java @@ -22,6 +22,7 @@ import java.util.concurrent.ScheduledFuture; *
  • 取消定时任务
  • *
  • 高级操作
  • * + * 参考:Spring doc * * @author JC * @date 03/13 diff --git a/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringCronUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringCronUtilTest.java index a3eb1e615..e4959da27 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringCronUtilTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringCronUtilTest.java @@ -61,7 +61,7 @@ public class SpringCronUtilTest { /** * 高级用法 - * 参考: + * 参考:Spring doc */ @Test public void senior() {