【问题标题】:Unable to cache using ehcache version 3.4.0 and spring boot 2.0.2.RELEASE无法使用 ehcache 版本 3.4.0 和 spring boot 2.0.2.RELEASE 进行缓存
【发布时间】:2018-12-09 11:16:10
【问题描述】:

我尝试了几种在 Spring Boot 应用程序上实现缓存的方法,这似乎是正确的方法,但它只是记录了这一点

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

我有一个事件记录器,但我没有看到任何输出:

@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());
    }
}

缓存配置

@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));

            }
        };
    }

} 

缓存方法

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

ehcache.xml 位于资源下

<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 依赖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'

我查看了许多帖子和博客,看来我这样做是正确的,但我必须在某个地方出错。

@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

建议?

---------------更新1-----

我收到一条错误消息:

    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

当我添加时我得到了这个:

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

追踪

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

------------- 更新 2------------------

我将以下内容添加到我的 gradle 文件中

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

唯一显示 ehcache 的 jar 是:

/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

我有

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

也在application.properties 中。这应该可以解释为什么当我添加spring.cache.jcache.config=classpath:ehcache.xml.时它会失败

但 intellij 它在我的项目结构中:

+--- 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

【问题讨论】:

  • 您的配置工作正常
  • 如果添加属性 spring.cache.jcache.provider=org.ehcache.jsr107.EhcacheCachingProvider spring.cache.jcache.config=classpath:ehcache.xml,您会在日志中看到什么区别跨度>
  • 如果你设置了logging.level.org.springframework.boot.autoconfigure.cache=tracelogging.level.org.ehcache=trace,你还能在日志中看到吗
  • @pcoates 没有日志输出,如果我添加=classpath:ehcache.xml,我会得到Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: org.ehcache.jsr107.EhcacheCachingProvider 没有变化
  • 这很奇怪,你应该看到一些东西。我假设您的主应用程序上有@EnableCaching。可能值得发布您在主应用程序上获得的注释,以及您拥有的全套依赖项,以防有什么阻碍。我注意到您在注释上的帖子Cacheable(value = "studetNode") I assume this is a typo as it should be studentNode, also needs an @`。

标签: spring-boot spring-cache ehcache-3


【解决方案1】:

我发现使用 spring-boot-starter-cache 会产生一些微妙的问题。如果找不到您的 ehcache.xml 或者您错误地命名了缓存名称,Spring 似乎会回退到通用缓存实现,从而隐藏问题。尝试删除 spring-boot-starter-cache 作为依赖项并添加:

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

还将 ehcache 添加为显式依赖项,然后查看是否有帮助。您甚至不需要访问 CacheManager,因为您使用的是 ehcache.xml; xml 的全部意义在于使您的配置具有声明性并且在代码之外。

【讨论】:

  • 谢谢。我会试一试!感谢发帖
  • 我试过并得到了这个错误`创建类路径资源中定义的名称为'objectMapperConfigurer'的bean时出错[springfox/documentation/spring/web/SpringfoxWebMvcConfiguration.class]:`值得一试。感谢您发帖。
  • 您是否删除了 CacheConfig 并尝试精简 ehcache.xml,例如:
【解决方案2】:
  • 确保 springboot 应用配置了@EnableCaching
  • 确保@Cacheable 中的名称与您的缓存名称匹配(您发布的内容不匹配。)

    @Cacheable(value = "studentCache")
    
  • 删除您的 CacheConfig

  • 将您的 ehcache.xml 文件放在资源的子文件夹中,以确保您没有从其他 jar 中提取一个

    e.g. `resources/myconfig/ehcache.xml`
    
  • 在 application.properties 中设置属性告诉 spring 在哪里可以找到配置文件

    spring.cache.jcache.config=classpath:myconfig/ehcache.xml
    
  • 使用简化的 ehcache.xml。例如

    <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>
    

如果仍然失败,请发布结果,说明您如何知道它失败了。

使用&lt;jsr107:cache 元素时需要CacheConfig 的原因是ehcache 只会将模板与缓存名称相关联。它不会创建缓存。当您以编程方式创建缓存时(即在您的 CacheConfig 中),将使用该模板。因此,如果您尝试定义缓存的 ehcache.xml,则不需要 CacheConfig

【讨论】:

    【解决方案3】:

    使您的实体或 d 实现可序列化。 在我的情况下工作。

    【讨论】: