【问题标题】:Spring: Multiple Cache ManagersSpring:多个缓存管理器
【发布时间】:2018-02-10 11:27:42
【问题描述】:

我在实现第二个缓存管理器时遇到问题。目前我正在使用 EhCache,它工作正常。另外,我想实现Java Simple Cache。

我的CacheConfiguration 看起来像这样:

CacheConfiguration.java

@Configuration
@EnableCaching
@AutoConfigureAfter(value = { MetricsConfiguration.class })
@AutoConfigureBefore(value = { WebConfigurer.class, DatabaseConfiguration.class })
public class CacheConfiguration {

    private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;

    public CacheConfiguration(JHipsterProperties jHipsterProperties) {
        JHipsterProperties.Cache.Ehcache ehcache =
            jHipsterProperties.getCache().getEhcache();

        jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
            CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
                ResourcePoolsBuilder.heap(ehcache.getMaxEntries()))
                .withExpiry(Expirations.timeToLiveExpiration(Duration.of(ehcache.getTimeToLiveSeconds(), TimeUnit.SECONDS)))
                .build());
    }

    /**
     * EhCache configuration
     * 
     * @return
     */
    @Bean
    @Primary
    public JCacheManagerCustomizer cacheManagerCustomizer() {
        return cm -> {          
            cm.createCache(com.david.coinlender.domain.News.class.getName(), jcacheConfiguration);
            
    // ...More caches
    }
    
    /**
     * Java Simple Cache configuration
     * @return
     */
    @Bean
    @Qualifier("simpleCacheManager")
    public CacheManager simpleCacheManager() {
        
        SimpleCacheManager simpleCacheManager = new SimpleCacheManager();       
        simpleCacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("bitfinexAuthCache")));
        
        return simpleCacheManager;
        
    }
}

使用简单缓存我想缓存对象。即:

@Cacheable(cacheManager = "simpleCacheManager", cacheNames = "bitfinexAuthCache", key = "#apiKey.apiKey")
private Exchange createBitfinexAuthenticatedExchange(ApiKeys apiKey) {
    
    ExchangeSpecification exSpec = new BitfinexExchange().getDefaultExchangeSpecification();
    exSpec.setApiKey(apiKey.getApiKey());
    exSpec.setSecretKey(apiKey.getSecret());
    
    Exchange bfx = ExchangeFactory.INSTANCE.createExchange(BitfinexExchange.class.getName());
    bfx.applySpecification(exSpec);
    
    return bfx;
}

但是,在服务器启动时,liquibase 给我一个错误说明:

Caused by: java.lang.IllegalStateException: All Hibernate caches should be created upfront. Please update CacheConfiguration.java to add com.david.coinlender.domain.News
at io.github.jhipster.config.jcache.NoDefaultJCacheRegionFactory.createCache(NoDefaultJCacheRegionFactory.java:37)
at org.hibernate.cache.jcache.JCacheRegionFactory.getOrCreateCache(JCacheRegionFactory.java:190)
at org.hibernate.cache.jcache.JCacheRegionFactory.buildEntityRegion(JCacheRegionFactory.java:113)
at org.hibernate.cache.spi.RegionFactory.buildEntityRegion(RegionFactory.java:132)
at org.hibernate.internal.CacheImpl.determineEntityRegionAccessStrategy(CacheImpl.java:439)
at org.hibernate.metamodel.internal.MetamodelImpl.initialize(MetamodelImpl.java:120)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:297)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:445)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:889)
... 25 common frames omitted

我正在为我的应用程序使用 Jhipster 框架。我在谷歌上搜索了这个问题几个小时,但还没有找到解决方案。

这个错误是因为配置错误吗?有人可以指出我正确的方向吗?

【问题讨论】:

  • 试试@Bean("simpleCacheManager")而不是@Qualifier
  • 不幸的是抛出了同样的错误:/

标签: spring caching ehcache jhipster


【解决方案1】:

在JHipster(我做了代码)中,实际上有两层缓存。你有 Spring Cache 和 Hibernate 二级缓存。两者都使用相同的实际 Ehcache CacheManager

在您的情况下,您已将 Ehcache 替换为 Spring 的简单缓存。但是由于 NoDefaultJCacheRegionFactory 仍然在 Hibernate 上配置,所以它仍然是 Ehcache 用于 Hibernate。但是不再使用定制器。所以它失败了。

您希望为 Spring 提供一个简单的缓存,为 Hibernate 提供一个 Ehcache。这意味着实际上不需要在 Spring 中为 Ehcache 注册 bean。

最简单的方法是执行以下操作。

首先,在DatabaseConfiguration中配置Ehcache。所以当hibernate JCache工厂检索它时,它会被正确配置。

public DatabaseConfiguration(Environment env, JHipsterProperties jHipsterProperties) {
    this.env = env;

    JHipsterProperties.Cache.Ehcache ehcache =
        jHipsterProperties.getCache().getEhcache();

    CachingProvider provider = Caching.getCachingProvider();
    javax.cache.CacheManager cacheManager = provider.getCacheManager();

    javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
        CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
            ResourcePoolsBuilder.heap(ehcache.getMaxEntries()))
            .withExpiry(Expirations.timeToLiveExpiration(Duration.of(ehcache.getTimeToLiveSeconds(), TimeUnit.SECONDS)))
            .build());

    cacheManager.createCache(com.mycompany.myapp.domain.User.class.getName(), jcacheConfiguration);
    cacheManager.createCache(com.mycompany.myapp.domain.Authority.class.getName(), jcacheConfiguration);
    cacheManager.createCache(com.mycompany.myapp.domain.User.class.getName() + ".authorities", jcacheConfiguration);
}

然后,配置 Spring Cache。

public class CacheConfiguration {

