Shiro 整合 ehcache 缓存报: Another CacheManager with same name 'test' already exists in the same VM

原创
2021/01/06 11:32
阅读数 1.8K

Shiro 整合 ehcache 缓存报错:

Factory method 'ehCacheCacheManager' threw exception; nested exception is net.sf.ehcache.CacheException: Another CacheManager with same name 'test' already exists in the same VM. Please provide unique names for each CacheManager in the config or do one of following:

ehcache 存放位置和 内容

位置: resources/ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false"
         name="test" >
    <defaultCache
            eternal="false"
            maxElementsInMemory="1000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="0"
            timeToLiveSeconds="600"
            memoryStoreEvictionPolicy="LRU" />

    <!-- 这里的 users 缓存空间是为了下面的 demo 做准备 -->
    <cache
            name="user"
            eternal="false"
            maxElementsInMemory="100"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="0"
            timeToLiveSeconds="300"
            memoryStoreEvictionPolicy="LRU" />
    <cache
            name="allMenus"
            eternal="false"
            maxElementsInMemory="100"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="0"
            timeToLiveSeconds="300"
            memoryStoreEvictionPolicy="LRU" />
</ehcache>

springboot shiro 项目配置 ehcache 依赖

说明: shiro-ehcache.jar 中本来就依赖 ehcache-core.jar 所以也可以不用引入ehcache.jar

<!-- Ehcache 坐标 -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.10.6</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.ehcache/ehcache -->
        <!--<dependency>-->
        <!--<groupId>org.ehcache</groupId>-->
        <!--<artifactId>ehcache</artifactId>-->
        <!--<version>3.5.3</version>-->
        <!--</dependency>-->

		<!-- shiro 和 ehchche 整合 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>net.sf.ehcache</artifactId>
                    <groupId>ehcache-core</groupId>
                </exclusion>
            </exclusions>
        </dependency>

shiro 配置中引入 ehcache 缓存

原来在网上找的配置,这里仅仅展示 shiro 需要 配置 ehcache 的地方,没有展示 shiro 的全部配置

    @Bean
    public SecurityManager securityManager(@Qualifier("authRealm")AuthRealm authRealm){
        logger.info("- - - - - - -shiro开始加载- - - - - - ");
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(authRealm);
        defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
        defaultWebSecurityManager.setSessionManager(webSessionManager());
//        defaultWebSecurityManager.setCacheManager(cacheManager());
        defaultWebSecurityManager.setCacheManager(ehCacheManager());
        return defaultWebSecurityManager;
    }



    @Bean
    public EhCacheManager ehCacheManager() {

        CacheManager cacheManager = CacheManager.getCacheManager("test");// 2.10.6

        if(cacheManager == null) {
            try {
                cacheManager = CacheManager.create(ResourceUtils.getInputStreamForPath("classpath:ehcache.xml"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManager(cacheManager);
//        ehCacheManager.setCacheManager(cacheCacheManager.getCacheManager());
        return ehCacheManager;
    }



    @Bean
    public SessionManager webSessionManager(){
        DefaultWebSessionManager manager = new DefaultWebSessionManager();
        //设置session过期时间为5小时(单位:毫秒),默认为30分钟
        manager.setGlobalSessionTimeout(4 * 60 * 60 * 1000);
        manager.setSessionValidationSchedulerEnabled(true);
//        manager.setSessionDAO(redisSessionDAO());
        manager.setSessionDAO(sessionDAO());
        return manager;
    }



    @Bean
    public SessionDAO sessionDAO(){
        return new MemorySessionDAO();
    }

报错详情

具体信息:Error creating bean with name 'ehCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/EhCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [net.sf.ehcache.CacheManager]: Factory method 'ehCacheCacheManager' threw exception; nested exception is net.sf.ehcache.CacheException: Another CacheManager with same name 'test' already exists in the same VM. Please provide unique names for each CacheManager in the config or do one of following:

创建 EhCacheCacheManager 类的对象失败,因为 在内存中 已经有同一个 名为 "test" 的 CacheManager

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/EhCacheCacheConfiguration.class]: Unsatisfied dependency expressed through method 'cacheManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ehCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/EhCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [net.sf.ehcache.CacheManager]: Factory method 'ehCacheCacheManager' threw exception; nested exception is net.sf.ehcache.CacheException: Another CacheManager with same name 'test' 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: InputStreamConfigurationSource [stream=java.io.BufferedInputStream@4f6f8bec]
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:509)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
	at 
...
	... 86 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ehCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/EhCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [net.sf.ehcache.CacheManager]: Factory method 'ehCacheCacheManager' threw exception; nested exception is net.sf.ehcache.CacheException: Another CacheManager with same name 'test' 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: InputStreamConfigurationSource [stream=java.io.BufferedInputStream@4f6f8bec]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456)
	...
	... 103 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [net.sf.ehcache.CacheManager]: Factory method 'ehCacheCacheManager' threw exception; nested exception is net.sf.ehcache.CacheException: Another CacheManager with same name 'test' 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: InputStreamConfigurationSource [stream=java.io.BufferedInputStream@4f6f8bec]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622)
	... 117 common frames omitted
