【问题标题】:JPA/EclipseLink: Understanding ClassLoader issuesJPA/EclipseLink:了解 ClassLoader 问题
【发布时间】:2016-08-21 12:27:32
【问题描述】:

编辑:虽然给出并授予了(好的)答案,但这仅涵盖了我的问题中相当不重要的部分。这个问题的主要部分仍然悬而未决。

我在一个云项目中使用 EclipseLink (2.6.2)。该项目是一个打包为WAR 文件并部署在Apache Tomcat 8 上的Web 应用程序。持久性上下文是使用Java 代码设置的,其中我使用entityManagerFactoryBean.setPackagesToScan(packagesToScan) 指定要使用的实体。此配置通常按预期工作,在其中找到指定包中的实体类。

我现在无法理解何时使用哪个类加载器,尤其是在考虑 Tomcat、运行测试和使用不同的连接池实现时。

在包括 Tomcat 连接池的 Apache Tomcat 上运行时,DataSource 实例是使用 spring-cloud-connector 插件 (spring-cloud-spring-service-connector) 创建的。 在此设置中,只要我不按如下所述更改类加载器,一切都会按预期工作(否则我将面对实体类的ClassNotFoundExceptions)。

JUnitspring-test 的帮助下运行单元测试时,DataSource 实例是使用内存数据库 H2 创建的(使用来自spring-jdbcEmbeddedDatabaseBuilder)。在此设置中,我必须指定 JPA 以使用用于 DataSource 实例的类加载器(JPA 属性映射中的键 eclipselink.classloader),否则我会得到“Object ... is not a known Entity type”。

在嵌入式 Apache Tomcat 8 中运行测试时,我没有看到任何指示正在使用的连接池的消息。在此设置中,我还必须将类加载器设置为单元测试。

如果我将commons-dbcp (2.1.1) 添加到我的项目并显式配置spring-cloud-connector 插件以使用它而不是Tomcat 的连接池,我可以在不配置类加载器的情况下在Tomcat 上运行应用程序,但它也可以工作使用上述类加载器规范。

对于测试,commons-dbcp 与上述场景相比没有任何变化(因为未使用相应的配置)。

总结:

  • Tomcat (Tomcat CP):仅使用未修改的 JPA 类加载器
  • Tomcat (DBCP):两种变体
  • 测试:仅使用 DataSource 的 JPA 类加载器

您能帮我理解这里的区别,并提出一个适用于所有情况的简单解决方案吗?我假设 DBCP 和 Spring 使用与 Tomcat(和 Tomcat 的连接池)不同的类加载器。

如果您需要更多信息,我很乐意添加。

编辑:我添加了一个示例项目,其中包含有关如何重现的大型 README。

https://github.com/C-Otto/classloaderexample

【问题讨论】:

  • 我不明白你的问题。您的问题混合了数据源、连接池和服务发现 (spring-cloud-service-*)。我认为您最好使用 github 中的简单项目创建案例研究并在此处询问您的确切问题。
  • @xsalefter 我添加了一个带有一些文档的示例项目。谢谢你的建议。
  • 刚刚发现为什么你的 tomcat:run 不能与你的 CloudDatabaseConfig 一起工作。您需要在 tomcat7-maven-plugin 上配置 postgresql 依赖项。我现在会尝试找到其他错误。
  • @fhofmann 实际上它可以工作,只是不是在所有配置变体中。 “配置postgresql依赖”是什么意思?

标签: java jpa eclipselink classloader apache-commons-dbcp


【解决方案1】:

“当我开始使用 mvn tomcat7 时出现另一个错误:运行,使用 Tomcat 的 连接池 (CloudDatabaseConfig) 并且不要重新配置 类加载器(JpaConfig):“

您必须在 maven 插件上配置 PostreSQL 依赖项。你得到 ClassNot found 因为 PostgreSQL JAR 不在路径中:

<plugin>
  <groupId>org.apache.tomcat.maven</groupId>
  <artifactId>tomcat7-maven-plugin</artifactId>
  <version>2.2</version>
  <configuration>
    <port>8080</port>
    <path>/</path>
  </configuration>
  <!-- For any extra dependencies needed when running embedded Tomcat (not WAR dependencies) add them below -->
  <dependencies>
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>9.4-1206-jdbc41</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</plugin>

也可以看看https://tomcat.apache.org/maven-plugin-2.2/run-mojo-features.html

我忘记在 (JpaConfigWithDatasourceClassloader.getJPAProperties) 上包含类加载器更改:

properties.put(CLASSLOADER, new java.net.URLClassLoader(
   ((java.net.URLClassLoader)classLoader).getURLs(), JpaConfigWithDatasourceClassloader.class.getClassLoader()  ) 
) ;

有了这个,您可以使用tomcat7:run 运行所有变体

【讨论】:

  • 谢谢,我不知道插件依赖。我在你的答案中添加了一些信息,这真的很有帮助。对于类加载器问题:对我来说,您的 sn-p 似乎只是显示了一种配置 JPA 使用的类加载器的不同方式。我仍然不明白为什么这个配置是必要的,以及为什么它会根据连接池和启动/测试设置引起问题。
  • 我不是 Tomcat 类加载器方面的专家,但查看代码我想数据源是使用容器类加载器加载的,而您的实体是使用应用程序类加载器加载的。如果您将容器类加载器传递给 JPA,它不会看到您在战争中拥有的分类。
  • DataSource 对象是在我的应用程序内部构造的,所以不能这样。但是很可能连接池实现是使用另一个类加载器创建的,这会导致问题。
猜你喜欢
  • 2018-09-15
  • 1970-01-01
  • 1970-01-01
  • 2014-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
  • 1970-01-01
相关资源
最近更新 更多