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

发布于 2024-12-03 19:25:30 字数 750 浏览 0 评论 0原文

我正在运行 tomcat 6.0.23,并根据类加载器 文档 webapps 应该按以下顺序查找类:

  1. Bootstrap
  2. System
  3. WEB-INF/classes
  4. WEB-INF/lib
  5. Common

我有一个使用 hibernate 和 hibernate jar 的 web 应用程序位于其 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 目录中找不到他们需要的东西,或者建议一种在运行时调试类路径的方法?

谢谢。

I'm running tomcat 6.0.23, and according to the classloader documentation webapps should look for classes in this order:

  1. Bootstrap
  2. System
  3. WEB-INF/classes
  4. WEB-INF/lib
  5. Common

I have a webapp that uses hibernate and the hibernate jars are in it's WEB-INF/lib directory. When running on it's own, all works fine.

I also have a jar file that needs to sit in the tomcat/lib directory as it contains some classes that need to be loaded on startup (an object factory and the objects it creates). These classes use toplink for their JPA implementation and here is where I get a problem.

I need to put the toplink jars where they can be accessed on tomcat startup, so I've put them in the tomcat/lib directory. According to the order of classloading listed above, when the webapp that uses hibernate wants the hibernate implementation classes, it should find them in it's WEB-INF/lib directory, but what actually happens is it finds the toplink implementation classes from the tomcat/lib directory, and I get a class cast exception.

Can anyone please explain why my webapp class loaders aren't finding what they need in their WEB-INF/lib directory, or suggest a way to debug the classpath at runtime?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

杯别 2024-12-10 19:25:30

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

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

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

编辑:根据您的评论,这只是一个典型的跨类加载器加载问题。 Tomcat 的类加载完全按照您的预期工作。如果您查看进行此初始化的 JPA 类,您会发现如下一行:

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

That loads all PersistenceProviders from all ClassLoaders, include your Toplink one in lib 目录。然后它立即执行此操作:

for ( PersistenceProvider provider : providers ) { ...

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

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

Be sure to read and understand the paragraph preceding the list you quoted:

"When a request to load a class from the web application's WebappX class loader is processed, this class loader will look in the local repositories first, instead of delegating before looking. There are exceptions. Classes which are part of the JRE base classes cannot be overriden. For some classes (such as the XML parser components in J2SE 1.4+), the J2SE 1.4 endorsed feature can be used."

What are these "hibernate implementation classes" that you're having problems with? (Hibernate's "implementation" classes would be completely different from Toplink's.) Are they javax.persistence classes? These may (or may not) fall under the category of "JRE base classes", which behave differently.

Edit: Based on your comment, this is just a typical cross-class-loader loading problem. Tomcat's class loading is working exactly as you expect it to. If you look into the JPA classes where this initialization is going on, you'll find a line like this:

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

That loads all PersistenceProviders from all ClassLoaders, including your Toplink one in the lib directory. It then immediately does this:

for ( PersistenceProvider provider : providers ) { ...

That's on line 77 of javax.persistence.Persistence, where your exception is coming from. That's because the PersistenceProvider class referred to on that line is from your webapp class loader, but the collection contains two instances: your Hibernate implementation from the same class loader and the Toplink one from a different class loader.

This global, static initialization is one major thing that's kept me from shifting to JPA. I still just use straight Hibernate because of problems like this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文