Spring #Cacheable is breaking #RequestMapping - spring

I have upgraded my application to Spring 3.1 and all the jars have been adequately updated. But when I try to use #Cacheable for a method in one of my controllers, URL mapping for all the methods of that controller breaks. On checking the log files I found that the URL mapping for all the methods of that controller were never detected. I am pretty sure that my cache configurations are fine.
Can anyone give me some clue as what I might be doing wrong.
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<defaultCache
eternal="false"
maxElementsInMemory="2"
overflowToDisk="false"
diskPersistent="false"
timeToLiveSeconds="300"
memoryStoreEvictionPolicy="LRU" />
<cache name="Backlog"
eternal="false"
maxElementsInMemory="2"
overflowToDisk="false"
diskPersistent="false"
timeToLiveSeconds="300"
memoryStoreEvictionPolicy="LRU" />
</ehcache>
configuration:
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager">
<ref bean="ehcache" />
</property>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="/WEB-INF/spring-configuration/ehcache.xml" />
code snippet:
#RequestMapping("/*/backlog")
#Cacheable(value = "Backlog")
public ModelAndView getBackLog(){
//sth here
}
Thanks for the help.

Whilst #mana has explained how to fix this, this is why adding #Cacheable breaks your code. A recent blog post explains this in more detail and is well worth a read.
By default Spring creates JDK dynamic proxies to achieve the caching behaviour, this requires that the class being proxied implements an interface which declares all the methods you wish to expose on your #Cacheable class. It is worth noting that you don't have to implement any interfaces if you configure Spring to use CGLIB based proxies.
You haven't supplied any specific errors but often you get a method not found exception in this scenario. Spring tries to invoke the getBackLog() method on the proxy and there isn't one.

You shouldn't cache the controller method itself but the resource hungry method that will be called to create the backlog. Have a look at this similar question. What #Cachable does is to create a key value map for your function parameters and the related return value. In your case this would be a ModelAndView object.
If you really need server side web page caching maybe use this Apache Cache Module.

you should be injecting your service class into the controller and caching the methods on the service class

Related

Spiring #Cacheable is not working

I have added <cache:annotation-driven /> in my Spring applicationcontext.xml.
Also added
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set><bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
name="executeCachedMethod" />
</set></property></bean>
Added #Cacheable before a method that make a database call using JdbcTemplate.
Whenever I makes call to that method with same parameter method is always executed and goes to database. It supposed get me a cached result. Any help?
Actually I was using it in a spring bean during startup. By Spring implementation #cacheable only work after cacheInterceptor.afterSingletonsInstantiated() call is made. In my case I was using before that.
So just for testing
#Autowired
CacheInterceptor cacheInterceptor;
Just to test the cache while load if we purposefully (not recommended) make this call cacheInterceptor.afterSingletonsInstantiated(), cache will work.

Ehcache and spring bootstrapcacheloader not working

