SpringBoot动态配置定时任务(支持毫秒级)

项目中使用携程Apollo进行配置管理,需要实现动态配置Job的执行间隔。
使用动态修改cron表达式的方式可以实现,但是cron表达式不支持毫秒,所以采用以下方式进行配置。
每次配置改动时,将旧的定时任务停掉,重新启动一个定时任务。

/**
 * shang
 * 2020-02-11 15:41
 */
@Slf4j
@Component
public class OrderJob {

    // 订单宽表定时同步间隔,单位ms
    @Value("${order.schedule.interval:1000}")
    private Long orderScheduleInterVal;

    private static final String lock = "lock";

    private final Set<String> orderIdSet = Sets.newHashSet();

    @Resource
    private OrderManager orderManager;
    @Resource
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    @ApolloConfig
    private Config config;

    private ScheduledFuture<?> future;

    @ApolloConfigChangeListener
    private void configChangeListener(ConfigChangeEvent changeEvent) {
        Set<String> keyNames = config.getPropertyNames();
        for (String key : keyNames) {
            if (StringUtils.equals(key, "order.schedule.interval")) {
                String interVal = config.getProperty(key, "1000");

                if (future != null) {
                    future.cancel(true);
                    log.info("cancel order task");
                }

                PeriodicTrigger periodicTrigger = new PeriodicTrigger(Long.valueOf(interVal), TimeUnit.MILLISECONDS);
                periodicTrigger.setFixedRate(true);
                periodicTrigger.setInitialDelay(1000);

                future = threadPoolTaskScheduler.schedule(this::readOrderIdSet, periodicTrigger);

                log.info("start order task");
            }
            log.info("{}:{}", key, config.getProperty(key, null));
        }
    }

    /**
     * 写入缓冲set
     *
     * @param orderIds
     */
    public void writeOrderIdSet(Set<String> orderIds) {
        if (CollectionUtils.isEmpty(orderIds)) {
            return;
        }
        synchronized (lock) {
            orderIdSet.addAll(orderIds);
        }
    }

    /**
     * 定时任务从缓冲set里取
     */
     // 这样配置无法动态修改执行间隔
//    @Scheduled(fixedRate = 2000)
    public void readOrderIdSet() {
        if (CollectionUtils.isEmpty(orderIdSet)) {
            log.info("缓冲set为空,定时任务不执行");
            return;
        }
        synchronized (lock) {
            log.info("发送订单宽表消息:{}条", CollectionUtils.size(orderIdSet));
            // 缓冲区的orderId发kafka消息
            orderManager.sendMessage(orderIdSet);
            // 清空缓冲区
            orderIdSet.clear();
        }
    }

    @PostConstruct
    public void postConstruct() {
        PeriodicTrigger periodicTrigger = new PeriodicTrigger(orderScheduleInterVal, TimeUnit.MILLISECONDS);
        periodicTrigger.setFixedRate(true);
        periodicTrigger.setInitialDelay(1000);

        future = threadPoolTaskScheduler.schedule(this::readOrderIdSet, periodicTrigger);
    }
}

你可能感兴趣的:(Java&Javaweb)