首页 > 解决方案 > java.lang.NoSuchMethodError 因为 Tomcat 的 lib 文件夹中有重复的类

问题描述

我面对

java.lang.NoSuchMethodError:javax.persistence.PersistenceContext.synchronization()Ljavax/persistence/SynchronizationType

在 Tomcat 8 中部署我的应用程序时,因为 tomcat 类加载器正在从位于 TOMCAT_HOME\lib 文件夹的 annotations-api.jar 文件中加载 PersistenceContext 类,而 annotations-api.jar 中的 PersistenceContext 类不包含如下同步方法

package javax.persistence;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PersistenceContext {
  String name() default "";

  String unitName() default "";

  PersistenceContextType type() default PersistenceContextType.TRANSACTION;

  PersistenceProperty[] properties() default {};
}

虽然我希望 tomcat 从 javax.persitence-api-2.2 jar 加载 PersistenceContext 类,但我已将其复制到 TOMCAT_HOME\lib 文件夹而不是 TOMCAT_HOME\lib 文件夹中的 annotations-api.jar,因为来自 javax.persitence-api-2.2 的 PersistenceContext 类jar包含同步方法如下

package javax.persistence;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Repeatable(PersistenceContexts.class)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PersistenceContext {
  String name() default "";

  String unitName() default "";

  PersistenceContextType type() default PersistenceContextType.TRANSACTION;

  SynchronizationType synchronization() default SynchronizationType.SYNCHRONIZED;

  PersistenceProperty[] properties() default {};
}

这样tomcat 在部署我的应用程序时不会给出java.lang.NoSuchMethodError: javax.persistence.PersistenceContext.synchronization()Ljavax/persistence/SynchronizationType 。

如何在 Tomcat 8 中给予优先权,以便 Tomcat 8 从 javax.persistence-api-2.2.jar 而不是 annotations-api.jar 加载 PersistenceContext 类?

编辑:Tomcat 8 lib 文件夹已经包含 annotations-api.jar 并且我已经将 javax.persistence-api-2.2.jar 复制到 Tomcat 的 lib 文件夹中,以便在 Tomcat 8 中支持 eclipselink,因此在我的 dependencies.gradle 中排除 annotations-api.jar 选项不会有帮助,因为 annotations-api.jar 已经是 Tomcat 的 lib 文件夹的一部分。我还没有自己添加 annotations-api.jar。

注意:同一应用程序正在 Tomcat 9 中运行文件,因为 Tomcat 9 中的 annotations-api.jar 不包含 javax.persistence 包。

标签: javaspringtomcatclassloadertomcat8

解决方案


尝试在项目中添加 javax.persistence-api-2.2.jar 作为依赖项并将其从 tomcat lib 中删除,原因是如果 web 应用程序的 /WEB-INF/lib/*.jar 将首先加载应用程序类加载器未配置为 delegate="true

正常顺序:

  1. JVM 的引导类(核心 java 类)
  2. /WEB-INF/Web 应用程序的类
  3. /WEB-INF/lib/*.jar 您的 Web 应用程序
  4. 系统类加载器类(Tomcat / Classpath 特定类)
  5. 通用类加载器类(所有 Web 应用程序通用的类)

使用delegate="true " 然后订购:

  1. JVM 的引导类(核心 java 类)
  2. 系统类加载器类(Tomcat / Classpath 特定类)
  3. 通用类加载器类(所有 Web 应用程序通用的类)
  4. /WEB-INF/Web 应用程序的类
  5. /WEB-INF/lib/*.jar 您的 Web 应用程序

推荐阅读