Caused by: net.sf.ehcache.CacheException: Another CacheManager with same name 'test' 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: InputStreamConfigurationSource [stream=java.io.BufferedInputStream@4f6f8bec]
	at net.sf.ehcache.CacheManager.assertNoCacheManagerExistsWithSameName(CacheManager.java:631)
	at net.sf.ehcache.CacheManager.init(CacheManager.java:395)
	at net.sf.ehcache.CacheManager.<init>(CacheManager.java:269)
	at org.springframework.cache.ehcache.EhCacheManagerUtils.buildCacheManager(EhCacheManagerUtils.java:79)
	at org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration.ehCacheCacheManager(EhCacheCacheConfiguration.java:66)
	at org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration$$EnhancerBySpringCGLIB$$fbdd92b7.CGLIB$ehCacheCacheManager$1(<generated>)
	at org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration$$EnhancerBySpringCGLIB$$fbdd92b7$$FastClassBySpringCGLIB$$e88e0c8.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
	at org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration$$EnhancerBySpringCGLIB$$fbdd92b7.ehCacheCacheManager(<generated>)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
	... 118 common frames omitted

分析错误:

确定事实: ehcache 2.5 后 , CacheManager 变成单例模式,所以不能创建两个 cacheManager 对象,

解决办法1: 将ehcache 版本换到2.5 以下,CacheManager 对象就不是单例的允许存在多个对象

分析报错: 创建 EhCacheCacheManager 类的对象失败,发现 在debug 模式下, 先进入shiro 的配置类,此时cacheManager 对象为空,然后创建成功,但是走完就报错, 所以是在 创建 EhCacheCacheManager  时报错, 分析 报错截图, 发现EhCacheCacheConfiguration.java:66  在此处是个配置类,再次调用了 生成的CacaheManager 的方法,

通过 EhCacheCacheManager 来管理,

EhCacheManagerUtils.buildCacheManager(location);  -->  new CacheManager(parseConfiguration(configLocation));     --> init(configuration, null, null, null);

但是 创建CacaheManager  的 方法 并没有按照 单例模式推荐的方法来调用,而是用init() 方法来进行,创建的时候并没有先去map 中查询是否有对应name 的cacheManager 对象,

解决办法2:在shiro 配置类中显示声明 CacheManager 对象,因为分析中  EhCacheCacheConfiguration.java:66 方法注解表明

@ConditionalOnMissingBean , 这个配置类是在找不到声明的 CacheManager 对象的情况才行创建,

修改后的 shiro 集成 ehcache 配置

    @Bean
    public SecurityManager securityManager(@Qualifier("authRealm")AuthRealm authRealm){
        logger.info("- - - - - - -shiro开始加载- - - - - - ");
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(authRealm);
        defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
        defaultWebSecurityManager.setSessionManager(webSessionManager());
//        defaultWebSecurityManager.setCacheManager(cacheManager());
        defaultWebSecurityManager.setCacheManager(ehCacheManager());
        return defaultWebSecurityManager;
    }


    /**
     * 显式声明 CacheManager ,防止 EhCacheCacheConfiguration 调用 ehCacheCacheManager()                
     * 继续生成 CacheManager
     * @return
     */
    @Bean
    public CacheManager ehCacheCacheManager() {
        CacheManager cacheManager = CacheManager.getCacheManager("test");// 2.10.6

        if(cacheManager == null) {
            try {
                cacheManager = CacheManager.create(ResourceUtils.getInputStreamForPath("classpath:ehcache.xml"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return cacheManager;
    }



    /**
     * 将生成的 CacheManager 对象转为Shiro 管理的 EhCacheManager 对象
     * @return
     */
    @Bean
    public EhCacheManager ehCacheManager() {
        CacheManager cacheManager = ehCacheCacheManager();
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManager(cacheManager);
//        ehCacheManager.setCacheManager(cacheCacheManager.getCacheManager());
        return ehCacheManager;
    }

     @Bean
    public SessionManager webSessionManager(){
        DefaultWebSessionManager manager = new DefaultWebSessionManager();
        //设置session过期时间为5小时(单位:毫秒),默认为30分钟
        manager.setGlobalSessionTimeout(4 * 60 * 60 * 1000);
        manager.setSessionValidationSchedulerEnabled(true);
//        manager.setSessionDAO(redisSessionDAO());
        manager.setSessionDAO(sessionDAO());
        return manager;
    }



    @Bean
    public SessionDAO sessionDAO(){
        return new MemorySessionDAO();
    }

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部