一、問題描述java
首先是我遇到的問題現象是:前文1 前文2 前文3 前文4spa
通過一個星期得順藤摸瓜,最後找到了問題得根源是,ClassLoader不一樣的問題。引用別人博文的話:
.net
在Java中,一個類用其徹底匹配類名(fully qualified class name)做爲標識,這裏指的徹底匹配類名包括包名和類名。但在JVM中一個類用其全名和一個加載類ClassLoader的實例做爲惟一標識,不一樣類加載器加載的類將被置於不一樣的命名空間。線程
所以,在JFinal中的modelToTableMap和modelToConfigMap,雖然Map中都保存着名字相同的類對象,可是因爲使用了不一樣的ClassLoader,也是沒法從Map中get到值,每次都是返回Null。調試
在個人項目中,使用了ServletContextListener來執行一個定時任務,這裏使用的ClassLoader是WebAppClassLoader。而在JFinal初始化配置的時候,卻使用了AppClassLoader。對象
另外就是,我使用了Maven來進行了Jar包的管理。開發
二、ClassLoader的相關知識get
首先,AppClassLoader是屬於JVM的ClassLoader體系中的一個,屬於系統類加載器,另外兩個是ExtClassLoader和Bootstrap Loader。三者之間存在的父類委託機制,就是子類接受類加載的請求時,先向父類進行類進行委託加載,若是父類有,則使用父類的加載器,若是沒有,才使用子類自身類加載器。it
Bootstrap ClassLoader,負責加載java基礎類,主要是 %JRE_HOME/lib目錄下的jar和classio
Extension ClassLoader,負責加載java擴展類,主要是 %JRE_HOME/lib/ext 目錄下的jar和class
App ClassLoader,負責加載當前java應用的classpath中的全部類。
而後再說WebAppClassLoader,它是屬於特殊的加載機制,它先試圖本身載入類(在ContextPath/WEB-INF/lib和classes中載入類),若是沒法載入,再請求父ClassLoader完成。 對於WEB APP線程,它的contextClassLoader是WebAppClassLoader 。對於Tomcat Server線程,它的contextClassLoader是CatalinaClassLoader 。
根據以上的知識,大概能夠把問題解釋清楚了。
JFinal的jar包是經過Maven添加到項目中,雖然是添加到了classpath當中,可是並無放到WEB-INF/lib目錄下面。所以,在使用ServletContextListener啓動的定時任務時,使用的類加載器是WebAppClassLoader。JFinal進行初始化時,默認也是優先從WebAppClassLoader的目錄下尋找相應的類文件,可是因爲lib下沒有,所以轉而向AppClassLoader發出請求,這時就遵循父類委託機制。最後,在ClassPath中找到,也就是Maven中,因此就使用了AppClassLoader。
三、問題解決
方法一:把定時任務,也放到JFinal中去啓動,而不是使用ServletContext,這樣就保證了定時任務和JFinal的對象都是在同一個ClassLoader中,就是AppClassLoader。
方法二:把JFinal-1.9.jar包放到WEB-INF/lib目錄下,這樣就可以保證二者的對象在同一個ClassLoader中,這時就是WebAppClassLoader。
其實,這也是在開發調試中才會遇到的問題,若是打包成war包,放到Tomcat中運行的話,也是不會出現這個問題的。由於,全部使用的jar包都會導出到WEB-INF/lib目錄下。
以上就是我我的在該問題中的經驗總結,但願可以幫助到你們,謝謝~