Spring Boot 在 Tomcat 8.5.x 但不在 8.0.37 上运行 java.lang.NoClassDefFoundError: org/apache/coyote/UpgradeP

Posted

技术标签:

【中文标题】Spring Boot 在 Tomcat 8.5.x 但不在 8.0.37 上运行 java.lang.NoClassDefFoundError: org/apache/coyote/UpgradeProtocol【英文标题】:Spring Boot Runs on Tomcat 8.5.x but not 8.0.37 java.lang.NoClassDefFoundError: org/apache/coyote/UpgradeProtocol 【发布时间】:2019-06-12 04:38:46 【问题描述】:

对 Spring 来说相对较新,所以我猜我没有正确地做某事。我一直在将较旧的 java soap 服务转换为 spring。我可以在 tomcat 8.5 及更高版本上本地运行它,但是当我在 tomcat 8.0.37 上运行它时(这是我将部署它的服务器),我收到以下错误。我在另一个项目中遇到了这个错误,但在另一个项目中意识到我不必要地创建了一个 servlet,所以一旦我删除了 servlet 代码,我就可以开始了。在这种情况下,我需要创建一个 servlet。该错误正在寻找不在 Tomcat 8.0.37 中的“org/apache/coyote/UpgradeProtocol”。不确定我的代码中有什么正在尝试使用它。任何建议都非常感谢,谢谢。

pom 中的 Tomcat 依赖项...

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.7.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

错误...

2019-01-17 16:05:12,539 SEVERE Class= org.apache.catalina.core.ContainerBase Method= addChildInternal Message= ContainerBase.addChild: start: org.apache.catalina.LifecycleException:无法启动组件 [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/exampleServices]] 在 org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:162) 在 org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725) 在 org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701) 在 org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717) 在 org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:940) 在 org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1816) 在 java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) 在 java.util.concurrent.FutureTask.run(FutureTask.java:266) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 在 java.lang.Thread.run(Thread.java:745) 原因:org.springframework.beans.factory.BeanCreationException:在类路径资源[com/removed/exampleServices/exampleServicesConfiguration.class]中定义名称为“containerFactory”的bean创建错误:通过工厂方法实例化bean失败;嵌套异常是 org.springframework.beans.BeanInstantiationException:无法实例化 [org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory]:工厂方法 'containerFactory' 抛出异常;嵌套异常是 java.lang.NoClassDefFoundError: org/apache/coyote/UpgradeProtocol 在 org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:591) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1246) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1096) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) 在 org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) 在 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) 在 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) 在 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759) 在 org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) 在 org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:548) 在 org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) 在 org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) 在 org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386) 在 org.springframework.boot.SpringApplication.run(SpringApplication.java:307) 在 org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:157) 在 org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:137) 在 org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:91) 在 org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:172) 在 org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5303) 在 org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)

下面的配置类,我认为问题在于我如何创建我的 TomcatServletWebServerFactory 或我的 ServletRegistrationBean

@ComponentScan("com.example.exampleservices", "com.example.examplesoapservices")
@Configuration
@EnableAWSF
public class exampleservicesConfiguration 


static 
    // Statically initialize SystemImpl so it doesn't slow down first
    // request
    try 
        SystemImpl.getInstance();
     catch (exampleException e) 
        throw new RuntimeException(e);
    


@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) 
    ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new WSSpringServlet(), "/exampleservicesSOAP/*", "/exampleservicesSOAPV3/*");
    //ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new WSSpringServlet(), "/exampleservicesPort/*", "/exampleservicesPortV3/*");
    servletRegistrationBean.setEnabled(true);
    servletRegistrationBean.setLoadOnStartup(0);
    return servletRegistrationBean;



@Bean
@SneakyThrows
public SpringBinding springBinding(exampleservicesSOAPImpl exampleservicesSOAPImpl, AWSFHandlers awsfHandlers) throws Exception 
    SpringBinding springBinding = new SpringBinding();
    springBinding.setUrl("/exampleservicesSOAP");
    SpringService springService = new SpringService();
    springService.setBean(exampleservicesSOAPImpl);
    springService.setHandlers(awsfHandlers.getAwsfHandlers());
    springBinding.setService(springService.getObject());
    return springBinding;


