Spring Bean中的ScheduledExecutorService,在两次执行后不起作用

问题描述 投票:0回答:1

我正在尝试在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;
}
java spring multithreading spring-bean scheduledexecutorservice
1个回答
0
投票

serviceLoader的生命周期看起来很奇怪-它在方法或服务过程中被正确初始化,然后安排一些工作,然后返回服务。对该池的引用发生了什么?什么时候可以关机?

此外,第一次迭代会立即运行,并且在应用程序上下文尚未准备就绪时会发生这种情况,这可能导致不可预测的结果,具体取决于迭代期间运行的实际代码。

我不能确定基于此代码段会发生什么,但是这里有一些可能的解决方案:

  1. 使用@Scheduled批注,运行计划的任务是bulit-in spring功能。有很多教程,这里是one of them

  2. 如果绝对必须使用线程池,我建议使用以下配置:

@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会为您调用它)。

© www.soinside.com 2019 - 2024. All rights reserved.