同一个 VM 中已经存在另一个未命名的 CacheManager (ehCache 2.5)

这就是我运行 junit 测试时发生的情况。

Another CacheManager with same name '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:
DefaultConfigurationSource [ ehcache.xml or ehcache-failsafe.xml ]

异常背后的原因是什么? 是否有多个缓存管理器同时运行?

这就是我如何使用 Spring3.1.1配置 cachManager 的。它显式地将 cachManager 的范围设置为“ singleton”

<ehcache:annotation-driven />


<bean
id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
scope="singleton"
/>

Xml 看起来像

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false"
maxBytesLocalHeap="100M"
name="cacheManager"
>
....
</ehcache>

终于轮到我上课了

@Component
public class BookingCache implements CacheWrapper<String, BookingUIBean> {


@Autowired
private CacheManager ehCacheManager;
....
}

我非常确定我的代码库中只有一个缓存管理器。可能有别的东西在运行第 n 个实例。

86707 次浏览

您的 EhCacheManagerFactoryBean 可能是一个单例模式,但它正在构建多个 CacheManager,并试图给它们同一个名称。这违反了 Ehcache 2.5 语义学

版本2.5之前的 Ehcache 版本允许在 JVM 中存在任意数量的具有相同名称(相同配置资源)的 CacheManager。

Ehcache 2.5或更高版本不允许在同一个 JVM 中存在多个具有相同名称的 CacheManager。创建非 Singleton CacheManager 的 CacheManager ()构造函数可能违反此规则

通过将 分享属性设置为 true,告诉工厂 bean 在 JVM 中创建 CacheManager 的共享实例。

<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:shared="true"/>

您的问题是在 Spring 测试框架中构建的上下文加载优化。Spring (每个默认值)在测试类完成后不会破坏上下文,希望另一个测试类可以重用它(而不是从头开始创建它)。

您可以使用@DirtiesContext 覆盖这个默认值,或者如果您使用 maven,您可以将 surefire forkMode 设置为“ always”,并为每个测试类创建一个新的 VM。

您还可以尝试将名称设置为“ xxx”(在 ehcache 元素上)。

这对我来说很有用,因为我认为我有另一个缓存配置潜伏在我的应用程序的模块之一。

共享的解决方案也是有效的,但我不知道其中的深远含义。

在 glassfish 3.0.1中,我将问题追溯到 IniShiroFilter 进行两次初始化,这种情况发生在服务器启动后触发并发请求时。下面是来自两个对应于两个 HTTP 请求的不同线程的堆栈跟踪:

[#|2012-11-28T08:25:10.630-0800|SEVERE|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=28;_ThreadName=Thread-1;|java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1249)
at org.apache.shiro.web.servlet.IniShiroFilter.<init>(IniShiroFilter.java:124)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.createManagedObject(InjectionManagerImpl.java:303)
at com.sun.enterprise.web.WebContainer.createFilterInstance(WebContainer.java:725)
at com.sun.enterprise.web.WebModule.createFilterInstance(WebModule.java:1948)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:248)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at com.sentilla.filter.DumpFilter.doFilter(DumpFilter.java:152)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:322)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:239)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:662)

另一条线

[#|2012-11-28T08:25:15.299-0800|SEVERE|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=29;_ThreadName=Thread-1;|java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1249)
at org.apache.shiro.web.servlet.IniShiroFilter.<init>(IniShiroFilter.java:124)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.createManagedObject(InjectionManagerImpl.java:303)
at com.sun.enterprise.web.WebContainer.createFilterInstance(WebContainer.java:725)
at com.sun.enterprise.web.WebModule.createFilterInstance(WebModule.java:1948)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:248)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at com.sentilla.filter.DumpFilter.doFilter(DumpFilter.java:152)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:322)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:239)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:662)

查看堆栈跟踪 ApplicationFilterConfig.java: 248可能是罪魁祸首。或者,glassfish 在错误的上下文中初始化过滤器,为了比较,Tomcat 在 BootStrap 期间初始化过滤器。

如果您只测试您的业务服务,而不是二级缓存,那么您可以删除 Spring 配置文件中的二级配置,您的测试将成功运行。这是我的第二级配置:

 <bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="defaultPU" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">false</prop>
<!-- <prop key="hibernate.hbm2ddl.auto">update</prop> -->
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
</props>
</property>
</bean>

如果我改为完全配置二级缓存配置,真正的 webapp 在运行时使用,像这样:

    <bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="defaultPU" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">false</prop>
<!-- <prop key="hibernate.hbm2ddl.auto">update</prop> -->
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">net.sf.ehcache.hibernate.EhCacheRegionFactory</prop>
<prop key="net.sf.ehcache.configurationResourceName">ehcache/ehcache-hibernate-local.xml</prop>
</props>
</property>
</bean>

然后我得到同样的异常“另一个未命名的 CacheManager 已经存在于同一个 VM 中”

我在使用 JPA (2.0) + Hibernate (3.6.4) + Spring (3.2.4)进行集成测试时遇到了同样的问题。 使用以下 Hibernate 配置解决了这个问题:

