一、开启定时器,需要在启动类和定时任务类上添加注解
–>springboot+springcloud的定时任务
二、设计定时任务的数据库,通过数据库动态配置定时任务。
-- auto-generated definition
create table timer_config
(
creation_date datetime not null,
created_by bigint not null,
last_update_date datetime(3) null,
last_updated_by bigint not null,
enabled_flag varchar(1) not null,
timer_config_id bigint auto_increment comment '主键'
primary key,
timer_code varchar(64) not null comment '定时器编码',
timer_name varchar(1024) not null comment '定时器名称',
timer_ip varchar(64) not null comment '定时器可执行IP',
timer_cron varchar(32) not null comment '定时器执行的表达式(0 10 6 * * ?)(* 0/10 * * * ?)',
timer_para varchar(512) null comment '定时器带入参数(JSON字符)',
timer_app varchar(32) null comment '定时器应用模块(应用名)',
log_flag varchar(1) not null comment '是否记录运行日志(打印在日志控制台)',
constraint timer_config_u1
unique (timer_code)
)
comment '定时器配置';
creation_date --> 创建时间
created_by --> 创建人id
last_update_date–> 最后更新时间
last_updated_by --> 最后更新人id
enabled_flag --> 是否有效
三、基于SchedulingConfigurer接口实现配置化的定时任务
@Schedule 注解的方式,缺点是不能动态配置,SchedulingConfigurer可以做到。
public abstract class AbstractTimer implements SchedulingConfigurer {
protected final Logger log = LoggerFactory.getLogger(getClass());
@Autowired
protected TimerConfigService timerConfigService;
@Autowired
protected MonitorSendByMqService monitorSendByMqService;
@Autowired
private CacheService cache;
private TimerConfig getTimerConfig(ContextInfo context, String timerCode) {
String key = CacheKeyUtil.buildKey(TimerConfig.class, timerCode);
try {
return cache.get(key, () -> {
TimerConfig config = timerConfigService.getTimerConfig(timerCode);
if (null == config) {
log.error("找不到定时器配置。timerCode={},sessionId={}", timerCode, context.getSessionId());
}
return config;
});
} catch (Exception e) {
log.error("查询缓存的定时器配置出错。timerCode={},sessionId={}", timerCode, context.getSessionId(), e);
return null;
}
}
@SuppressWarnings("rawtypes")
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ContextInfo context = ContextInfo.buildTimer();//构建上下文
Set netIps = BeeGetLocalIpUtil.get();//获取ip地址 https://blog.csdn.net/shihuahao0353/article/details/121167878
String timerCode = this.getTimerCode();
TimerConfig config = this.getTimerConfig(context, timerCode);
if (null == config) {
return;
}
taskRegistrar.addTriggerTask(() -> {
if (YesOrNo.Y.val.equals(config.getLogFlag())) {
log.info("定时任务执行[开始], timerCode={},sessionId={}", timerCode, context.getSessionId());
}
// 判断定时器是否可以在本机运行
if (!this.isRun(config.getTimerIp(), netIps)) {
log.error("定时任务执行失败,IP不合法, timerCode={},执行ip={},合法ip={},sessionId={}", timerCode, netIps.toString(), config.getTimerIp(), context.getSessionId());
return;
}
long start = System.currentTimeMillis();
// 执行业务逻辑
try {
CommonResult cr = this.process(context, BeeStringUtil.isEmpty(config.getTimerPara()) ? null : JSONObject.parseObject(config.getTimerPara()));
if (cr == null) {
log.error("定时任务执行失败,业务处理未返回处理结果, timerCode={},sessionId={}", timerCode, context.getSessionId());
return;
} else if (!cr.isSuccess()) {
log.error("定时任务执行失败,业务处理未返回错误, timerCode={},msg={},sessionId={}", timerCode, cr.getMessage(), context.getSessionId());
return;
}
} catch (BusinessException e) {
// 业务异常不发通知
log.error("执行定时器任务出错!timerCode={},sessionId={}", timerCode, context.getSessionId(), e);
} catch (Exception e) {
log.error("执行定时器任务异常!timerCode={},sessionId={}", timerCode, context.getSessionId(), e);
// 运行时异常发通知
this.sendMonitorNotice("执行定时器任务异常!timerCode=" + timerCode + ",sessionId=" + context.getSessionId());
} finally {
if (YesOrNo.Y.val.equals(config.getLogFlag())) {
long end = System.currentTimeMillis();
log.info("定时任务执行[结束]。timerCode={},耗时={}毫秒,sessionId={}", timerCode, end - start, context.getSessionId());
}
}
}, triggerContext -> {
// log.info("====获取定时器配置,sessionId={},TimerCode={}", context.getSessionId(), timerCode);
return new CronTrigger(config.getTimerCron()).nextExecutionTime(triggerContext);
});
}
@SuppressWarnings("rawtypes")
protected abstract CommonResult process(ContextInfo context, JSONObject para) throws Exception;
protected abstract String getTimerCode();
private boolean isRun(String configIps, Set netIps) {
for (String configIp : configIps.split(",")) {
for (String netIp : netIps) {
if (configIp.equals(netIp)) {
return true;
}
}
}
return false;
}
private void sendMonitorNotice(String msg) {
try {
SysMonitorBean bean = SysMonitorBean.buildMail("定时器运行异常", msg, null);
monitorSendByMqService.send(bean);
} catch (Exception e) {
log.error("发送错误监控消息异常:" + e.getMessage(), e);
}
}
}
定时任务的实现类继承AbstractTimer抽象类,添加@Component注解,实现抽象方法,就可以实现通过数据库来灵活配置定时器了。
附:CommonResult类
public class CommonResultimplements java.io.Serializable { private static final long serialVersionUID = 2683217789586688528L; private int status; private String message; private T data; public CommonResult() { } public CommonResult(int status, String message, T data) { this.status = status; this.message = message; this.data = data; } // 成功 public static CommonResult success() { return new CommonResult (RespStatus.SUCCESS, null, null); } public static CommonResult successWithMessage(String msg) { return new CommonResult (RespStatus.SUCCESS, msg, null); } public static CommonResult successWithMessage(String msg, Object... objects) { return new CommonResult (RespStatus.SUCCESS, String.format(msg, objects), null); } public static CommonResult successWithData(T data) { return new CommonResult (RespStatus.SUCCESS, null, data); } // 失败 public static CommonResult fail() { return new CommonResult (RespStatus.BUSIENSSERROR, null, null); } public static CommonResult failWithMessageAndData(String msg, T data) { return new CommonResult (RespStatus.BUSIENSSERROR, msg, data); } public static CommonResult failWithMessage(String msg) { return new CommonResult (RespStatus.BUSIENSSERROR, msg, null); } public static CommonResult failWithMessage(String msg, Object... objects) { return new CommonResult (RespStatus.BUSIENSSERROR, String.format(msg, objects), null); } public static CommonResult build(int status, String message, T data) { return new CommonResult (status, message, data); } // public boolean isSuccess() { return RespStatus.SUCCESS == this.getStatus(); } public boolean isFailure() { return !this.isSuccess(); } // public String getMessage() { return message; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } }



