Reputation: 3014
I'm using Spring Boot and EhCache to develop a calendar application. I'm trying to cache the following method:
@Override
@Cacheable(value = "concerts")
public List<Event> getEvents(String eventsForUser, Date startDate, Date endDate) throws Exception {
return fetchEventsFromTheServer(eventsForUser, startDate, endDate);
}
The challenge is I would like to manipulate returned cached result. For example, check if there is cache for given dates but for a different user and then return it instead (as long as both users meet certain criteria).
So, before returning a result I would like:
I think the best would be to create a custom Cache Manager which will do all the manipulation with cached concert and use default auto configured cache for all other methods, but I can't get my custom manager to work and didn't find any good example on how to implement a custom CacheManager.
Here is what I have:
Application.java:
@SpringBootApplication
@ComponentScan
@EnableCaching
@EnableScheduling
public class SpringBootWebApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SpringBootWebApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<SpringBootWebApplication> applicationClass = SpringBootWebApplication.class;
@Bean(name = "eventsCacheManager")
public EventsCacheManager eventsCacheManager() {
return new EventsCacheManager();
}
@Primary
@Bean(name = "cacheManager")
public CacheManager cacheManager() {
return new EhCacheCacheManager(ehCacheCacheManager().getObject());
}
@Bean
public EhCacheManagerFactoryBean ehCacheCacheManager() {
EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
cmfb.setShared(true);
return cmfb;
}
}
EventsCacheManager.java
@Component
public class EventsCacheManager implements CacheManager {
@Override
public Cache getCache(String s) {
return null;
}
@Override
public Collection<String> getCacheNames() {
return null;
}
}
EventsCacheManager.java - how to implement it?
@Component
public class EventsCacheManager implements CacheManager {
@Override
public Cache getCache(String s) {
return null;
}
@Override
public Collection<String> getCacheNames() {
return null;
}
}
I would really appreciate if someone can give me an example on how I should implement my custom CacheManager
Upvotes: 7
Views: 29848
Reputation: 14500
From my understanding of your question, I believe you are looking at the problem the wrong way.
Instead of having to browse cache contents to extract derived information, you should insert into the cache the derived information at the time of loading the main data.
For example, when loading month based information, break it immediately into day based information and put that in a cache as well.
This description also should clearly indicate that what you want to do is beyond the capabilities of the Spring caching abstraction, as you need custom cache loading logic.
So I would not recommend hacking a CacheManager
to hide that logic but instead do it from the data loading logic.
Upvotes: 1
Reputation: 7981
I did not spend much time thinking about your requirements/use case, but I do think a custom CacheManager
would work in this situation, assuming the "custom" CacheManager
logic is correct.
So, by default, Spring looks for a bean in the context with the name "cacheManager" and uses it for all cached operations. In your configuration, you clearly have 2 "CacheManagers" defined...
@Bean(name = "eventsCacheManager")
public EventsCacheManager eventsCacheManager() {
return new EventsCacheManager();
}
@Primary
@Bean(name = "cacheManager")
public CacheManager cacheManager() {
return new EhCacheCacheManager(ehCacheCacheManager().getObject());
}
I.e. the "eventsCacheManager" (custom) and "cacheManager" (standard). Indeed, you even marked the "cacheManager" as primary (using the @Primary
annotation). Of course, had you not done that, Spring would certainly have complained since more than 1 bean of a given type (i.e. CacheManager
) was found in the context when performing auto-wiring (which defaults to auto-wire by type).
So, in order to call out which cache management strategy (i.e. CacheManager
) to use at runtime with a particular service call, you also need to tell Spring which CacheManager
(aka strategy) to use, like so...
@Override
@Cacheable(value = "concerts", cacheManager="eventsCacheManager")
public List<Event> getEvents(String eventsForUser, Date startDate, Date endDate) throws Exception {
return fetchEventsFromTheServer(eventsForUser, startDate, endDate);
}
I.e. using the cacheManager
attribute in the @Cacheable
annotation to indicate which caching strategy to use.
See Spring's Reference Doc on Custom cache resolution for more details.
Hope this helps get you going.
Upvotes: 2