目前在做springboot項目的shiro session redis共享功能。但是有一個對象我把它放到redis中之后再取出來就會出現類型不匹配的異常
AuthorizationUser user = (AuthorizationUser) cache.getSuper(key);
異常信息:
java.lang.ClassCastException: com.ch.evaluation.auth.shiro.entity.AuthorizationUser cannot be cast to com.ch.evaluation.auth.shiro.entity.AuthorizationUser
通過debug看到他們的類信息是一樣的
難道只是看起來一樣么?我來判斷一下
結果是false ,
那么我們知道JVM判斷兩個類對象是否相同的依據:一是類全稱;一個是類加載器
既然他倆的類全稱一樣,那么問題肯定就出在了類加載器上了
我們可以Debug看一下他倆的類加載器
果然不出所料,他倆的類加載器是不同的!
那么是什么原因導致他的類加載器不一樣呢?
大家都知道虛擬機的默認類加載機制是通過雙親委派實現的。springboot為了實現程序動態性(比如:代碼熱替換、模塊熱部署等,白話講就是類文件修改后容器不重啟),“破壞或犧牲” 了雙親委派模型。springboot通過強行干預-- “截獲”了用戶自定義類的加載(由jvm的加載器AppClassLoader變為springboot自定義的加載器RestartClassLoader,一旦發現類路徑下有文件的修改,springboot中的spring-boot-devtools模塊會立馬丟棄原來的類文件及類加載器,重新生成新的類加載器來加載新的類文件,從而實現熱部署。比較流行的OSGI也能實現熱部署)。
既然源頭因熱部署而起,所以只要想辦法關掉springboot的熱部署即可。
<方案一> 通過卸掉springboot的熱部署模塊spring-boot-devtools來實現
在pom中注釋掉springboot的spring-boot-devtools
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency>
<方案二>如果不想卸掉spring-boot-devtools模塊也可禁用部署功能

讀者也可以在application.properties設置禁用屬性,但它的作用域只發生在當前模塊,如果你的項目牽扯到多個模塊,最好通過上面的方式在整個運行系統的級別禁用,以免出現多個模塊之間實現類文件調用時類加載器不一致的問題。
<方案三>既然是類加載器的問題也可使用Spring的ConfigurableObjectInputStream配合Thread.currentThread().getContextClassLoader() 來使用。
?