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..29287bdd8
--- /dev/null
+++ b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringCronUtil.java
@@ -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 动态定时任务封装
+ *
+ * - 创建定时任务
+ * - 修改定时任务
+ * - 取消定时任务
+ * - 高级操作
+ *
+ * 参考:Spring doc
+ *
+ * @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) {
+ 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 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/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..0f0032ef8 100644
--- a/hutool-extra/src/main/resources/META-INF/spring.factories
+++ b/hutool-extra/src/main/resources/META-INF/spring.factories
@@ -1,3 +1,5 @@
# 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,\
+cn.hutool.extra.spring.SpringCronUtil
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..e4959da27
--- /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);
+ }
+
+ /**
+ * 高级用法
+ * 参考:Spring doc
+ */
+ @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());
+ }
+}