spring-boot-devtools热部署 和cacheManager冲突解决方案


一、问题

Idea开发工具想使用devtools实现开发过程中的热部署,添加依赖如下:

<dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-devtools</artifactId>

            <version>2.1.8.RELEASE</version>

            <optional>true</optional>

        </dependency>

项目中还使用了ehcache缓存和redis缓存,单机情况下使用ehcache缓存,添加devtools依赖后,更改html模板的内容后,项目会重新重启,但是在获取缓存中内容的时候报异常。

 

跟踪代码到如下位置:

 

 

 

错误信息为:

The CacheManager has been shut down. It can no longer be used.

 

查看getEhcache方法:

 

 

 

 

 

 

二、解决方法

经分析为cacheManager在热启动的时候被关闭关闭,但是对象没有被重新创建还是用的原来

 

 

 

 

  

所以需要重新实例化一个cacheManager,原来的代码如下:

 

 

 

 

 现在改为:

private net.sf.ehcache.CacheManager getCacheManager() {
    net.sf.ehcache.CacheManager cacheManager = ((EhCacheCacheManager) this.ehCacheCacheManager).getCacheManager();
    if (cacheManager == null || cacheManager.getStatus().intValue() == 2) {//等于2表示当前状态为关闭状态
        //在spring boot devtools 页面重启的时候,cacheManager会报当前缓存已经关闭的异常,
        // 所以在状态为关闭情况下,这里需要重新设置一下
        try {
            CacheManager cacheManager1 = CacheManager.create(ResourceUtils.getInputStreamForPath("classpath:ehcache.xml"));
            ((EhCacheCacheManager) this.ehCacheCacheManager).setCacheManager(cacheManager1);
            return cacheManager1;
        } catch (Exception e) {
            throw new RuntimeException("initialize cacheManager failed");
        }

    }
    return cacheManager;
}

问题解决了

但是如果采用的是memorySessionDao存储的session,重启之后session会丢失,这样需要对开发环境进行额外的拦截规则判断,如果不想修改shiro的拦截器或增加白名单的方式,可以采用ehcacheSessionDao的方式存储session信息,修改shiroconfig的配置:

    public SessionDAO sessionDAO() {
/*        SessionDAO sessionDAO = null;
        {sessionDAO = new MemorySessionDAO()*/
        EnterpriseCacheSessionDAO sessionDAO = new EnterpriseCacheSessionDAO();
        sessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
        return sessionDAO;
    }

defaultWebSessionManager的配置不用修改:

public DefaultWebSessionManager defaultWebSessionManager(CacheManager cacheShiroManager, Collection<SessionListener> listeners, SessionDAO sessionDAO) {
    
    DefaultWebSessionManager sessionManager = new DefaultWebSessionManager ();
    ……
    sessionManager.setSessionDAO(sessionDAO);
    return sessionManager;
}

配置ehcache.xml文件,增加shiro-activeSessionCache,设置overflowToDisk=true,存储到硬盘中

 

这样,重启之后就不用重新登录系统了

还有其他问题:

在热部署重新启动后,发现写日志的静态方法报数据库连接已关闭的异常,但是除了这个类之外其它访问数据库的操作又都正常,原来写日志的类采用的都是静态方法,而对应的数据库日志表的mapper是在该类的静态变量中声明的

 

 

猜测是热部署重启之后,datasource先是shutdown,而后新创建datasource对象,而日志类中静态变量不是采用authowire自动注入的方式,依然保持原来的mapper对象,所以访问数据库的时候就提示数据库连接已经关闭。

修改方式,将该私有全局静态变量放到方法中赋值:

private static void insertSecurityLog(SysSecurityLog sysSecurityLog) {
    
    SysSecurityLogMapper securityLogMapper = SpringCtxHolder.getBean(SysSecurityLogMapper.class);
    securityLogMapper.insert(sysSecurityLog);
    }

 参考地址:

Shiro如何使用Ehcache实现Session共享

解决springboot集成dubbo并使用外部容器部署在应用重启出现dataSource has already close 异常

还有一个通过监控事件的方式的文章:

SpringBoot Test 多线程报错:dataSource already closed

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM