ScheduledExecutorService внутри Spring Bean, не работает после пары выполнений - PullRequest
0 голосов
/ 19 февраля 2020

Я пытаюсь запланировать задачу внутри 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;
}

1 Ответ

0 голосов
/ 19 февраля 2020

Жизненный цикл serviceLoader выглядит странно - он инициализируется прямо во время метода или сервиса, затем планирует некоторую работу, а затем сервис возвращается. Что происходит со ссылкой на этот пул? когда остановка может быть вызвана?

Кроме того, первая итерация запускается немедленно, и это происходит, когда контекст приложения еще не готов, это может привести к непредсказуемым результатам в зависимости от фактического кода, который выполняется во время итерации.

Я не могу точно сказать, что происходит на основе этого фрагмента кода, но вот несколько возможных решений:

  1. Использовать аннотацию @Scheduled, запуск запланированных задач - это функция встроенной пружины , Есть много учебных пособий, вот один из них

  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);
   }
}

При таком подходе вы можете быть уверены, что служба начнет обновляться, когда контекст приложения будет готов.

Жизненный цикл службы исполнителя также хорошо определен, Spring управляет им как обычным одноэлементным компонентом, поэтому он не будет редактироваться G C, пока контекст приложения работает.

Наличие метода destroy гарантирует постепенное завершение работы (снова , весна назовет это для вас).

...