intellij中啟動jetty出現的類載入問題
背景
簡單來說,就是使用intellij啟動內嵌jetty的工程,爆出class not found exception
,但是用eclipse啟動沒有問題,並且之前也是一直在eclipse中啟動,最近嚐鮮換成intellij才出現此問題。以下是具體配置
配置
開發環境
開發工具intellij
專案內嵌jetty+jFinal
問題
使用intellij啟動,失敗,工程以前都是在eclipse啟動,一點問題沒有,最近intellij大行其道才切換到intellij。
程式碼配置
public class MyJFinalConfig extends JFinalConfig {
public static void main(String[] args) {
JFinal.start("WebRoot", 8080, "/myproject", 5);
}
}
web.xml配置
<filter>
<filter-name>jfinal</filter-name>
<filter-class>com.jfinal.core.JFinalFilter</filter-class>
<init-param>
<param -name>configClass</param-name>
<param-value>com.mypak.MyJFinalConfig</param-value>
</init-param>
</filter>
異常資訊class not found com.mypak.MyJFinalConfig
分析
追蹤出錯的原始碼
ps:程式碼大體上就是這樣,只是為了表達那個意思。
Object obj = Class.forName("com.mypak.MyJFinalConfig" ).forInstance;
if(!obj instanceof JFinalFilter){
throw new Exception("出錯了")
}
classloader在搗鬼
我們知道MyJFinalConfig
是 JFinalFilter
子類,它的例項肯定是JFinalFilter
例項,但是實際執行結果來看,居然不是!
第一反應想到可能是ClassLoader在搗鼓,因為ClassLoader不同時,類的上下級關係無從談起,並且是jetty內嵌啟動,不同於以往的正常啟動,所以猜測可能跟classloader有關係。debug發現,MyJFinalConfig
類載入器是sun.misc.Launcher$AppClassLoader
,而JFinalFilter
是jetty包中的WebAppClassLoader
,果然classloader不一樣!原因找到了。
為何eclipse可以work,intellij就不行呢?
搜尋文章後發現,jetty的classloader會將WEB-INF/lib和 WEB-INF/classes底下的類,當作app的class,而不委託給父classloader。基於此,將intellij的outputpath設定為webRoot/WEB-INF/classes,讓WebAppClassLoader載入MyJFinalConfig
這樣兩個類就都是WebAppClassLoader
了。
修正
設定outputpath,將webRoot下的資原始檔排除,否則classes資料夾下也有有頁面等資原始檔
D:\intellij_workspace\myproject\WebRoot\WEB-INF\classes。
後續
後來在看JFinal手冊時,發現同樣道理的一句話。此處的 Default out folder 必須要與 WebRoot\WEB-INF\classes 目錄完全一致才可以使用 JFinal 整合的 Jetty 來啟動專案
並且,作者也說使用重啟方式,而不使用熱載入方式開發,因為重啟速度很快,如果熱載入還會出現classnotfoundexception
。當然資原始檔,比如頁面、js修改後,不需要重啟。