I am trying to setup a bootstrapcacheloader which will query the database and populate the cache. Here I am using ehcache integrated with spring. But the problem is that I am not able to get the dependencies wired into my cacheloader implementation. The #Autowired,#Resource,#Configurable none of them seem to work. Quite obviously the cacheloader instantiation is not done by Spring container , but is there a way I can inject a spring created cacheloader instance into the cachemanager and bootstrap it?
My implementation details below.
ehcache.xml
<cache name="MyCache"
maxElementsInMemory="100000"
eternal="false"
overflowToDisk="false"
timeToLiveSeconds="500">
<!-- <pinning store="localMemory"/> -->
<bootstrapCacheLoaderFactory class="net.tristargroup.claims.helper.ClaimsCacheLoaderFactory" properties="bootstrapAsynchronously=true"/>
<cacheEventListenerFactory class="net.tristargroup.claims.helper.TristarCacheEventListenerFactory" listenFor="all"/>
</cache>
Spring Context xml
<cache:annotation-driven/>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager"><ref local="ehcache"/></property>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" depends-on="cacheLoader">
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>
Cache loader class
#Configurable
public class ClaimsCacheLoaderFactory extends BootstrapCacheLoaderFactory{
#Resource
CacheManager cacheManager;
.
.
.
#Override
public BootstrapCacheLoader createBootstrapCacheLoader(Properties arg0) {
System.out.println("Create cache loader method . Cache manager is ->"+cacheManager);
BootstrapCacheLoader cacheLoader = new ClaimsCacheLoader();
return cacheLoader;
}
The cacheManager instance is always null here even if I specify it as an Autowired attribute.
The problem is present even in the cache event listeners.
Someone please help me on this.
If the cacheManager is null, Tthat means you haven't made the bean available to your package. Add a #ComponentScan("yourpackage") in the same place you defined your bean and add #Component where you want to use your cacheManager.
This is old, but i hope it helps someone else.

Spring 3.1 #Cacheable with ehcache doesn't work

My #Cacheable with Spring and ehcache doesn't work, no datas are put on the cache.
When the application calls the cacheable method getFolProfile, the database is always call rather than the cache.
Can you, please, say me what is wrong in my code.
My root-context.xml:
<cache:annotation-driven proxy-target-class="true"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:/cache/ehcache.xml" />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehcache"/>
My Service :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
#Service
public class FolManager {
#Autowired
FolDao folDao;
#Cacheable(value = "oneCache", key = "#email")
public FolProfileForm getFolProfile(String email) {
return folDao.retrieveByLogin(email);
}
}
My ehcache.xml:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<diskStore path="c:/tmp" />
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120"
timeToLiveSeconds="120" overflowToDisk="true" diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />
<cache name="oneCache" maxElementsInMemory="100000" maxElementsOnDisk="10000000" eternal="true" diskPersistent="true"
overflowToDisk="true" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="LFU" />
</ehcache>
Thanks for your help
Michel
It looks like you're defining caching in the service layer. At http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html, it is specifically noted as follows:
Note
<cache:annotation-driven/> only looks for #Cacheable/#CacheEvict on
beans in the same application context it is defined in. This means
that, if you put <cache:annotation-driven/> in a WebApplicationContext
for a DispatcherServlet, it only checks for #Cacheable/#CacheEvict
beans in your controllers, and not your services. See Section 16.2,
“The DispatcherServlet” for more information.
Add this
<cache:annotation-driven cache-manager="cacheManager" />
You have to tell Spring where cache-manager is.
When proxy-target-class attribute is set to true, class-based proxies are created. CGLIB will be used to create the proxy for a given target object. Make sur that you have CGLIB in your dependencies.
If you have the choice, prefer JDK dynamic proxies by setting proxy-target-class attribute to false and by implementing at least one interface on your class.
Please check your ehCache logs for exceptions like the following:
java.io.NotSerializableException: com.googlecode.ehcache.annotations.RefreshableCacheEntry
You use disk persistent cache (diskPersistent=true), so you have to check that your FolProfileForm object is Serializable.
From the ehCache documentation:
Only data that is Serializable can be placed in the DiskStore. Writes to and from the disk use ObjectInputStream and the Java serialization mechanism. Any non-serializable data overflowing to the disk store is removed and a NotSerializableException is thrown.
It could be the case that your data aren't placed to your cache (filesystem), so it tries to get it from the method invocation again and again.
You can use memory store cache where you can save even not serializable data.

Spring cache vs. cachemanger

The following sample from the Spring manual confuses the heck out of me.
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager"
p:cache-manager-ref="ehcache"/>
<!-- Ehcache library setup -->
<bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:config-location="ehcache.xml"/>
The naming convention mandates that EhCacheManagerFactoryBean produces a cache manager, more precisely it's a net.sf.ehcache.CacheManager instance. Yet, the bean is called ehcache not ehcachemanager. The actual cacheManager, however, references this bean.
In prose you could say that one is the Ehcache cache manager while the other is the Spring cache manager (which is backed by the former).
It gets worse if you use the EhCacheFactoryBean:
<bean
id="myCache"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="ehcache" />
</property>
There's a property called cacheManager which references a bean called ehcache.
Did I misunderstand anything or is it really that confusing? Bad design or just bad naming in the example?
Spring framework recently introduced caching abstraction with org.springframework.cache.CacheManager central interface. This interface has few built-in implementations, including:
ConcurrentMapCacheManager
EhCacheCacheManager
NoOpCacheManager
SimpleCacheManager
This design allows you to switch caching library without touching application code. As you can see one of these built-in implementations is backed by EhCache. However notice that EhCacheCacheManager is just a bridge between Spring caching abstraction and EhCache library. Thus it needs existing net.sf.ehcache.CacheManager. You can either create an instance of this cache manager yourself or take advantage of existing factory bean, namely EhCacheManagerFactoryBean.
I understand it's confusing because of overlapping names, but it should be clear from the above which classes come from which library and why are they used.

global-method-security works on some beans but not others using spring security

i've a service ,
<bean id="myservicie" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="aService"/>
<property name="serviceInterface" value="com.statestr.oms.fx.ws.service.IService"/>
</bean>
inside this aservice,
#Secured ({"ROLE_USER"})
private void mythod(),
but it's not working,
however, if i move this method to another bean, say, mybean,the security annotation will work,
i've enabled both in the configuration like below, can anyone help? thx.
<global-method-security secured-annotations="enabled" access-decision-manager-ref="accessDecisionManager">
<protect-pointcut expression="execution(* *..com.statestr.oms.service.impl.*Mybean*.*(..))" access="ROLE_USER"/>
<protect-pointcut expression="execution(* *..com.statestr.oms.service.impl.*Service*.*(..))" access="ROLE_USER"/>
</global-method-security>
I guess it is because your application uses Spring Proxy AOP. And this AOP Style has no influence if the method is invoked directly (from the same bean). And I think that is what you do, because the method you mentioned is a private method.
So what you can do is:
use AspectJ (I strongly recommend it),
put the #Secured annotation to a method that is invoked from outside of the bean
Anyway your configuration looks a bit strange - why do you use #Secured AND <protect-pointcut... for the same Class? One of them should be enough.

Resources