@Cacheable и инициализация во время запуска - PullRequest
0 голосов
/ 15 декабря 2018

Я хотел бы инициализировать все записи в кеше при запуске моего весеннего загрузочного приложения (загрузка материала из БД).В идеале это делается до того, как приложение уже готово.Поэтому я реализовал всю загрузку в @PostConstruct.Я заметил, что кеш еще не настроен в @PostContruct, и я следовал некоторым советам, чтобы сделать такие инициализации в ApplicationReadyEvent.Однако это все еще не работает должным образом:

Несмотря на то, что я уже вызываю метод @Cacheable в ApplicationReadyEvent, второй вызов повторно вводит метод вместо использования кэша.

My Service:

@Service
public class MyService implements ApplicationListener<ApplicationReadyEvent {

  @Cacheable("entry")
  public List<String> getEntry() {
    System.out.println("getEntry called!");
    return Arrays.asList("aaa", "bbb");
  }

  @Override
  public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
    System.out.println("*** onApplicationEvent");
    getEntry();
  }
}

My Caffeine CacheManager Config:

@Configuration
@EnableCaching
public class CachingConfig {

  @Bean
  public CacheManager cacheManager() {
    List<CaffeineCache> caffeineCaches = chacheList(Arrays.asList(
        "entry"
    ));

    SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
    simpleCacheManager.setCaches(caffeineCaches);
    System.out.println("*** @Bean CacheManager");
    return simpleCacheManager;
  }

  private List<CaffeineCache> chacheList(List<String> cacheNames) {
    return cacheNames.stream().map(s -> new CaffeineCache(s, Caffeine.newBuilder().build()))
        .collect(Collectors.toList());
  }

}

Простая конечная точка REST, использующая сервис:

@RestController
public class MyController {

  @Autowired
  MyService myService;

  @GetMapping("/test")
  public void test()
  {
    System.out.println("*** GET /test");
    myService.getEntry();
  }
}

Если я запускаю приложение ивыполнить два GET /test, я получаю следующий вывод:

INFO 20120  --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 907 ms
*** @Bean CacheManager
INFO 20120  --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
INFO 20120  --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
INFO 20120  --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.639 seconds (JVM running for 2.473)
*** onApplicationEvent
*** getEntry called!
INFO 20120  --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
INFO 20120  --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
INFO 20120  --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 4 ms
*** GET /test
*** getEntry called!
*** GET /test

Так почему второй вызов MyService.getEntry (т.е. первый вызов после «Startup») вводит код снова?

В конце мне нужно решение, которое выполняет первую загрузку до того, как приложение завершит загрузку - т.е. я попытаюсь ContextRefreshedEvent или снова @PostConstruct@Autowire CacheManager, чтобы настроить его перед выполнением @PostConstruct),Но первым шагом было бы заставить этот пример вести себя как ожидалось.

1 Ответ

0 голосов
/ 15 декабря 2018

Хорошо, глупая ошибка: в моем сервисе вызов getEntry() должен выполняться через прокси-объект, а не напрямую:

@Service
public class MyService implements ApplicationListener<ApplicationReadyEvent {

  @Autowired
  MyService self;

  @Cacheable("entry")
  public List<String> getEntry() {
    System.out.println("getEntry called!");
    return Arrays.asList("aaa", "bbb");
  }

  @Override
  public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
    System.out.println("*** onApplicationEvent");
    self.getEntry();
  }
}
...