I'm using spring-cache to improve database queries, which works fine as follows:
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("books");
}
@Cacheable("books")
public Book getByIsbn(String isbn) {
return dao.findByIsbn(isbn);
}
But now I want to prepopulate the full book-cache on startup. Which means I want to call dao.findAll()
and put all values into the cache. This routine shall than only be scheduled periodically.
But how can I explicit populate a cache when using @Cacheable
?
For caching at the application start-up, we can use @PostContruct in any of the Service class. This will cache the entire table data.
We can enable caching in the Spring Boot application by using the annotation @EnableCaching. It is defined in org. springframework. cache.
Spring Cache uses the parameters of the method as key and the return value as a value in the cache. When the method is called the first time, Spring will check if the value with the given key is in the cache. It will not be the case, and the method itself will be executed.
Just use the cache as before, add a scheduler to update cache, code snippet is below.
@Service
public class CacheScheduler {
@Autowired
BookDao bookDao;
@Autowired
CacheManager cacheManager;
@PostConstruct
public void init() {
update();
scheduleUpdateAsync();
}
public void update() {
for (Book book : bookDao.findAll()) {
cacheManager.getCache("books").put(book.getIsbn(), book);
}
}
}
Make sure your KeyGenerator
will return the object for one parameter (as default). Or else, expose the putToCache
method in BookService
to avoid using cacheManager directly.
@CachePut(value = "books", key = "#book.isbn")
public Book putToCache(Book book) {
return book;
}
I have encountered the following problem when using @PostConstruct: - even though the method I wanted to be cached was called, after calling it from swagger, it still didn't use the cached value. Only after called it once more.
That was because @PostConstruct is too early for caching something. (At least I think that was the issue)
Now I'm using it more late in the startup process and it works without problems:
@Component
public class CacheInit implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
//call service method
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With