Tomcat类加载似乎没有记录的行为

时间:2011-09-07 16:08:20

标签: java tomcat

我正在运行tomcat 6.0.23,并且根据类加载器documentation,webapps应按此顺序查找类:

  1. 自举
  2. 系统
  3. WEB-INF /类
  4. WEB-INF / lib中
  5. 通用
  6. 我有一个使用hibernate的webapp,而hibernate jar在它的WEB-INF / lib目录中。当它自己运行时,一切正常。

    我还有一个需要位于tomcat / lib目录下的jar文件,因为它包含一些需要在启动时加载的类(对象工厂及其创建的对象)。这些类使用toplink进行JPA实现,这就是我遇到问题的地方。

    我需要将toplink jar放在tomcat启动时可以访问它们的位置,所以我把它们放在tomcat / lib目录中。根据上面列出的类加载顺序,当使用hibernate的webapp需要hibernate实现类时,它应该在它的WEB-INF / lib目录中找到它们,但实际发生的是它从tomcat / lib中找到toplink实现类。目录,我得到一个类强制转换异常。

    有谁能解释为什么我的webapp类加载器没有在WEB-INF / lib目录中找到他们需要的东西,或者建议在运行时调试类路径的方法?

    感谢。

1 个答案:

答案 0 :(得分:4)

请务必阅读并理解您引用的列表前面的段落:

“当处理从Web应用程序的WebappX类加载器加载类的请求时,此类加载器将首先查看本地存储库,而不是在查看之前委托。有例外。类是JRE基础的一部分对于某些类(例如J2SE 1.4+中的XML解析器组件),可以使用J2SE 1.4认可的功能。“

您遇到问题的这些“hibernate实现类”是什么? (Hibernate的“实现”类与Toplink完全不同。)它们是javax.persistence类吗?这些可能(或可能不属于)“JRE基类”的类别,其行为有所不同。

编辑:根据您的评论,这只是典型的跨类加载器加载问题。 Tomcat的类加载完全按照您的预期工作。如果您查看正在进行此初始化的JPA类,您将找到如下所示的行:

Enumeration<URL> resources =
    cl.getResources("META-INF/services/" + PersistenceProvider.class.getName());

所有 ClassLoader加载所有 PersistenceProviders,包括lib目录中的Toplink。然后立即这样做:

for ( PersistenceProvider provider : providers ) { ...

这是javax.persistence.Persistence的第77行,你的异常来自。这是因为该行引用的PersistenceProvider类来自您的webapp类加载器,但该集合包含两个实例:来自同一类加载器的Hibernate实现和来自不同类加载器的Toplink实现。

这种全局的静态初始化是让我无法转向JPA的一件大事。我仍然只是使用直接Hibernate,因为这样的问题。