Mike3355
Mike3355

Reputation: 12081

Unable to cache using ehcache version 3.4.0 and spring boot 2.0.2.RELEASE

I have tried to implement caching on Spring boot app several ways and this seems to be the right approach but it just logs that

CacheStatistics,CacheManager=urn.X-ehcache.jsr107-default-config,Cache=studentCache
Registering Ehcache MBean javax.cache:type=CacheStatistics,CacheManager=urn.X-ehcache.jsr107-default-config,Cache=studentCache

I have a event logger but I do not see any output from it:

@Component
public class EventLogger implements CacheEventListener<Object, Object> {

    private static final Logger LOGGER = LoggerFactory.getLogger(EventLogger.class);

    @Override
    public void onEvent(CacheEvent<?, ?> event) {
        LOGGER.info("Event: " + event.getType() + " Key: " + event.getKey() + " old value: " + event.getOldValue() + " new value: " + event.getNewValue());
    }
}

CacheConfig

@Configuration
public class CacheConfig {

    @Bean
    public JCacheManagerCustomizer cacheManagerCustomizer() {
        return new JCacheManagerCustomizer() {

            @Override
            public void customize(CacheManager cacheManager) {
                cacheManager.createCache("studentCache", new MutableConfiguration<>()
                        .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.MINUTES, 5)))
                        .setStoreByValue(false)
                        .setStatisticsEnabled(true));

            }
        };
    }

} 

Cache on method

