ClassLoader优先级问题

wangyeee 2011-02-26 09:37:36
最近做一个web项目,服务器用的是tomcat,需要一个动态添加jar库的功能(系统不停机),我在程序中用URLClassLoader动态加载新的jar,发现无法引用项目里面WEB-INF/lib下的jar库,老是报ClassNotFoundException,我在没有动态加载jar之前看了看原有jar中类的加载器是org.apache.catalina.loader.WebappClassLoader:

Class<?>c = Class.forName("org.slf4j.Logger");//slf4j的jar包在WEB-INF/lib目录下
out.print(c.getClassLoader().getClass().getName());

输出结果是WebappClassLoader,这个类是java.net.URLClassLoader的子类,属于最低优先级的类加载器,现在我用URLClassLoader加载新的jar文件,就出错:

String className;//类名
URL[] url;//url数组
//省略变量初始化,保证变量值正确
ClassLoader loader = new URLClassLoader(url);
Class<?> c = loader.loadClass(className);//这里抛ClassNotFoundException异常
Object obj = c.newInstance();

不过这里抛出的异常不是className没找到,而是className的父接口没找到,className父接口所在的jar包在WEB-INF/lib目录下。我尝试了下面两个办法解决:
1.用Java Instrumentation把className父接口所在的jar包加入系统classpath中,这时loadClass正常了,但是后面无法直接调用类的方法了,必须全部用反射调用,这样需要修改大量代码,就没有继续。
2.把WEB-INF/lib里面的jar全部拷到%JRE_HOME%\lib\ext里面,现在一切都正常了,但是这样需要修改系统配置,而我更希望能在程序代码中解决这个问题,或者最多是修改项目配置。
不知道大家还有没有其它解决方法,我希望能通过在ClassLoader下手解决。谢谢!
...全文
226 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
suntingtingonly 2011-03-01
  • 打赏
  • 举报
回复
我关注这个问题。 这个问题我也遇到过。 自己想做 动态加载程序。
但是加载过程中我用的 URLClassLoader 用这个加载的话,我这里的程序是需要把加载的放在一个文件里面
声明的时候 要写父路径。
我想问的是 你的包更新或者添加。添加的话 能够接受。 怎么调用
覆盖的话 怎么调用呢?
树成 2011-02-27
  • 打赏
  • 举报
回复
你可以试着自己写一个ClassLoader,不过这个方式解决不了文件Class的版本问题,因为虚拟机的这个类空间加载了这个类,在其回收之前,会一直用内存中这个类,而不会去文件中加载。

至于哪个类装载其先装载,这个并不用担心,按照类加载器的双亲委派模型,如果优先级类装载其未能加载类,他会委派给其子类装载器装载,如果出现ClassNotFountException,则说明你没有任何一个类装载其能够装载这个类,或者说能够找到这个类并装载,这不是一个优先级的问题。
wangyeee 2011-02-27
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 spiniper 的回复:]

你可以试着自己写一个ClassLoader,不过这个方式解决不了文件Class的版本问题,因为虚拟机的这个类空间加载了这个类,在其回收之前,会一直用内存中这个类,而不会去文件中加载。

至于哪个类装载其先装载,这个并不用担心,按照类加载器的双亲委派模型,如果优先级类装载其未能加载类,他会委派给其子类装载器装载,如果出现ClassNotFountException,则说明你没有任何一个类装载其……
[/Quote]
感谢你的回答,我明白为什么无法用Instrumentation加载了,对于web项目里面的Java类文件,它们的加载器是org.apache.catalina.loader.WebappClassLoader,我以此调用getParent()方法,得到的父加载器为:
org.apache.catalina.loader.StandardClassLoader
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
而URLClassLoader的父加载器为:
sun.misc.Launcher$AppClassLoader
因此URLClassLoader在本身无法加载的情况下,也无法请求父加载器加载类,就抛出ClassNotFountException了。
而%JRE_HOME%\lib\ext下的类是由sun.misc.Launcher$ExtClassLoader加载的,这也是为什么把jar复制到%JRE_HOME%\lib\ext可以正常加载的原因。
i李小武 2011-02-27
  • 打赏
  • 举报
回复
优先级:启动类加载器,扩展类加载器,classpath类加载器,自定义类加载器
java的安全模式下,采用双亲委派模式加载一个类,当某个对象需要加载一个类的时候,首先请求他的双亲,双亲继续向它的双亲请求...直到根——启动加载器。
如果启动加载器能提供这个类,那么就返回这个类。如果不能,就让请求启动加载器的子加载这个类。。。
如果都不能加载这个类,就用这个对象的自定义类加载器加载这个类。
大_爱 2011-02-26
  • 打赏
  • 举报
回复
看了半天 没理解,如果类加载不对 你加载接口试试嘛
LamFeeling 2011-02-26
  • 打赏
  • 举报
回复
不知道, 帮楼主顶了.

松.

62,616

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