- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章浅谈springboot项目中定时任务如何优雅退出由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
在一个springboot项目中需要跑定时任务处理批数据时,突然有个Kill命令或者一个Ctrl+C的命令,此时我们需要当批数据处理完毕后才允许定时任务关闭,也就是当定时任务结束时才允许Kill命令生效.
启动类 。
启动类上我们获取到相应的上下文,捕捉相应命令。在这里插入代码片 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@SpringBootApplication
/**指定mapper对应包的路径*/
@MapperScan
(
"com.youlanw.kz.dao"
)
/**开启计划任务*/
@EnableScheduling
/**开启异常重试机制*/
@EnableRetry
public
class
YlkzTaskApplication {
public
static
ConfigurableApplicationContext context;
public
static
void
main(String[] args) {
context = SpringApplication.run(YlkzTaskApplication.
class
, args);
/**
* 捕捉命令实现优雅退出
*/
MySignalHandler.install(
"TERM"
);
//捕捉kill命令
MySignalHandler.install(
"INT"
);
//捕捉ctrl+c命令
}
}
|
优雅退出配置类 。
通过install方法捕捉到相应的命令, 。
通过signalAction方法进行总开发的控制.
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
|
import
org.slf4j.LoggerFactory;
import
sun.misc.Signal;
import
sun.misc.SignalHandler;
/**
* @description: 定时任务控制类(实现优雅退出)
* @method:
* @author: mamengmeng
* @date: 10:51 2018/8/13
*/
public
class
MySignalHandler
implements
SignalHandler {
private
final
static
org.slf4j.Logger logger = LoggerFactory.getLogger(MySignalHandler.
class
);
private
SignalHandler oldHandler;
/**
* 定时任务总开关-状态:true:打开 false:关闭
*/
public
static
boolean
base_flag =
true
;
@Override
public
void
handle(Signal signal) {
signalAction(signal);
}
public
static
SignalHandler install(String signalName) {
Signal diagSignal =
new
Signal(signalName);
MySignalHandler instance =
new
MySignalHandler();
instance.oldHandler = Signal.handle(diagSignal, instance);
return
instance;
}
public
void
signalAction(Signal signal) {
try
{
//关闭总开关
this
.base_flag =
false
;
logger.info(
"\n执行优雅退出操作\n等待运行中任务执行完毕…………"
);
Thread.sleep(
3000
);
StringBuffer stringBuffer =
new
StringBuffer(
"a"
);
//此处为相关的业务代码,只要还有一个定时任务在执行,那么就等待线程任务执行完毕。
while
(BaseApplyTask.apply_flag || BaseResumeTask.resume_flag || CorpDemandTask.demand_flag || RecommendResumeTask.resume_flag || BaseCodeTask.code_flag || RecommendoneTask.resume_flag ||ResumeByZcbTask.zpbresume_flag) {
//等待线程任务执行完毕
stringBuffer.append(
""
);
}
//获取到的上下文对象关闭相应的程序。
YlkzTaskApplication.context.close();
logger.info(
"\n================\n程序已安全退出!\n================"
);
oldHandler.handle(signal);
}
catch
(Exception e) {
logger.error(
"handle|Signal handler"
+
"failed, reason "
+ e.getMessage());
e.printStackTrace();
}
}
}
|
举例说明 。
我们在定时任务中添加一个总开关,当总开关是关着时是不允许定时任务执行的, 。
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
|
@Component
public
class
BaseCodeTask {
private
final
static
Logger logger = LoggerFactory.getLogger(BaseCodeTask.
class
);
@Autowired
private
ResumeService resumeService;
public
static
boolean
code_flag =
true
;
//简历任务执行状态 true:执行中 false:执行完毕
private
static
final
Integer LIMIT =
500
;
private
final
static
long
time =
60
*
1000
;
//一分钟
/**
* @param
* @description: 同步简历信息(定时任务)
* 任务执行间隔时间:6秒
* 待同步数据为空,则5分钟后执行下一次
* @method: sendResume
* @author: zhengmingjie
* @date: 16:17 2018/8/3
* @return: void
*/
@Scheduled
(initialDelay =
1000
, fixedDelay = time /
10
)
@Async
public
void
sendResume()
throws
Exception {
List<Resume> list =
null
;
try
{
//总开关状态:true:打开 false:关闭
if
(!MySignalHandler.base_flag)
return
;
this
.code_flag =
true
;
logger.info(
"\n======定时任务:初始化基本数据======\n开始执行\n"
);
//以下是业务代码。相关的定时任务批处理
resumeService.initializationMap();
resumeService.setCodeDictionary();
resumeService.setCityInfo();
resumeService.setCodePostInfo();
logger.info(
"\n======定时任务:初始化基本数据======\n结束\n"
);
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
this
.code_flag =
false
;
}
}
}
|
定时任务优雅退出的使用可以有效的防止批处理任务的中断,小伙伴们可以尝试添加哦。。。.
补充知识:springboot自带定时器实现定时任务的开启关闭以及动态修改定时规则 。
最近项目中遇到了需要自动定时导出的需求,用户可以从页面修改导出的时间规则,可以启用和停用定时任务.
经过了解,项目中目前实现定时任务,一般有三种选择,一是用Java自带的timer类。稍微看了一下,可以实现大部分的指定频率的任务的调度(timer.schedule()),也可以实现关闭和开启(timer.cancle)。但是用其来实现某天的某个时间或者某月的某一天调度任务有点不方便.
二是采用Quartz 调度器实现。这是一个功能很强大的开源的专门用于定时任务调度的框架,也很好的和springboot整合,缺点:配置复杂,需要花费一定的时间去了解和研究。(本人懒,因此没有选择这个,但是这个功能地区强大,有时间研究) 。
三是spring3.0以后自带的scheduletask任务调度,可以实现quartz的大部分功能,不需要额外引用jar,也不需要另外配置。而且支持注解和配置文件两种.
因此最后选择直接用spring自带的task 实现.
基本用法很简单,通过在方法上加注解@schedule(也可以通过xml文件配置的方式),注解里有 cron ,fixedDelay ,fixedRate ,initialDelay 等等参数,可以完成指定时间,平率执行此方法。这里不详细介绍.
直接介绍,通过页面动态修改cron参数,修改定时规则的思路.
1 实现接口SchedulingConfigurer,这个接口只有一个方法,配置定时任务。重写此方法,添加新的任务实现runable和新的触发 实现trigger .
2 在新的触发里,把修改的cron写入新的触发 。
3 写UI 方法,接收前端修改的定时参数.
代码如下:
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
|
package
com.fiberhome.ms.cus.cashform.ui;
import
java.util.Date;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.scheduling.Trigger;
import
org.springframework.scheduling.TriggerContext;
import
org.springframework.scheduling.annotation.SchedulingConfigurer;
import
org.springframework.scheduling.config.ScheduledTaskRegistrar;
import
org.springframework.scheduling.support.CronTrigger;
import
org.springframework.stereotype.Component;
@Component
public
class
DynamicScheduledTask
implements
SchedulingConfigurer {
@Autowired
private
ScheduleExport scheduleExport;
// private static String DEFAULT_CRON = "0/10 * * * * ?";
private
String cron =
""
;
public
String getCron() {
return
cron;
}
public
void
setCron(String cron) {
this
.cron = cron;
}
@Override
public
void
configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// TODO Auto-generated method stub
taskRegistrar.addTriggerTask(
new
Runnable() {
@Override
public
void
run() {
// TODO Auto-generated method stub
try
{
scheduleExport.scheduleTaskExport();
//异步定时生成文件
System.out.println(
"Msg:定时生成文件成功"
);
}
catch
(Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(
"Error:定时生成文件错误"
);
}
}
},
new
Trigger() {
@Override
public
Date nextExecutionTime(TriggerContext triggerContext) {
// TODO Auto-generated method stub
if
(
""
.equals(cron)|| cron ==
null
)
return
null
;
CronTrigger trigger =
new
CronTrigger(cron);
// 定时任务触发,可修改定时任务的执行周期
Date nextExecDate = trigger.nextExecutionTime(triggerContext);
return
nextExecDate;
}
});
System.out.println(
"can?"
);
}
}
|
这个方法可以实现 根据页面设置动态修改定时器的cron参数,不用重启服务。但是运行之后发现了一个缺陷,即必须在修改完之后,只有再一次到达定时任务的时间,才会调用新的触发时间, 这就导致,页面设置的时间并不能即时生效,这在项目中是不符合用户的要求,于是为了解决这个bug,换了另外一种解决方法.
思路:(了解ThreadPoolTaskScheduler这个类,TaskScheduler接口的默认实现类,多线程定时任务执行。可以设置执行线程池数(默认一个线程)) 。
1、ThreadPoolTaskScheduler 实现TaskScheduler,可以通过方法 schedule(java.lang.Runnable task, Trigger trigger),添加定时任务和触发器。返回java.util.concurrent.ScheduledFuture<?>,future可以控制任务的开关等.
2、前端修改定时参数,在set方法中修改ThreadPoolTaskScheduler 的触发器.
代码如下:
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
|
package
com.fiberhome.ms.cus.cashform.ui.util;
import
java.util.Date;
import
java.util.concurrent.ScheduledFuture;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.scheduling.Trigger;
import
org.springframework.scheduling.TriggerContext;
import
org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import
org.springframework.scheduling.support.CronTrigger;
import
org.springframework.stereotype.Component;
import
com.fiberhome.ms.cus.cashform.ui.ScheduleExport;
@Component
public
class
DynamicScheduleTaskSecond {
@Autowired
private
ThreadPoolTaskScheduler threadPoolTaskScheduler;
@Autowired
private
ScheduleExport scheduleExport;
private
ScheduledFuture<?> future;
private
String cron =
""
;
public
String getCron() {
return
cron;
}
public
void
setCron(String cron) {
this
.cron = cron;
stopCron();
future = threadPoolTaskScheduler.schedule(
new
Runnable() {
@Override
public
void
run() {
// TODO Auto-generated method stub
try
{
scheduleExport.scheduleTaskExport();
// 异步定时生成文件
System.out.println(
"Msg:定时生成文件成功"
);
}
catch
(Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(
"Error:定时生成文件错误"
);
}
}
},
new
Trigger() {
@Override
public
Date nextExecutionTime(TriggerContext triggerContext) {
// TODO Auto-generated method stub
if
(
""
.equals(cron) || cron ==
null
)
return
null
;
CronTrigger trigger =
new
CronTrigger(cron);
// 定时任务触发,可修改定时任务的执行周期
Date nextExecDate = trigger.nextExecutionTime(triggerContext);
return
nextExecDate;
}
});
}
public
void
stopCron() {
if
(future !=
null
) {
future.cancel(
true
);
//取消任务调度
}
}
}
|
验证可行,作个记录,如果有认为可以调整的地方,欢迎讨论! 。
以上这篇浅谈springboot项目中定时任务如何优雅退出就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我.
原文链接:https://blog.csdn.net/weixin_42395975/article/details/95946020 。
最后此篇关于浅谈springboot项目中定时任务如何优雅退出的文章就讲到这里了,如果你想了解更多关于浅谈springboot项目中定时任务如何优雅退出的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
SpringBoot-Admin 服务监控 简单介绍 Spring Boot Actuator 是 Spring Boot 自带的一个功能模块, 提供了一组已经开箱即用的生产环境下常用
我想查找通过关键字匹配字段 nameEnglish 或 nameChinese 的模型列表。我花了一个多小时谷歌搜索但我做不到。请帮忙。 Springboot Mongo 入门示例 https://s
(请注意:在调查 this issue 时,我更好地发现了我在此处介绍的问题根源) 我对 Hibernate 和 SpringBoot 非常陌生。我的项目涉及一个搜索引擎,其中索引(javafx 客户
我最近有一个 Web 应用程序从 springboot 升级到 springboot 2。当我将其部署到 Tomcat 8 时,它似乎启动了,但没有完全启动。 在 localhost.2019-09-
我是 Spring boot 的新手...我在运行 Controller 时遇到问题, Description: Field todoService in com.springboot.todoCon
我有一个SpringBoot应用程序,它使用以下配置与PostgreSQL通信,通过AWS Beanstrik部署:。在我将AWS Aurora证书更新为rds-ca-ecc384-g1之前,一切都很
实在是不知道标题写什么了 可以在评论区给个建议哈哈哈哈 先用这个作为标题吧 尝试使用 国内给出的 AI 大模型做出一个 可以和 AI 对话的 网站出来 使用 智普AI 只能 在控制
一、介绍 在实际的软件系统开发过程中,由于业务的需求,在代码层面实现数据的脱敏还是远远不够的,往往还需要在数据库层面针对某些关键性的敏感信息,例如:身份证号、银行卡号、手机号、工资等信息进行加密存储
Selenium Selenium是一个用于Web应用程序自动化测试的开源工具套件。它主要用于以下目的: 浏览器自动化:Selenium能够模拟真实用户在不同浏览器(如Chrome、Fire
一、简介 在实际的项目开发过程中,经常需要用到邮件通知功能。例如,通过邮箱注册,邮箱找回密码,邮箱推送报表等等,实际的应用场景非常的多。 早期的时候,为了能实现邮件的自动发送功能,通常会使用 Ja
SpringBoot:基于redis自定义注解实现后端接口防重复提交校验 一、添加依赖 org.springframework.boot spring
SpringBoot:使用Jackson完成全局序列化配置 一、测试准备 com.fasterxml.jackson.core jackson-cor
springboot:整合rocketmq 一、简易消息操作 生产者整合mq 导入依赖 org.springframework.boot
springboot:常用注解 一、spring常用注解 包扫描+组件标注注解 @Component:泛指各种组件 @Controller、@Service、@Repository都可以称为@Comp
我们经常需要在两个系统之间进行一些数据的交互,这时候我们就需要开发数据交互接口。 一般来说,遇到比较多的接口有HTTP接口、WebService接口、FTP文件传输。今天我要来学习一下在SpringB
背景 近期项目上线,甲方要求通过安全检测才能进行验收,故针对扫描结果对系统进行了一系列的安全加固,本文对一些常见的安全问题及防护策略进行介绍,提供对应的解决方案 跨站脚本攻击 XSS常发生于论坛评论等
1.排除 Spring-boot-starter 默认的日志配置 将原本的 spring-boot-starter 改为 org.springframework.boot
springboot:解决跨域问题 一、跨域简介 URL的组成: // 协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址 http://www.baidu.com:8080/ 只要协
一、自定义Starter 的思路: 创建一个Maven工程,创建三个模块 一个模块为demo-app,一个模块为demo-module,一个模块为demo-module-springboot-star
1.pom.xml 4.0.0 org.springframework.boot spring-boot-starter-parent
我是一名优秀的程序员,十分优秀!