背景
简单来说,就是使用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修改后,不需要重启。