关于JFinal中Jetty的类加载器问题

一、问题描述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


  1. Bootstrap ClassLoader,负责加载java基础类,主要是 %JRE_HOME/lib目录下的jar和classio

  2. Extension ClassLoader,负责加载java扩展类,主要是 %JRE_HOME/lib/ext 目录下的jar和class

  3. 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目录下。

以上就是我我的在该问题中的经验总结,但愿可以帮助到你们,谢谢~

相关文章
相关标签/搜索