【问题标题】:Using EhCache in Spring 4 without XML在没有 XML 的 Spring 4 中使用 EhCache
【发布时间】:2014-03-23 13:03:58
【问题描述】:

有没有办法在 Spring 4 或 Spring Boot 中不使用 xml 来初始化 EhCache?

我注意到 Spring Boot 1.0.0.RC3 没有任何 ehcache 依赖项,但 Spring 4.0GA release post 提到它改进了对 EhCache 的支持。此外,Spring 3 有 org.springframework.cache.ehcache.EhCacheCacheManager 类,但这不再是依赖项的一部分。

编辑: Spring 4 确实支持 EhCache。您必须添加依赖项:

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

编辑2: 我尝试了以下方法,我想我已经接近了,但我收到了一个错误:

@Bean
@Override
public CacheManager cacheManager() {
    CacheConfiguration cacheConfiguration = new CacheConfiguration();
    cacheConfiguration.setName("primary");
    cacheConfiguration.setMemoryStoreEvictionPolicy("LRU");
    cacheConfiguration.setMaxEntriesLocalHeap(0);

    net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration();
    config.addCache(cacheConfiguration);

    net.sf.ehcache.CacheManager cacheManager = new net.sf.ehcache.CacheManager(config);
    cacheManager.setName("EhCache");

    return new EhCacheCacheManager(cacheManager);
}

@Bean
public EhCacheManagerFactoryBean factoryBean() {
    return new EhCacheManagerFactoryBean();
}

错误

Caused by: net.sf.ehcache.CacheException: Another unnamed CacheManager already exists in the same VM. Please provide unique names for each CacheManager in the config or do one of following:
1. Use one of the CacheManager.create() static factory methods to reuse same CacheManager with same name or create one if necessary
2. Shutdown the earlier cacheManager before creating new one with same name.
The source of the existing CacheManager is: [Programmatically configured]
    at net.sf.ehcache.CacheManager.assertNoCacheManagerExistsWithSameName(CacheManager.java:590)
    at net.sf.ehcache.CacheManager.init(CacheManager.java:384)
    at net.sf.ehcache.CacheManager.<init>(CacheManager.java:263)
    at org.springframework.cache.ehcache.EhCacheManagerFactoryBean.afterPropertiesSet(EhCacheManagerFactoryBean.java:166)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
    ... 15 more

【问题讨论】:

标签: java spring ehcache


【解决方案1】:

Spring 中 EhCache 的 XML-less 配置

@Configuration
@EnableCaching
public class CachingConfig implements CachingConfigurer {
    @Bean(destroyMethod="shutdown")
    public net.sf.ehcache.CacheManager ehCacheManager() {
        CacheConfiguration cacheConfiguration = new CacheConfiguration();
        cacheConfiguration.setName("myCacheName");
        cacheConfiguration.setMemoryStoreEvictionPolicy("LRU");
        cacheConfiguration.setMaxEntriesLocalHeap(1000);

        net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration();
        config.addCache(cacheConfiguration);

        return net.sf.ehcache.CacheManager.newInstance(config);
    }

    @Bean
    @Override
    public CacheManager cacheManager() {
        return new EhCacheCacheManager(ehCacheManager());
    }

    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return new SimpleKeyGenerator();
    }

    @Bean
    @Override
    public CacheResolver cacheResolver()    {
        return new SimpleCacheResolver();
    }

    @Bean
    @Override
    public CacheErrorHandler errorHandler() {
         return new SimpleCacheErrorHandler();
    }
}

或者,为了测试,您可以使用一个简单的 ConcurrentMapCache,如下所示,不使用 XML 运行。

@Configuration
@EnableCaching
public class CachingConfig implements CachingConfigurer {
    @Bean
    @Override
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();

        List<Cache> caches = new ArrayList<Cache>();
        caches.add(new ConcurrentMapCache("myCacheName"));
        cacheManager.setCaches(caches);

        return cacheManager;
    }

    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return new SimpleKeyGenerator();
    }

    @Bean
    @Override
    public CacheResolver cacheResolver()    {
        return new SimpleCacheResolver();
    }

    @Bean
    @Override
    public CacheErrorHandler errorHandler() {
         return new SimpleCacheErrorHandler();
    }
}

编辑:更新以在底层缓存上添加关闭方法

编辑:添加了错误处理程序和缓存解析器的配置

编辑:更改 SimpleCacheResolver 上的构造函数调用解决了 CacheManager must not be null 问题(Spring v5.1+)

@Configuration
@EnableCaching
public class CachingConfig implements CachingConfigurer {

    public static final String USER_CACHE_INSTANCE = "my-spring-ehcache";
    private final CacheManager cacheManager;
    private final net.sf.ehcache.CacheManager ehCacheManager;


