springcloud的可配置化定时任务的设计及实现

一、开启定时器,需要在启动类和定时任务类上添加注解
–>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可以做到。


/**
 * 如果大时间段改为小时间段或者更改IP,需要重启应用才能立即生效。比如:1天改为1小时
 */
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<String> 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;

    /** timer_config表中的timer_code字段 */
    protected abstract String getTimerCode();

    private boolean isRun(String configIps, Set<String> 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 CommonResult<T> implements 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 <T> CommonResult<T> success() {
        return new CommonResult<T>(RespStatus.SUCCESS, null, null);
    }

    public static <T> CommonResult<T> successWithMessage(String msg) {
        return new CommonResult<T>(RespStatus.SUCCESS, msg, null);
    }

    public static <T> CommonResult<T> successWithMessage(String msg, Object... objects) {
        return new CommonResult<T>(RespStatus.SUCCESS, String.format(msg, objects), null);
    }

    public static <T> CommonResult<T> successWithData(T data) {
        return new CommonResult<T>(RespStatus.SUCCESS, null, data);
    }

    // 失败
    public static <T> CommonResult<T> fail() {
        return new CommonResult<T>(RespStatus.BUSIENSSERROR, null, null);
    }

    public static <T> CommonResult<T> failWithMessageAndData(String msg, T data) {
        return new CommonResult<T>(RespStatus.BUSIENSSERROR, msg, data);
    }
    
    public static <T> CommonResult<T> failWithMessage(String msg) {
        return new CommonResult<T>(RespStatus.BUSIENSSERROR, msg, null);
    }

    public static <T> CommonResult<T> failWithMessage(String msg, Object... objects) {
        return new CommonResult<T>(RespStatus.BUSIENSSERROR, String.format(msg, objects), null);
    }
    
    public static <T> CommonResult<T> build(int status, String message, T data) {
        return new CommonResult<T>(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;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我了解了您的问题。在Spring Cloud集成Quartz时,需要进行以下数据库配置: 1. 首先,在您的Spring Boot项目中添加Quartz的依赖项。您可以在pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ``` 2. 接下来,在application.properties文件中配置Quartz的数据库属性,例如: ``` spring.quartz.job-store-type=jdbc spring.quartz.jdbc.initialize-schema=always spring.datasource.url=jdbc:mysql://localhost:3306/quartz spring.datasource.username=root spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` 其中,spring.quartz.job-store-type设置为jdbc,表示Quartz将使用数据库存储作业和触发器,spring.quartz.jdbc.initialize-schema设置为always表示每次启动应用程序时都会初始Quartz数据库,spring.datasource.url、spring.datasource.username、spring.datasource.password和spring.datasource.driver-class-name为您的数据库连接属性。 3. 最后,定义您的定时任务,例如: ``` @Configuration public class QuartzConfiguration { @Bean public JobDetail myJobDetail() { return JobBuilder.newJob(MyJob.class) .withIdentity("myJob") .storeDurably() .build(); } @Bean public Trigger myTrigger() { return TriggerBuilder.newTrigger() .forJob(myJobDetail()) .withIdentity("myTrigger") .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) .build(); } } @Component public class MyJob implements Job { @Override public void execute(JobExecutionContext context) { // 任务逻辑 } } ``` 其中,定时任务使用Cron表达式配置,该表达式将在每分钟的第0秒开始,每5秒执行一次任务。 以上就是Spring Cloud集成Quartz数据库配置定时任务的方法。希望能够帮助到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值