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