    public CacheConfiguration() {
    }

    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        Collection<Cache> caches = Arrays.asList(
            new ConcurrentMapCache("mycache")
            // ...
        ); 
        cacheManager.setCaches(caches);
        return cacheManager;
    }
}

【讨论】:

  • 感谢您的帮助。我发现这比我最初想象的要复杂。我会在接下来的几天里尝试@Daniel C 的建议并给你反馈。
  • 我实际上想实现两个缓存管理器。对于“标准”休眠二级缓存,我想使用 EhCache(标记为@Primary)。但是对于某些用例,我需要 Java Simple Cache 的实现(例如,我想缓存从 API 返回的对象 - 一种连接/交换对象)。所以据我了解,不可能只在 CacheConfiguration.java 中实现第二个缓存?
  • 啊!这是不同的。这意味着您不需要从 Spring 中公开 Ehcache。只需要配置提供程序。然后暴露简单的缓存。让我更新我的答案。
【解决方案2】:

@EnableCaching Doc

对于那些希望在 @EnableCaching 和要使用的确切缓存管理器 bean 之间建立更直接关系的人,可以实现 CachingConfigurer 回调接口。注意下面@Override 注释的方法:

还有一个使用 CachingConfigurer 并采用在 JCacheCacheConfiguration 上实施的方法的替代方法。

1- 在CacheConfiguration 类中实现CachingConfigurer 接口。一种选择是从JCacheConfigurerSupport 扩展。

public class CustomCacheConfiguration extends JCacheConfigurerSupport {

2- 创建默认的cacheManager bean,因为 bean 是通过CachingConfigurer 配置的,它将作为默认的cacheManager 检索,在这种情况下,它可以被休眠二级缓存使用,对于这种方法cacheManagerCustomizer 将只是一种方法。像这样:

   @Bean
    @Override
    public CacheManager cacheManager() {
        javax.cache.CacheManager jCacheCacheManager = createCacheManager();
        cacheManagerCustomizer().customize(jCacheCacheManager);
        return new JCacheCacheManager(jCacheCacheManager);
    }

    private javax.cache.CacheManager createCacheManager()  {
        CachingProvider cachingProvider = Caching.getCachingProvider();
        return cachingProvider.getCacheManager();
    }

    private JCacheManagerCustomizer cacheManagerCustomizer() {
        return cm -> {

            cm.createCache(org.demo.app.domain.User.class.getName(), jcacheConfiguration);
        ......

      };
}

3- 创建simpleCacheManager bean

@Bean("simpleCacheManager")
    public SimpleCacheManager simpleCacheManager() {
        SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
        simpleCacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("bitfinexAuthCache")));

        return simpleCacheManager;

    }
  1. 为了定义将使用哪个cacheManager,然后通过@Cacheable(cacheManager = "simpleCacheManager", cacheNames = "bitfinexAuthCache")定义它

这里是CacheConfiguration的完整定制。

@Configuration
@EnableCaching
@AutoConfigureAfter(value = { MetricsConfiguration.class })
@AutoConfigureBefore(value = { WebConfigurer.class, DatabaseConfiguration.class})
public class CacheConfiguration extends JCacheConfigurerSupport {

    private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;


    public CustomCacheConfiguration(JHipsterProperties jHipsterProperties) {
        JHipsterProperties.Cache.Ehcache ehcache =
            jHipsterProperties.getCache().getEhcache();




        jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
            CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
                ResourcePoolsBuilder.heap(ehcache.getMaxEntries()))
                .withExpiry(Expirations.timeToLiveExpiration(Duration.of(ehcache.getTimeToLiveSeconds(), TimeUnit.SECONDS)))
                .build());
    }


    @Bean
    @Override
    public CacheManager cacheManager() {
        javax.cache.CacheManager jCacheCacheManager = createCacheManager();
        cacheManagerCustomizer().customize(jCacheCacheManager);
        return new JCacheCacheManager(jCacheCacheManager);
    }

    private javax.cache.CacheManager createCacheManager()  {
        CachingProvider cachingProvider = Caching.getCachingProvider();
        return cachingProvider.getCacheManager();
    }


    private JCacheManagerCustomizer cacheManagerCustomizer() {
        return cm -> {

            cm.createCache(org.demo.app.domain.User.class.getName(), jcacheConfiguration);
            cm.createCache(org.demo.app.domain.Authority.class.getName(), jcacheConfiguration);
            cm.createCache(org.demo.app.domain.User.class.getName() + ".authorities", jcacheConfiguration);
            cm.createCache(org.demo.app.domain.Company.class.getName(), jcacheConfiguration);
            //cm.createCache(org.demo.app.domain.News.class.getName(), jcacheConfiguration);

        };
    }

    @Bean("simpleCacheManager")
    public SimpleCacheManager simpleCacheManager() {
        SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
        simpleCacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("bitfinexAuthCache")));

        return simpleCacheManager;

    }

}

【讨论】:

  • 没有。 NoDefaultJCacheRegionFactory 扩展了 JCacheRegionFactory。照你说的去做,但你不会得到你想的缓存。
  • 你是对的!!,simpleCacheManager 正在覆盖默认的jCacheCacheManager,一旦我创建了simpleCacheManager bean,默认的缓存管理器就消失了。我错了,谢谢你的cmets。我会再试一次。
  • 嗨@Henri,我添加了一个基于CachingConfigurer 接口的新替代方案。
  • 非常感谢您的评论。我将在接下来的几天内尝试该解决方案并给您反馈!
猜你喜欢
  • 2016-05-05
  • 1970-01-01
  • 2016-11-28
  • 1970-01-01
  • 2016-02-02
  • 1970-01-01
  • 1970-01-01
  • 2018-11-29
  • 1970-01-01
相关资源
最近更新 更多