I have been experimenting with the Spring 3.1 Cache abstraction features and got them to work but we have some user specific data, which I would like to cache using session scoped beans.
My cache-config.xml (imported into applicationContext.xml):
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!-- Activates various annotations to be detected in bean classes: Spring's @Required and @Autowired, as well as JSR 250's @Resource. -->
<context:annotation-config />
<context:component-scan base-package="my.package.whatevs" />
<!-- <cache:annotation-driven cache-manager="cacheManager" proxy-target-class="false" mode="proxy" /> -->
<cache:annotation-driven cache-manager="cacheManager" />
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean id="defaultCache" class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="defaultCache" />
<bean id="accountSettingsCache" class="org.springframework.cache.concurrent.ConcurrentMapCache" scope="session">
<aop:scoped-proxy proxy-target-class="false" />
<constructor-arg>
<value>accountSettingsCache</value>
</constructor-arg>
</bean>
</set>
</property>
</bean>
</beans>
I do have RequestContextListener and ContextLoaderListener in web.xml. But everytime I try to autowire my cache object I get the following message:
Error creating bean with name 'scopedTarget.accountSettingsCache': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
I do have spring-aop-3.1.1.RELEASE.jar in my classpath. I tried writing a wrapper for ConcurrentMapCache that has a default constructor with no parameters so I can set proxy-target-class to true. I tried declaring them outside the cacheManager and adding it to the list of caches later.
But everytime I try to set it as a property or autowire it in a class (@Service or @Controller) it gives me the same error. It's as if the aop:scoped-proxy is totally ignored.
I also tried ehCache and it worked but it doesn't seem to support session scoped caching. I could also try to write a custom keyGenerator and use the sessionId as part of the key in the cache, but then I would have to manage it's lifecycle, it could have an expiration time but I want finer control over the data in the cache. Any ideas ?
Thanks.
SimpleCacheManager
per session, then make that bean session-scoped. Otherwise just have a session-scoped bean calledshoppingCart
or whatever you need, and wire that in to your controller. But I can't see why you need a caching layer for just session-scoped beans. – Paul GrimecacheManager
is created, there is no session. Therefore when Spring tries to create a session-scoped bean it fails, as there is no session at that point in time (application startup). If you want a cache per session, then movescope="session"
fromaccountSettingsCache
tocacheManager
. Then when an MVC controller asks for acacheManager
, it will get one specific to the current session. I'm still not sure that a cache is the right thing for you to use, but I don't know your use-case. – Paul Grime