    public CachingConfig() {
        CacheConfiguration cacheConfiguration = new CacheConfiguration();
        cacheConfiguration.setName(USER_CACHE_INSTANCE);
        cacheConfiguration.setMemoryStoreEvictionPolicy("LRU");
        cacheConfiguration.setMaxEntriesLocalHeap(1000);
        net.sf.ehcache.config.Configuration config
                = new net.sf.ehcache.config.Configuration();
        config.addCache(cacheConfiguration);
        this.ehCacheManager = net.sf.ehcache.CacheManager.newInstance(config);
        this.cacheManager = new EhCacheCacheManager(ehCacheManager);
    }

    @Bean(destroyMethod="shutdown")
    public net.sf.ehcache.CacheManager ehCacheManager() {
        return ehCacheManager;
    }

    @Bean
    @Override
    public CacheManager cacheManager() {
        return cacheManager;
    }

    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return new SimpleKeyGenerator();
    }

    @Bean
    @Override
    public CacheResolver cacheResolver() {
        return new SimpleCacheResolver(cacheManager);
    }

    @Bean
    @Override
    public CacheErrorHandler errorHandler() {
        return new SimpleCacheErrorHandler();
    }
}

【讨论】:

  • @KevinM 您也可以为此使用 Spring Profile。使用这将根据活动配置文件启动一个或另一个。 docs.spring.io/spring/docs/current/javadoc-api/org/…
  • @KevinM 我会将它们分成两个单独的配置类并为每个类添加注释
  • Spring 4.2.5 org.springframework.cache.annotation.CachingConfigurer 需要为 EHCache 3.x 实现两个额外的方法:cacheResolvererrorHandler。如果答案中包含这些内容将是完美的:)
  • @Hadi 有同样的问题。我修复了它在 CachingConfig 类中将 return new SimpleCacheResolver(); 替换为 return new SimpleCacheResolver(cacheManager());
  • @SantiagoTórtora 当您调用cacheManager() 时,您每次都会实例化一个新的,例如Spring 将在创建 CacheManager bean 时调用一次以填充 IoC bean 上下文,然后在创建 SimpleCacheResolver bean 时再次调用它。我将在构造函数中创建cacheManager 的位置添加我的版本,并将其保留为CacheConfig 的成员变量,这在Spring 将其创建为单例的情况下很好。
【解决方案2】:

我在两个抽象级别上执行此操作,每个技术(Ehcache、Redis 等)的配置文件和通用配置文件。

这是 Ehcache 的一个(Redis 类似):

@Configuration
public class EhCacheConfiguration {

    @Bean
    public EhCacheCacheManager ehCacheCacheManager() {

        return new EhCacheCacheManager(ehCacheManagerFactoryBean().getObject());
    }


    @Bean
    public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {

        EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean();

        cacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
        cacheManagerFactoryBean.setShared(true);

        return cacheManagerFactoryBean;
    }
}

这是一个通用的(包含 Redis 钩子):

@Configuration
@EnableCaching
public class CachingConfiguration implements CachingConfigurer {

    @Qualifier("ehCacheCacheManager")
    @Autowired(required = false)
    private CacheManager ehCacheCacheManager;

    @Qualifier("redisCacheManager")
    @Autowired(required = false)
    private CacheManager redisCacheManager;


    @Bean
    @Override
    public CacheManager cacheManager() {

        List<CacheManager> cacheManagers = Lists.newArrayList();

        if (this.ehCacheCacheManager != null) {
            cacheManagers.add(this.ehCacheCacheManager);
        }

        if (this.redisCacheManager != null) {
            cacheManagers.add(this.redisCacheManager);
        }

        CompositeCacheManager cacheManager = new CompositeCacheManager();

        cacheManager.setCacheManagers(cacheManagers);
        cacheManager.setFallbackToNoOpCache(false);

        return cacheManager;
    }


    @Bean
    @Override
    public KeyGenerator keyGenerator() {

        return new DefaultKeyGenerator();
    }
}

【讨论】:

  • +1 喜欢抽象的想法。会玩这个
  • 我需要它来组合两个缓存管理器;它可能对您的需求有点过分,但删除复合材料应该很简单。
  • 我也喜欢这个想法,但我对 CacheManager 类型感到困惑。如何将 org.springframework.cache.CacheManager 和 net.sf.ehcache.CacheManager 的实例放在同一个列表中?
  • @Gabriel docs.spring.io/spring-framework/docs/current/javadoc-api/org/…,实现 org.springframework.cache.CacheManager
猜你喜欢
  • 1970-01-01
  • 2014-01-24
  • 2020-01-14
  • 2014-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-24
相关资源
最近更新 更多