Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CacheManager abstraction not working well with caches defined as beans [SPR-8081] #12736

Closed
spring-issuemaster opened this issue Mar 23, 2011 · 9 comments

Comments

@spring-issuemaster
Copy link
Collaborator

@spring-issuemaster spring-issuemaster commented Mar 23, 2011

Bozhidar Bozhanov opened SPR-8081 and commented

I have ehcache caches defined as spring beans:

<bean id="fooCache" class="..EhCacheFactoryBean">...</bean>

To make that work, I have the two CacheManagers - the ehcache one, and the new spring one that is part of the cache abstraction:

<bean id="ehCacheManager" class="net.sf.ehcache.CacheManager" />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" />

However, there's a tricky moment - if spring instantiates the EhCacheCacheManager before the caches, then startup fails, because the cacheManager's loadCache() method, that is invoked in afterPropertiesSet(), tries to obtain the caches from the ehcache CacheManager, but they might not be registered with it yet (they get registered whenever they are instantiated as spring beans).

A workarounds I got to use is to set the EhCacheCacheManager depends-on attribute to include all caches - but that's not particularly good - it is likely that someone will forget to add a new cache to the depends-on list, and then he will have hard time finding why his cache is not used.

Btw, the bahaviour is non-deterministic - it works on my local machine, and doesn't work on the server. Perhaps different loading orders.

One solution that comes to my mind is to make the list of caches within the EhCacheCacheManager lazy - i.e. not load it on afterPropertiesSet() (synchornized, double-check locking).


Affects: 3.1 M1

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 23, 2011

Bozhidar Bozhanov commented

Blah, can't edit the issue. Two things: the EhCacheCacheManager in my xml of course takes the other CacheManager as a property. And (for me at least) the priority is not 'minor', but rather 'high'.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 23, 2011

Bozhidar Bozhanov commented

And another thing - using the latest snapshot build.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Apr 21, 2011

Costin Leau commented

I'm afraid there's not much the Spring container can do. Clearly there's a relationship between your ehcache caches however the container is not aware of it hence the initialization problem. Making EhCacheCacheManager lazy besides the fact that goes against its role (to do eager initialization and validation of the cache), it only postpones the problem since there are no guarantees that the other cache beans would be initialized by the time the cache is accessed.
In fact, the ECCM implementation uses a fallback approach each time it doesn't find a cache since one might have been added already.
Besides the obvious depends-on, another solution would be to improve the EhCacheFactoryBean declaration to somehow cause the other caches to be initialized (for example by allowing nested declarations of the caches causing them to be automatically initialized).
At the end of the day, without any dependency indication between the beans, there are no guarantees (nor they should be) the container will instantiate beans the right way...

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Oct 7, 2011

Bozhidar Bozhanov commented

Hm, what about a ApplicationListener<ContextRefreshedEvent>? Whenever the context is ready, the listener can "grab" the cache manager and call its initialization method. That way it is guarnateed that all cache beans will be in place.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 26, 2013

drekbour commented

I find this wont-fix a tad annoying. A valid use case is that using Spring 3 method-level @Cacheable and only want to spin up caches for the modules in scope of the current application. Given this, we deleted the fixed ehcache.xml in favour of dynamic cache instantiation via EhCacheFactoryBean. As described above, EhCacheFactoryBean does not work as they are initialised too late.

Eyecatcher: java.lang.IllegalArgumentException: loadCaches must not return an empty Collection

Workaround: define a pointlessly disabled cache which will be present when EhCache initialises.

    <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>

    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" depends-on="dummyCacheBean">
        <property name="cacheManager" ref="ehcacheManager"/>
    </bean>

    <bean name="dummyCacheBean" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <!-- Workaround for https://jira.springsource.org/browse/SPR-8081 CacheManager abstraction not working well with caches defined as beans -->
        <property name="cacheName" value="dummyCache"/>
        <property name="disabled" value="true"/>
        <property name="cacheManager" ref="ehcacheManager"/>
        <property name="eternal" value="false"/>
        <property name="overflowToDisk" value="false"/>
        <property name="timeToIdle" value="0"/>
        <property name="timeToLive" value="604800"/>
        <property name="memoryStoreEvictionPolicy" value="LRU"/>
        <property name="statisticsEnabled" value="false"/>
        <property name="maxElementsInMemory" value="1"/>
    </bean>
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented May 27, 2014

Owen Berry commented

I agree that the won't-fix is a little frustrating, for the same reasons stated previously. I would like to be able to manage my whole ehcache configuration through Spring and properties files, but I have to add a dummy cache in ehcache.xml to get that to work. While experimenting, I subclassed org.springframework.cache.ehcache.EhCacheCacheManager and overrode afterProperties set in the AbstractCacheManager parent class, and with a 1 line change had a working implementation with no dummy cache.

From:

Assert.notEmpty(caches, "loadCaches must not return an empty Collection");

To:

Assert.notNull(caches, "loadCaches must not return a null Collection");

I'm wary of how maintainable this copy-and-paste override is (and the dummy cache really is not that bad), so I'm not going to keep it, but I think it shows how potentially simple the "fix" is. Maybe there's something else I'm not aware of, but it would be nice to know.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 3, 2015

Stéphane Nicoll commented

Have you thought of using SimpleCacheManager instead? If you're managing the Cache instance yourself, you don't need to use EhCacheCacheManager at all.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 4, 2015

Bozhidar Bozhanov commented

I don't remember well, but I think I needed them to be EhCache, in order to use EhCache distributed capabilities

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 5, 2015

Stéphane Nicoll commented

I think you misunderstand what SimpleCachManager does. It manages a set of Cache instances. Any Cache instance.

So if you want to define your EhCacheCache (using ehcache behind the scenes) you're free to do so. And since you need a CacheManager, you can just use SimpleCacheManager and reference those caches. It will work just fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.