我正在尝试在Spring @Bean中安排任务,这将更新从Bean返回的实例的属性。
我能够运行此代码,并且执行程序可以正常运行几次,但是此后,它突然停止加载。
这里到底是什么问题?有没有更好的方法来解决这个问题?
@Bean(name="service")
public Service getService(){
Service service = new Service();
ScheduledExecutorService serviceLoader = Executors.newScheduledThreadPool(1);
serviceLoader.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
service.loadAllLiveEvents();
}
}, 0, 1, TimeUnit.HOURS);
return service;
}
serviceLoader的生命周期看起来很奇怪-它在方法或服务过程中被正确初始化,然后安排一些工作,然后返回服务。对该池的引用发生了什么?什么时候可以关机?
此外,第一次迭代会立即运行,并且在应用程序上下文尚未准备就绪时会发生这种情况,这可能导致不可预测的结果,具体取决于迭代期间运行的实际代码。
我不能确定基于此代码段会发生什么,但是这里有一些可能的解决方案:
使用@Scheduled
批注,运行计划的任务是bulit-in spring功能。有很多教程,这里是one of them
如果绝对必须使用线程池,我建议使用以下配置:
@Configuration
public class MyConfiguration {
@Bean
public Service service() {
return new Service();
}
@Bean(destroyMethod="shutdownNow") // or shutdown - now spring will close the pool when the app context gets closed
@Qualifier("serviceLoaderPool")
public ScheduledExecutorService serviceLoader() {
return Executors.newScheduledThreadPool(1);
}
@EventListener
public void onAppContextStarted(ApplicationReadyEvent evt) {
ScheduledExecutorService loader =
(ScheduledExecutorService)evt.getApplicationContext().getBean("serviceLoaderPool");
Service service = evt.getApplicationContext.getBean(Service.class);
loader.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
service.loadAllLiveEvents();
}
}, 0, 1, TimeUnit.HOURS);
}
}
使用这种方法,您可以确定当应用程序上下文准备就绪时,服务将开始刷新。
executor服务的生命周期也得到了很好的定义,spring将其作为常规的singleton bean管理,因此只要应用程序上下文处于运行状态,就不会进行GC处理。
destroy方法的存在保证了正常关机(再次,spring会为您调用它)。