/tomcat/lib
目录中,我有课程SharedClass
(因此与所有网络应用共享)。WEB-INF/lib
我有课LocalClass
。 SharedClass
引用了LocalClass
。在我的网络应用程序中,我尝试创建SharedClass
的实例,但它失败并显示消息:
NoClassDefFoundError:LocalClass。
由于SharedClass
是共享的,LocalClass
是我的网络应用程序本地的,我希望它可行,但事实并非如此。
我怀疑是SharedClass
是由Tomcat父类加载器加载的,而LocalClass
是由Web App类加载器加载的。由于父SharedClass
已加载,因此我假设所有依赖项也必须由父项加载。因此,父级找不到LocalClass
并且它会抛出错误。
这有意义吗?有没有办法解决这个问题(没有编写我自己的类加载器)?
答案 0 :(得分:7)
ClassLoader是分层的。类加载器具有父级,并查看其父级的类。反之则不然。因此,webapp的类加载器加载的类可以访问由公共Tomcat类加载器(其父级)加载的类,它可以访问JRE类(Tomcat的类加载器的父级)。
有关详细信息,请参阅the Tomcat documentation和ClassLoader javadoc。
答案 1 :(得分:3)
这确实有意义,而且这是Tomcat能够隔离应用程序的方式。可以在此处找到更多信息:http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html
共享类加载应用程序类或创建应用程序类实例的有效原因很少。对于您需要执行此操作的极少数情况,您可以致电Thread.getCurrentThread().getContextClassloader()
。
编辑:我觉得我正在向一个想要开始篝火的人交出一个LOX浸泡的煤球,所以这就是从共享的类加载器加载应用程序类是个坏主意的原因
当前的问题是您实际上没有将类加载到共享类加载器中,因此您无法轻松地操作您创建的对象。相反,您需要使用反射来调用方法,这将使您的代码变得混乱。
但更糟糕的问题是,如果您的SharedClass
实例维护对LocalClass
实例的引用,那么这些引用将阻止Tomcat取消部署应用程序。实际上,它会声称取消部署,但是在收集这些引用之前,仍然会有一些旧的应用程序存在于permgen中,这通常会导致permgen耗尽。
因此,虽然上下文类加载器是一个有用的工具 - 并且应该是唯一方式,您访问类路径资源 - 它是一个很容易导致事情爆炸的工具。
答案 2 :(得分:0)
在普通的Java应用程序中,当要求类加载器加载一个类时,它会将请求委托给它的父类加载器,然后在父类加载器找不到所请求的类时加载它。
对于Web应用程序服务器,这略有不同。对于像tomcat这样的Web应用程序服务器中部署的每个Web应用程序,通常都有不同的类加载器。对于Tomcat,它看起来像下面 -
因此,对于Web应用程序类,加载资源按以下顺序发生 -
但请注意,如果Web应用程序类加载器配置了delegate="true"
,则订单会更改 -
有关详细信息,您可以查看Apache Tomcat的Class Loader HOW-TO页面。