Я хотел бы инициализировать все записи в кеше при запуске моего весеннего загрузочного приложения (загрузка материала из БД).В идеале это делается до того, как приложение уже готово.Поэтому я реализовал всю загрузку в @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
),Но первым шагом было бы заставить этот пример вести себя как ожидалось.