@RequestMapping(method = GET)
@ResponseBody
Cacheable(value = "studetNode")
    public List<StudentNodeDto> findAll(HttpServletResponse response) {
         val studentNodes = service.findAll();

ehcache.xml located under resources

<config
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xmlns:jsr107='http://www.ehcache.org/v3/jsr107'>

    <service>
        <jsr107:defaults>
            <jsr107:cache name="studentCache" template="heap-cache"/>
        </jsr107:defaults>
    </service>

    <cache-template name="heap-cache">
        <listeners>
            <listener>
                <class>org.terracotta.ehcache.EventLogger</class>
                <event-firing-mode>ASYNCHRONOUS</event-firing-mode>
                <event-ordering-mode>UNORDERED</event-ordering-mode>
                <events-to-fire-on>CREATED</events-to-fire-on>
                <events-to-fire-on>UPDATED</events-to-fire-on>
                <events-to-fire-on>EXPIRED</events-to-fire-on>
                <events-to-fire-on>REMOVED</events-to-fire-on>
                <events-to-fire-on>EVICTED</events-to-fire-on>
            </listener>
        </listeners>
        <resources>
            <heap unit="entries">2000</heap>
            <offheap unit="MB">100</offheap>
        </resources>
    </cache-template>
</config>

Gradle dependencies springBootVersion = '2.0.2.RELEASE'

    compile group: 'org.springframework.boot', name: 'spring-boot-starter', version: springBootVersion
        compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion
//Cache
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-cache', version: '2.1.1.RELEASE'
    compile group: 'org.ehcache', name: 'ehcache', version: '3.4.0'
    compile group: 'javax.cache', name: 'cache-api', version: '1.1.0'

I have looked over many post and blogs and it appears I am doing this correctl but I have to be wrong somewhere.

@Cacheable key on multiple method arguments

https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache

https://www.baeldung.com/spring-cache-tutorial

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html

https://www.baeldung.com/hibernate-second-level-cache

https://medium.com/@igorkosandyak/spring-boot-caching-d74591abe117

Advice?

---------------Update 1-----------------

I am getting an error saying:

    Error creating bean with name 'cacheManager' defined in class path 
    resource
 [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Unsatisfied dependency expressed through method 'cacheManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.cache.CacheManager]: Factory method 'jCacheCacheManager' threw exception; nested exception is org.ehcache.jsr107.MultiCacheException: [Exception 0] org.terracotta.ehcache.EventLogger

I get this when I added:

# caching
spring.cache.jcache.provider=org.ehcache.jsr107.EhcacheCachingProvider
spring.cache.jcache.config=classpath:ehcache.xml

Trace

restartedMain] heConfiguration$JCacheAvailableCondition : Condition JCacheCacheConfiguration.JCacheAvailableCondition on org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration matched due to AnyNestedCondition 1 matched 1 did not; NestedCondition on JCacheCacheConfiguration.JCacheAvailableCondition.CustomJCacheCacheManager @ConditionalOnSingleCandidate (types: javax.cache.CacheManager; SearchStrategy: all) did not find any beans; NestedCondition on JCacheCacheConfiguration.JCacheAvailableCondition.JCacheProvider JCache JCache provider specified

-------------- update 2------------------

I added the following to my gradle file

task showJarLocations {
    doLast {
        configurations.compile.resolve().each { file ->
            println file.canonicalPath
        }
    }
}

and the only jar showing with ehcache is:

/org.ehcache/ehcache/3.4.0/cac1f0840af0040a81401dfa55fa31a4ccc17932/ehcache-3.4.0.jar
and

javax.cache/cache-api/1.1.0/77bdcff7814076dfa61611b0db88487c515150b6/cache-api-1.1.0.jar

I have

spring.cache.jcache.provider=org.ehcache.jsr107.EhcacheCachingProvider
spring.cache.jcache.config=classpath:ehcache.xml

in application.properties too. This should explain why it fails when I add spring.cache.jcache.config=classpath:ehcache.xml.

Butin intellij it is in my project structure:

enter image description here

+--- org.springframework.boot:spring-boot-starter-cache:2.1.1.RELEASE
|    +--- org.springframework.boot:spring-boot-starter:2.1.1.RELEASE -> 2.0.2.RELEASE (*)
|    \--- org.springframework:spring-context-support:5.1.3.RELEASE -> 5.0.6.RELEASE
|         +--- org.springframework:spring-beans:5.0.6.RELEASE (*)
|         +--- org.springframework:spring-context:5.0.6.RELEASE (*)
|         \--- org.springframework:spring-core:5.0.6.RELEASE (*)
+--- org.ehcache:ehcache:3.4.0
|    \--- org.slf4j:slf4j-api:1.7.7 -> 1.7.25
+--- javax.cache:cache-api:1.1.0
+--- org.apache.tika:tika-core:1.19.1
+--- org.mapstruct:mapstruct-jdk8:1.2.0.Final
+--- org.projectlombok:lombok:1.18.2

Upvotes: 4

Views: 16397

Answers (3)

Fahmy Chaabane
Fahmy Chaabane

Reputation: 13

Make your entity or dto implement Serializable. Worked in my case.

Upvotes: 0

pcoates
pcoates

Reputation: 2307

  • Ensure springboot app is configured with @EnableCaching
  • Ensure the name in @Cacheable matches your cache name (you have a mismatch in what you posted.)

    @Cacheable(value = "studentCache")
    
  • Remove your CacheConfig

  • Place your ehcache.xml file in a subfolder of resources to make sure you're not picking up one from some other jar

    e.g. `resources/myconfig/ehcache.xml`
    
  • Set the property in application.properties to tell spring where to find the config file

    spring.cache.jcache.config=classpath:myconfig/ehcache.xml
    
  • Use a simplified ehcache.xml. e.g.

    <config
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
        xsi:schemaLocation="
            http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
            http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
    
        <cache alias="studentCache" uses-template="heap-cache" />
    
        <cache-template name="heap-cache">
            <resources>
                <heap unit="entries">2000</heap>
                <offheap unit="MB">100</offheap>
            </resources>
        </cache-template>
    
    </config>
    

If it still fails, post the results showing how you know it fails.

The reason you need the CacheConfig when using the <jsr107:cache elements is that ehcache will just associate the template with the cache name. It doesn't create the cache. The template will be used when you create the cache programatically (i.e. in your CacheConfig). So if you try an ehcache.xml which defines the cache you don't need the CacheConfig

Upvotes: 0

codemasterg
codemasterg

Reputation: 43

I found that using the spring-boot-starter-cache can create some subtle problems. If your ehcache.xml isn't found or you misname the cache name, Spring appears to fallback to a generic cache implementation thus hiding the problem. Try removing spring-boot-starter-cache as a dependency and add:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>

also add ehcache as an explicit dependency then see if that helps. You shouldn't need to even access a CacheManager since you are using ehcache.xml; the whole point of the xml is to make your configuration declarative and outside the code.

Upvotes: 3

Related Questions