配置中心实现定时任务动态更新

一、@RefreshScope导致定时任务失效

当定时任务使用@RefreshScope想达到配置动态刷新时,你会发现定定时任务失效了,失效的原因和@RefreshScope的原理有关:配置的刷新会导致原来的对象被清除,需要重新使用对象才能出发生成新对象,但因为对象没了,又没法重新使用对象(死循环),所以导致了定时任务的失效。(这样描述是否恰当)

二、定时任务的动态刷新实现方式

1. @RefreshScope+RefreshScopeRefreshedEvent

RefreshScopeRefreshedEvent刷新作用域刷新事件
1.1 简单写法

@RefreshScope
@Component
public class TestTask implements ApplicationListener<RefreshScopeRefreshedEvent> {

    @Value("${test.num}")
    private String num;

    @Scheduled(cron = "* * * * * *")
    // @Scheduled(cron = "${test.cron}")// 可实现定时任务执行时间的动态刷新
    public void schedule() {
        System.out.println("============ 定时任务执行了,num["+num+"] ============");
    }

    @Override
    public void onApplicationEvent(RefreshScopeRefreshedEvent event) {

    }
}

1.2复杂写法

public interface RefreshScheduler {
    default void materializeAfterRefresh() {
    }
}
@Component
public class RefreshScopeListener implements ApplicationListener<RefreshScopeRefreshedEvent> {
    private final List<RefreshScheduler> refreshSchedulers;

    public RefreshScopeListener(List<RefreshScheduler> refreshSchedulers) {
        this.refreshSchedulers = refreshSchedulers;
    }

    @Override
    public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
        refreshSchedulers.forEach(RefreshScheduler::materializeAfterRefresh);
    }
}
@Component
@RefreshScope
public class TestTask implements RefreshScheduler{

    @Value("${test.num}")
    private String num;

    @Scheduled(cron = "${test.cron}")
    public void schedule() {
        System.out.println("============ 定时任务执行了,当前时间["+ DateUtil.formatDateTime(new Date()) +"] ==== num["+num+"] ============");
    }
}

2. Environment

@Component
public class TestTask {

    @Autowired
    private Environment env;

    @Scheduled(cron = "* * * * * *")
    public void schedule() {
        String num =  env.getProperty("test.num");
        System.out.println("============ 定时任务执行了,num["+num+"] ============");
    }
}

3. @RefreshScope+@Value

@RefreshScope
@Component
public class TestConfig {
    @Value("${test.num}")
    private String url;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}
@Component
public class TestTask {

    @Autowired
    private TestConfig testConfig;

    @Scheduled(cron = "* * * * * *")
    public void schedule() {
        System.out.println("============ 定时任务执行了,num["+testConfig.getUrl()+"] ============");
    }
}

4. @ConfigurationProperties

@Component
@ConfigurationProperties(prefix = "test")
public class TestConfig {
    private String url;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}
@Component
public class TestTask {

    @Autowired
    private TestConfig testConfig;

    @Scheduled(cron = "* * * * * *")
    public void schedule() {
        System.out.println("============ 定时任务执行了,num["+testConfig.getUrl()+"] ============");
    }
}

5. EnvironmentChangeEvent

EnvironmentChangeEvent环境变化事件

public interface RefreshScheduler {
    default void materializeAfterRefresh() {
    }
}
@Component
@RefreshScope
public class TestTask implements ApplicationListener<EnvironmentChangeEvent>,RefreshScheduler {

    @Value("${test.num}")
    private String num;

    @Scheduled(cron = "${test.cron}")
    public void schedule() {
        System.out.println("============ 定时任务执行了,当前时间["+ DateUtil.formatDateTime(new Date()) +"] ==== num["+num+"] ============");
    }

    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        this.materializeAfterRefresh();
    }
}
上一篇:常用的sql语言基础(1)


下一篇:Cron表达式详解和表达式的验证