@Bean
@SneakyThrows
public SpringBinding springBindingV3(exampleservicesSOAPV3Impl exampleservicesSOAPV3Impl, AWSFHandlers awsfHandlers) throws Exception 
    SpringBinding springBinding = new SpringBinding();
    springBinding.setUrl("/exampleservicesSOAPV3");
    SpringService springService = new SpringService();
    springService.setBean(exampleservicesSOAPV3Impl);
    springService.setHandlers(awsfHandlers.getAwsfHandlers());
    springBinding.setService(springService.getObject());
    return springBinding;


@Bean
public Executor threadPoolTaskExecutor()
    return new ThreadPoolTaskExecutor();


@Bean
public TomcatServletWebServerFactory  containerFactory() 
    return new TomcatServletWebServerFactory () 
        protected void customizeConnector(Connector connector) 
            super.customizeConnector(connector);
        
    ;


@Bean
public Jaxb2Marshaller jaxb2Marshaller() 
    Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
    jaxb2Marshaller.setContextPath(exJAXBContext.JAXB_CONTEXT_PATH);
    return jaxb2Marshaller;


@Bean
private static JAXBContext initContext() 
    try 
        return JAXBContext.newInstance(BasicServiceComponents.eesvcof.getClass().getPackage().getName() + ":" + BasicServiceComponents.eesvcofV3.getClass().getPackage().getName());
     catch (JAXBException e) 
        e.printStackTrace();
        return null;
    




private static final JAXBContext context = initContext();

@Bean
public Marshaller marshaller() 
    Marshaller marshaller = null;
    try 
        marshaller = this.context.createMarshaller();
     catch (JAXBException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    
    //any setters
    return marshaller;


@Bean
public Unmarshaller unmarshaller() 
    Unmarshaller unmarshaller = null;
    try 
        unmarshaller = this.context.createUnmarshaller();
     catch (JAXBException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    
    //any setters
    return unmarshaller;

【问题讨论】:

【参考方案1】:

嗯,很可能是因为 Spring Boot 2.0 系列需要 release note 中提到的 Tomcat 8.5。 UpgradeProtocol 与 HTTP2 相关,在 Tomcat 8.0 中不存在,所以最好的办法是尝试在 application.properties 中禁用 HTTP2:

server.http2.enabled=false

【讨论】:

【参考方案2】:

所以被破坏的代码是

 @Bean
 public TomcatServletWebServerFactory  containerFactory() 
     return new TomcatServletWebServerFactory () 
         protected void customizeConnector(Connector connector) 
             super.customizeConnector(connector);
         
     ;
 

当我在评论之前进行测试时,当我在本地运行时,我会得到一个不同的错误。与我一起工作的人建议删除这个 bean(我猜 spring 2 不需要它),并且还删除了我指定 tomcat 版本的 pom 代码。这行得通。所以本地春天正在管理我的Tomcat版本。我相信 spring 将 Tomcat 设置为 8.5.35 以用于 spring 2.0.7 版本。当我部署我的代码时,它现在在 Tomcat 8.0.35 上运行良好。所以你不需要那个bean,在本地运行时让spring设置你自己的Tomcat版本。我不确定为什么该 bean 可以在 Tomcat 8.5.35 上运行,但无论如何我都不需要它。

【讨论】:

以上是关于Spring Boot 在 Tomcat 8.5.x 但不在 8.0.37 上运行 java.lang.NoClassDefFoundError: org/apache/coyote/UpgradeP的主要内容,如果未能解决你的问题,请参考以下文章

spring boot 集成 hbase

如何更改现有 Spring Boot 应用程序中的嵌入式 tomcat 版本?

Spring Boot 打war包并利用docBase指定根目录为打包的工程

Spring Boot配置Tomcat

在 Tomcat 上使用 Spring Boot 进行身份验证

Spring Boot启动过程:Spring Boot内嵌Tomcat启动