【问题标题】:Spring Boot 2 war file attempts to load el-api v3.0 class (NoClassDefFoundError: javax/el/ELManager) on tomcat 7 (el-api 2.2)Spring Boot 2 war 文件尝试在 tomcat 7 (el-api 2.2) 上加载 el-api v3.0 类 (NoClassDefFoundError: javax/el/ELManager)
【发布时间】:2018-11-03 02:31:36
【问题描述】:

我有一个 Spring boot 2 gradle 项目,我希望将其作为(不可执行的)war 文件部署到 tomcat 7 实例 (RHEL)。

在将战争部署到服务器上的 tomcat 时,我收到了 NoClassDefFoundError

...
Caused by: org.hibernate.cfg.beanvalidation.IntegrationException: Error activating Bean Validation integration
        at org.hibernate.cfg.beanvalidation.BeanValidationIntegrator.integrate(BeanValidationIntegrator.java:138)
        at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:281)
        at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:892)
        at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390)
        ... 34 more
Caused by: java.lang.NoClassDefFoundError: javax/el/ELManager
        at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:88)
        at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:47)
        at org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultMessageInterpolator(ConfigurationImpl.java:474)
        at org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultMessageInterpolatorConfiguredWithClassLoader(ConfigurationImpl.java:650)
        at org.hibernate.validator.internal.engine.ConfigurationImpl.getMessageInterpolator(ConfigurationImpl.java:397)
        at org.hibernate.validator.internal.engine.ValidatorFactoryImpl.<init>(ValidatorFactoryImpl.java:183)
        at org.hibernate.validator.HibernateValidator.buildValidatorFactory(HibernateValidator.java:38)
        at org.hibernate.validator.internal.engine.ConfigurationImpl.buildValidatorFactory(ConfigurationImpl.java:364)
        at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:103)
        at org.hibernate.cfg.beanvalidation.TypeSafeActivator.getValidatorFactory(TypeSafeActivator.java:501)
        at org.hibernate.cfg.beanvalidation.TypeSafeActivator.activate(TypeSafeActivator.java:84)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.hibernate.cfg.beanvalidation.BeanValidationIntegrator.integrate(BeanValidationIntegrator.java:132)
        ... 40 more

经过检查,我发现休眠 bean 验证库在初始化期间未能找到这个特定的类 (javax.el.ElManager)。

解决方案here 建议将正确的 el-api v3.0 依赖项添加到运行时,但我不确定这是一个明智的解决方案,因为 el-api v2.2 已经存在于共享 (providedRuntime Tomcat 中的 gradle 白话)库。如果我有相同 API 的 2 个版本,我会担心 ClassLoader 问题(这是一个合理的担忧吗?)。

升级到 tomcat 8 是不行的,因为我们在 RHEL 上运行 tomcat7,而目前只支持 tomcat 7。

如何让 Spring 使用 javax el-api v2.2?

补充说明

根据gradlew dependencies命令,依赖spring-boot-starter-tomcat时默认的tomcat.version似乎是8.5.31

+--- org.springframework.boot:spring-boot-starter-tomcat:2.0.2.RELEASE
|    +--- javax.annotation:javax.annotation-api:1.3.2
|    +--- org.apache.tomcat.embed:tomcat-embed-core:8.5.31
|    +--- org.apache.tomcat.embed:tomcat-embed-el:8.5.31
|    \--- org.apache.tomcat.embed:tomcat-embed-websocket:8.5.31

据我从another post 了解到,将 gradle ext['tomcat.version'] 属性设置为 7.0.76(我们的服务器版本)可以正确解决这些依赖关系:

+--- org.springframework.boot:spring-boot-starter-tomcat:2.0.2.RELEASE
|    +--- javax.annotation:javax.annotation-api:1.3.2
|    +--- org.apache.tomcat.embed:tomcat-embed-core:8.5.31 -> 7.0.76
|    +--- org.apache.tomcat.embed:tomcat-embed-el:8.5.31 -> 7.0.76
|    \--- org.apache.tomcat.embed:tomcat-embed-websocket:8.5.31 -> 7.0.76
|         \--- org.apache.tomcat.embed:tomcat-embed-core:7.0.76

但是我还是遇到了这个NoClassDefFoundError。在我看来,Spring 无法识别正确的 api 版本并继续假设存在 ElManager

感谢您的宝贵时间。

【问题讨论】:

    标签: spring-boot gradle tomcat7


    【解决方案1】:

    Spring Boot 2.X 仅支持 Tomcat >= 8.5.X

    在尝试修改默认 spring 配置(即hibernate-validator)的传递依赖项后,我遇到了 Spring Boot 2 的minimum server requirements 的文档:Tomcat 8.5.X。除此之外,只有 3.1+ 的 servlet API are supported

    我在这里要解决的根本问题——如果我更改依赖项无疑会产生问题——是 Spring Boot 2 不支持 Tomcat 7。我降级的任何传递库都可能会破坏其他一些需要更新功能的依赖项。

    Spring Boot 1.5.X does however support Tomcat 7 and Servlet 3.0 应用服务器。所以解决方案是降级到 Spring Boot 1.5.X(在撰写本文时当前为 1.5.13)。

    或者 - 我将在我的工作场所与系统团队一起推动的解决方案 - 改为使用嵌入式 servlet 容器(即嵌入的 tomcat 8.5/9)。对我来说不幸的是,这意味着对假设部署机制的现有企业流程的修改进行长时间的讨论。但这不是重点:P

    【讨论】:

    • 你拯救了我的一天!!,顺便说一句,你有没有其他方法让它只在 tomcat 7 中工作?
    猜你喜欢
    • 2018-08-29
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    • 2021-08-23
    • 2022-01-05
    • 1970-01-01
    相关资源
    最近更新 更多