<property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory"/>

而不是利用

<property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.EhCacheRegionFactory"/>

在我的案例中,问题是组件扫描和 java 配置。

root-context.xml
<context:component-scan base-package="org.beansugar">


servlet-context.xml
<context:component-scan base-package="org.beansugar">

Spring 组件-对 xml 文件进行两次扫描。 每次运行时它都在 SpringConfig.java 中生成 bean。 然后创建副本缓存管理器。

所以我在下面改了一下。

root-context.xml
<context:component-scan base-package="org.beansugar">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>


servlet-context.xml
<context:component-scan base-package="org.beansugar" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

在我的例子中,我们有一个定义为 bean 的自定义缓存管理器。 还有一个自定义的应用程序上下文,所以我们不使用 Spring junit runner... ... 因此@DirtiesContext 不能工作。

诀窍是从 bean 中检索缓存实例,在该缓存上获取 cache Manager (来自 EHCache 的实例)。并在缓存管理器上调用 RemoveCache 方法。

把它放在一个带有@After 注释的方法中,每次测试之后缓存就会从 VM 中删除。像这样:

@After
public void destroy() {
MyCustomCacheManager customCacheManager = (MyCustomCacheManager) context.getBean("yourCustomCacheManagerBean");


try {
net.sf.ehcache.Cache cache = customCacheManager.getCache();
net.sf.ehcache.CacheManager cacheManager = cache.getCacheManager();
cacheManager.removeCache("nameOfYourCache");
} catch (IllegalAccessException e) {
e.printStackTrace();
}


context.destroy();
context = null;
}

我通过添加以下资源解决了这个问题:

豆类 = { ... AclCacheManager (EhCacheManagerFactoryBean){ 分享 = 真实 } ... }

对于后代: 更好的方法是使用 EhCacheManagerFactoryBean的“接受-存在”属性。

对于未来的读者,在我的例子中出现这个问题的原因是,在 pom.xml 文件中,我导入了 hibernate-ehcache 库,我不知道它还包含了 ehcache 库,然后显式导入了 net.sf.ehache 库。

当我作为一个独立的应用程序(例如命令行实用程序)运行时,这似乎工作得很好,但是当在 tomcat 服务器上运行时,它导致了原始文章中的错误。

把我的文件从:

        <dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.0.2.Final</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.7.4</version>
</dependency>

致:

        <dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.0.2.Final</version>
</dependency>
<!-- ehcache dependency removed -->

解决了问题。如果有人知道为什么这个问题只在运行在 tomcat 容器中时出现,我会很感兴趣。.

这个错误也会发生在错误的映射文件上。消息很糟糕,没有说明原因。

升级到 Hibernate 5之后,我不得不使用:

<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>

而不是:

<property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory"/>

请注意这些包裹彼此不同。

当我切换到 SpringBoot2.0.2的时候,这种情况发生了。通过以下操作解决了这个问题:

在 application 中删除

spring.jpa.properties.hibernate.cache.region.factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory

在 pom.xml 中删除

<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>

仅保存在 pom.xml 中

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
</dependency>

EhCacheManagerFactoryBean#shared调到 true对我来说很管用。

EhCacheManagerFactoryBean#acceptExisting调到 true对我不起作用。

import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;


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

正如 在 Spring4中不使用 XML 使用 EhCache中所解释的

在我的案例中,配置如下:

<spring.boot.version>1.5.8.RELEASE</spring.boot.version>
<spring.boot.yarn.version>2.4.0.RELEASE</spring.boot.yarn.version>
<spring.version>4.3.7.RELEASE</spring.version>


<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.5.1-Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>3.5.1-Final</version>
</dependency>

更改 EHCache 提供程序类为我完成了这项工作。我使用缓存提供程序类作为 < code > org.hibernate.cache. EhCacheProvider ,而是将其更改为: net.sf.ehcache.hibernate.SingletonEhCacheProvider

SpringBoot2.1.2开始,下面的配置解决了这个问题(注意,这些是整个配置的片段)

依赖性:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.8.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.2.8.Final</version>
</dependency>

Yml 配置文件:

spring:
jpa:
open-in-view: false
hibernate:
ddl-auto: none
show-sql: true
properties:
dialect: org.hibernate.dialect.MySQLDialect
net:
sf:
ehcache:
configurationResourceName: ehcache.xml
hibernate:
cache:
use_second_level_cache: true
region:
factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory

Xml 配置:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<!-- Required elements -->
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"/>


<!-- Cache settings per class -->
<cache name="com.mystuff.component.services.example.Book"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"/>
</ehcache>

我正在开发的应用程序在没有工作缓存的情况下速度会急剧下降。因此,为了验证,我只需运行应用程序并命中一个读取强度很大的端点。

在我的例子中,Manager 是由这个 bean (ehCache 2.10)创建的:

  <bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="shared" value="false"/>
</bean>

对我来说唯一有效的解决办法就是用那种方式手动销毁它:

@Inject
private EhCacheManagerFactoryBean ehCacheManagerFactoryBean;

然后

ehCacheManagerFactoryBean.destroy();