Вот как мы решили эту проблему.
/**
* Listener of Spring's lifecycle to revive Scheduler beans, when spring's
* scope is refreshed.
* <p>
* Spring is able to restart beans, when we change their properties. Such a
* beans marked with RefreshScope annotation. To make it work, spring creates
* <b>lazy</b> proxies and push them instead of real object. The issue with
* scope refresh is that right after refresh in order for such a lazy proxy
* to be actually instantiated again someone has to call for any method of it.
* <p>
* It creates a tricky case with Schedulers, because there is no bean, which
* directly call anything on any Scheduler. Scheduler lifecycle is to start
* few threads upon instantiation and schedule tasks. No other bean needs
* anything from them.
* <p>
* To overcome this, we had to create artificial method on Schedulers and call
* them, when there is a scope refresh event. This actually instantiates.
*/
@RequiredArgsConstructor
public class RefreshScopeListener implements ApplicationListener<RefreshScopeRefreshedEvent> {
private final List<RefreshScheduler> refreshSchedulers;
@Override
public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
refreshSchedulers.forEach(RefreshScheduler::materializeAfterRefresh);
}
}
Итак, мы определили интерфейс, который ничего особенного не делает, но позволяет нам вызывать обновленную работу.
public interface RefreshScheduler {
/**
* Used after refresh context for scheduler bean initialization
*/
default void materializeAfterRefresh() {
}
}
А вот фактическое задание, параметр которого from.properties
может быть обновлен.
public class AJob implements RefreshScheduler {
@Scheduled(cron = "${from.properties}")
public void aTask() {
// do something useful
}
}
ОБНОВЛЕНО: Конечно, компонент AJob должен быть помечен @RefreshScope в @ Configuration
@Configuration
@EnableScheduling
public class SchedulingConfiguration {
@Bean
@RefreshScope
public AJob aJob() {
return new AJob();
}
}