java - Tomcat 类加载的行为似乎与记录的不符

标签 java tomcat

我运行的是tomcat 6.0.23,根据类加载器documentation webapps 应按以下顺序查找类:

  1. Bootstrap
  2. 系统
  3. WEB-INF/类
  4. WEB-INF/lib
  5. 常见

我有一个使用 hibernate 的 web 应用程序,hibernate jar 位于它的 WEB-INF/lib 目录中。单独运行时,一切正常。

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

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

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

谢谢。

最佳答案

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

“当处理从 Web 应用程序的 WebappX 类加载器加载类的请求时,该类加载器将首先在本地存储库中查找,而不是在查找之前进行委托(delegate)。也有异常(exception)。属于 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());

这会从所有类加载器加载所有 PersistenceProvider,包括lib目录中的Toplink。然后它立即执行此操作:

for ( PersistenceProvider provider : providers ) { ...

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

这种全局静态初始化是阻止我转向 JPA 的一大原因。由于这样的问题,我仍然直接使用 Hibernate。

关于java - Tomcat 类加载的行为似乎与记录的不符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7337046/

相关文章:

java - 在桌面应用程序和远程服务器之间创建安全连接?

java - 具有阻塞应用程序的 Tomcat NIO 连接器

Java:我丢失了 session :使用 "<a href >"会出现问题吗?

java - 在 Java 中,对于字符串 x,s.length() 的运行时成本是多少?是 O(1) 还是 O(n)?

java - 具有过滤功能的巨大排行榜排名

java - android,如何从内存中的位图/可绘制对象获取资源标识符?

shell - Tomcat 即服务

tomcat - Spring Boot 排除 Tomcat 依赖

java - 使用 Cloudflare 进行 Tomcat/TomEE SSL 配置

java - 顺时针旋转给定的字符串布局