- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Spring Boot如何实现定时任务的动态增删启停详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
我以为动态停启定时任务一般用quartz,没想到还可以通过ScheduledTaskRegistrar来拓展。但是分布式场景,建议还是用quartz吧! 。
在 spring boot 项目中,可以通过 @EnableScheduling 注解和 @Scheduled 注解实现定时任务,也可以通过 SchedulingConfigurer 接口来实现定时任务。但是这两种方式不能动态添加、删除、启动、停止任务。要实现动态增删启停定时任务功能,比较广泛的做法是集成 Quartz 框架.
但是本人的开发原则是:在满足项目需求的情况下,尽量少的依赖其它框架,避免项目过于臃肿和复杂。查看 spring-context 这个 jar 包中 org.springframework.scheduling.ScheduledTaskRegistrar 这个类的源代码,发现可以通过改造这个类就能实现动态增删启停定时任务功能.
定时任务列表页 。
定时任务执行日志 。
添加执行定时任务的线程池配置类 。
1
2
3
4
5
6
7
8
9
10
11
12
|
@Configuration
public
class
SchedulingConfig {
@Bean
public
TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler =
new
ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(
4
);
taskScheduler.setRemoveOnCancelPolicy(
true
);
taskScheduler.setThreadNamePrefix(
"TaskSchedulerThreadPool-"
);
return
taskScheduler;
}
}
|
添加 ScheduledFuture 的包装类。ScheduledFuture 是 ScheduledExecutorService 定时任务线程池的执行结果.
1
2
3
4
5
6
7
8
9
10
11
12
|
public
final
class
ScheduledTask {
volatile
ScheduledFuture<?> future;
public
void
cancel() {
ScheduledFuture<?> future =
this
.future;
if
(future !=
null
) {
future.cancel(
true
);
}
}
}
|
添加 Runnable 接口实现类,被定时任务线程池调用,用来执行指定 bean 里面的方法.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
public
class
SchedulingRunnable
implements
Runnable {
private
static
final
Logger logger = LoggerFactory.getLogger(SchedulingRunnable.
class
);
private
String beanName;
private
String methodName;
private
String params;
public
SchedulingRunnable(String beanName, String methodName) {
this
(beanName, methodName,
null
);
}
public
SchedulingRunnable(String beanName, String methodName, String 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 = SpringContextUtils.getBean(beanName);
Method method =
null
;
if
(StringUtils.isNotEmpty(params)) {
method = target.getClass().getDeclaredMethod(methodName, String.
class
);
}
else
{
method = target.getClass().getDeclaredMethod(methodName);
}
ReflectionUtils.makeAccessible(method);
if
(StringUtils.isNotEmpty(params)) {
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);
}
}
|
添加定时任务注册类,用来增加、删除定时任务.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
@Component
public
class
CronTaskRegistrar
implements
DisposableBean {
private
final
Map<Runnable, ScheduledTask> scheduledTasks =
new
ConcurrentHashMap<>(
16
);
@Autowired
private
TaskScheduler taskScheduler;
public
TaskScheduler getScheduler() {
return
this
.taskScheduler;
}
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));
}
}
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();
}
}
|
添加定时任务示例类 。
1
2
3
4
5
6
7
8
9
10
|
@Component
(
"demoTask"
)
public
class
DemoTask {
public
void
taskWithParams(String params) {
System.out.println(
"执行有参示例任务:"
+ params);
}
public
void
taskNoParams() {
System.out.println(
"执行无参示例任务"
);
}
}
|
定时任务数据库表设计 。
定时任务数据库表设计 。
添加定时任务实体类 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
public
class
SysJobPO {
private
Integer jobId;
private
String beanName;
private
String methodName;
private
String methodParams;
private
String cronExpression;
private
Integer jobStatus;
private
String remark;
private
Date createTime;
private
Date updateTime;
public
Integer getJobId() {
return
jobId;
}
public
void
setJobId(Integer jobId) {
this
.jobId = jobId;
}
public
String getBeanName() {
return
beanName;
}
public
void
setBeanName(String beanName) {
this
.beanName = beanName;
}
public
String getMethodName() {
return
methodName;
}
public
void
setMethodName(String methodName) {
this
.methodName = methodName;
}
public
String getMethodParams() {
return
methodParams;
}
public
void
setMethodParams(String methodParams) {
this
.methodParams = methodParams;
}
public
String getCronExpression() {
return
cronExpression;
}
public
void
setCronExpression(String cronExpression) {
this
.cronExpression = cronExpression;
}
public
Integer getJobStatus() {
return
jobStatus;
}
public
void
setJobStatus(Integer jobStatus) {
this
.jobStatus = jobStatus;
}
public
String getRemark() {
return
remark;
}
public
void
setRemark(String remark) {
this
.remark = remark;
}
public
Date getCreateTime() {
return
createTime;
}
public
void
setCreateTime(Date createTime) {
this
.createTime = createTime;
}
public
Date getUpdateTime() {
return
updateTime;
}
public
void
setUpdateTime(Date updateTime) {
this
.updateTime = updateTime;
}
}
|
新增定时任务 。
新增定时任务 。
1
2
3
4
5
6
7
8
9
10
11
|
boolean
success = sysJobRepository.addSysJob(sysJob);
if
(!success)
return
OperationResUtils.fail(
"新增失败"
);
else
{
if
(sysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())) {
SchedulingRunnable task =
new
SchedulingRunnable(sysJob.getBeanName(), sysJob.getMethodName(), sysJob.getMethodParams());
cronTaskRegistrar.addCronTask(task, sysJob.getCronExpression());
}
}
return
OperationResUtils.success();
|
修改定时任务,先移除原来的任务,再启动新任务 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
boolean
success = sysJobRepository.editSysJob(sysJob);
if
(!success)
return
OperationResUtils.fail(
"编辑失败"
);
else
{
if
(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())) {
SchedulingRunnable task =
new
SchedulingRunnable(existedSysJob.getBeanName(), existedSysJob.getMethodName(), existedSysJob.getMethodParams());
cronTaskRegistrar.removeCronTask(task);
}
if
(sysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())) {
SchedulingRunnable task =
new
SchedulingRunnable(sysJob.getBeanName(), sysJob.getMethodName(), sysJob.getMethodParams());
cronTaskRegistrar.addCronTask(task, sysJob.getCronExpression());
}
}
return
OperationResUtils.success();
|
删除定时任务 。
1
2
3
4
5
6
7
8
9
10
11
|
boolean
success = sysJobRepository.deleteSysJobById(req.getJobId());
if
(!success)
return
OperationResUtils.fail(
"删除失败"
);
else
{
if
(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())) {
SchedulingRunnable task =
new
SchedulingRunnable(existedSysJob.getBeanName(), existedSysJob.getMethodName(), existedSysJob.getMethodParams());
cronTaskRegistrar.removeCronTask(task);
}
}
return
OperationResUtils.success();
|
定时任务启动 / 停止状态切换 。
1
2
3
4
5
6
7
|
if
(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())) {
SchedulingRunnable task =
new
SchedulingRunnable(existedSysJob.getBeanName(), existedSysJob.getMethodName(), existedSysJob.getMethodParams());
cronTaskRegistrar.addCronTask(task, existedSysJob.getCronExpression());
}
else
{
SchedulingRunnable task =
new
SchedulingRunnable(existedSysJob.getBeanName(), existedSysJob.getMethodName(), existedSysJob.getMethodParams());
cronTaskRegistrar.removeCronTask(task);
}
|
添加实现了 CommandLineRunner 接口的 SysJobRunner 类,当 spring boot 项目启动完成后,加载数据库里状态为正常的定时任务.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
@Service
public
class
SysJobRunner
implements
CommandLineRunner {
private
static
final
Logger logger = LoggerFactory.getLogger(SysJobRunner.
class
);
@Autowired
private
ISysJobRepository sysJobRepository;
@Autowired
private
CronTaskRegistrar cronTaskRegistrar;
@Override
public
void
run(String... args) {
List<SysJobPO> jobList = sysJobRepository.getSysJobListByStatus(SysJobStatus.NORMAL.ordinal());
if
(CollectionUtils.isNotEmpty(jobList)) {
for
(SysJobPO job : jobList) {
SchedulingRunnable task =
new
SchedulingRunnable(job.getBeanName(), job.getMethodName(), job.getMethodParams());
cronTaskRegistrar.addCronTask(task, job.getCronExpression());
}
logger.info(
"定时任务已加载完毕..."
);
}
}
}
|
工具类 SpringContextUtils,用来从 spring 容器里获取 bean 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
@Component
public
class
SpringContextUtils
implements
ApplicationContextAware {
private
static
ApplicationContext applicationContext;
@Override
public
void
setApplicationContext(ApplicationContext applicationContext)
throws
BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public
static
Object getBean(String name) {
return
applicationContext.getBean(name);
}
public
static
<T> T getBean(Class<T> requiredType) {
return
applicationContext.getBean(requiredType);
}
public
static
<T> T getBean(String name, Class<T> requiredType) {
return
applicationContext.getBean(name, requiredType);
}
public
static
boolean
containsBean(String name) {
return
applicationContext.containsBean(name);
}
public
static
boolean
isSingleton(String name) {
return
applicationContext.isSingleton(name);
}
public
static
Class<?
extends
Object> getType(String name) {
return
applicationContext.getType(name);
}
}
|
总结 。
到此这篇关于Spring Boot如何实现定时任务的动态增删启停的文章就介绍到这了,更多相关SpringBoot定时任务的动态增删启停内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://www.geek521.com/2020/07/18/springboot实现定时任务的动态增删启停/ 。
最后此篇关于Spring Boot如何实现定时任务的动态增删启停详解的文章就讲到这里了,如果你想了解更多关于Spring Boot如何实现定时任务的动态增删启停详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Task.WaitAll 方法等待所有任务,Task.WaitAny 方法等待一个任务。如何等待任意N个任务? 用例:下载搜索结果页面,每个结果都需要一个单独的任务来下载和处理。如果我使用 WaitA
我正在查看一些像这样的遗留 C# 代码: await Task.Run(() => { _logger.LogException(LogLevel.Error, mes
如何在 Linux 中运行 cron 任务? 关注此Q&A ,我有这个 cron 任务要运行 - 只是将一些信息写入 txt 文件, // /var/www/cron.php $myfile = fo
原谅我的新手问题,但我想按顺序执行三个任务并在剧本中使用两个角色: 任务 角色 任务 角色 任务 这是我到目前为止(任务,角色,任务): --- - name: Task Role Task ho
我有一个依赖于 installDist 的自定义任务 - 不仅用于执行,还依赖于 installDist 输出: project.task('run', type: JavaExec, depends
从使用 Wix 创建的 MSI 运行卸载时,我需要在尝试删除任何文件之前强行终止在后台运行的进程。主要应用程序由一个托盘图标组成,它反射(reflect)了 bg 进程监控本地 Windows 服务的
我想编写 Ant 任务来自动执行启动服务器的任务,然后使用我的应用程序的 URL 打开 Internet Explorer。 显然我必须执行 startServer先任务,然后 startApplic
使用 ASP.NET 4.5,我正在尝试使用新的 async/await 玩具。我有一个 IDataReader 实现类,它包装了一个特定于供应商的阅读器(如 SqlDatareader)。我有一个简
使用命令 gradle tasks可以得到一份所有可用任务的报告。有什么方法可以向此命令添加参数并按任务组过滤任务。 我想发出类似 gradle tasks group:Demo 的命令筛选所有任务并
除了sshexec,还有什么办法吗?任务要做到这一点?我知道您可以使用 scp 复制文件任务。但是,我需要执行其他操作,例如检查是否存在某些文件夹,然后将其删除。我想使用类似 condition 的东
假设我有字符串 - "D:\ApEx_Schema\Functions\new.sql@@\main\ONEVIEW_Integration\3" 我需要将以下内容提取到 diff 变量中 - 文档名
我需要编写一个 ant 任务来确定某个文件是否是只读的,如果是,则失败。我想避免使用自定义选择器来为我们的构建系统的性质做这件事。任何人都有任何想法如何去做?我正在使用 ant 1.8 + ant-c
这是一个相当普遍的计算机科学问题,并不特定于任何操作系统或框架。 因此,我对与在线程池上切换任务相关的开销感到有些困惑。在许多情况下,给每个作业分配自己的特定线程是没有意义的(我们不想创建太多硬件线程
我正在使用以下 Ansible playbook 一次性关闭远程 Ubuntu 主机列表: - hosts: my_hosts become: yes remote_user: my_user
如何更改 Ant 中的当前工作目录? Ant documentation没有 任务,在我看来,最好的做法是不要更改当前工作目录。 但让我们假设我们仍然想这样做——你会如何做到这一点?谢谢! 最佳答案
是否可以运行 cronjob每三天一次?或者也许每月 10 次。 最佳答案 每三天运行一次 - 或更短时间在月底运行一次。 (如果上个月有 31 天,它将连续运行 2 天。) 0 0 */3 * *
如何在 Gradle 任务中执行托管在存储库中的工具? 在我的具体情况下,我正在使用 Gradle 构建一个 Android 应用程序。我添加了一项任务,将一些 protobuf 数据从文本编码为二进
我的项目有下一个结构: Root |- A |- C (depends on A) \- B (depends on A) 对于所有子项目,我们使用自己的插件生成资源:https://githu
我设置了一个具有4个节点的Hadoop群集,其中一个充当HDFS的NameNode以及Yarn主节点。该节点也是最强大的。 现在,我分发了2个文本文件,一个在node01(名称节点)上,一个在node
在 TFS 2010 中为多个用户存储任务的最佳方式是什么?我只能为一项任务分配一个。 (例如:当我计划向所有开发人员演示时) (这是一个 Scrum Msf 敏捷项目,其中任务是用户故事的一部分)
我是一名优秀的程序员,十分优秀!