【问题标题】:Spring Boot War deployed to TomcatSpring Boot War 部署到 Tomcat
【发布时间】:2015-03-10 08:57:17
【问题描述】:

我正在尝试将 Spring Boot 应用程序部署到 Tomcat,因为我想部署到 AWS。 我创建了一个 WAR 文件,但它似乎无法在 Tomcat 上运行,即使它是可见的。

详情:
0. 这是我的应用程序:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class App {
    public static void main(String[] args) {
        SpringApplication.run(SampleController.class, args);
    }
}

@Controller
@EnableAutoConfiguration
public class SampleController {
    @RequestMapping("/help")
    @ResponseBody
    String home() {
        String input = "Hi! Please use 'tag','check' and 'close' resources.";
        return input;
    }
}

application.properties 有以下内容:

server.port=${port:7777}
  1. 在阅读了一些pagesquestion-answers 之后,我在我的POM 中添加了以下内容:

    http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0

    <groupId>com.niewlabs</groupId>
    <artifactId>highlighter</artifactId>
    <version>1.0-SNAPSHOT</version>
    
    <packaging>war</packaging>
    
    <properties>
        <java.version>1.8</java.version>
    </properties>    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    

  2. 我运行“mvn package”并得到了 WAR 文件(大小 250Mb),我将其放入“webapps”文件夹中。

  3. 我启动了 Tomcat,并且能够看到我的应用程序已列出,在我的例子中是“/highlighter-1.0-SNAPSHOT”。
  4. 单击应用程序的链接会导致“状态 404”页面。
  5. 当我单独运行 Spring Boot 应用程序时,没有容器它在 localhost:7777 上运行,但是当我在 Tomcat 中运行它时什么都没有。

更新: 还有一个reference。不确定它有多大用处。

【问题讨论】:

  • 您是否扩展了SpringBootServletInitializer 并覆盖了它的configure 方法?
  • 不,我在 Spring Guide WAR 说明中没有看到任何提及。可以给我一个链接或详细信息吗?
  • @AndyWilkinson 谢谢你的提示。我在 Spring Guide [docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/….但我的应用仍然无法在 Tomcat 上运行。
  • 我遵循了文档的所有步骤,但仍然得到 404 。从 tomcat localhost 日志中,似乎已检测到应用程序。 09-Nov-2019 11:19:59.676 INFO [main] org.apache.catalina.core.ApplicationContext.log 1 Spring WebApplicationInitializers detected on classpath 09-Nov-2019 11:20:12.722 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: contextInitialized()
  • @AjayYadav 你是怎么解决的?

标签: spring maven tomcat spring-boot


【解决方案1】:

TL;DR:

  • 确保您的应用程序依赖项和外部 Tomcat 安装中具有相同的 Tomcat 版本
  • 具有相同的 Java 版本

我已按照所有步骤制作 Spring Boot 应用程序以生成与外部 Tomcat 服务器兼容的 WAR。我也扩展了SpringBootServletInitializer。如果您还没有这样做,请首先按照其他答案或Official Spring Docs - Traditional Deployment

中的说明进行这些更改

该应用在 STS Embedded Tomcat 上运行良好,但会给出 404 - Not Found in the external Tomcat。没有错误,catalina.bat run 命令也给出了“部署战争完成”的信息。

14-Apr-2021 12:38:01.996 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
14-Apr-2021 12:38:01.996 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.0.5]
14-Apr-2021 12:38:02.023 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [C:\dev\apache-tomcat-10.0.5\webapps\server-test-1-0.0.1-SNAPSHOT.war]
14-Apr-2021 12:38:05.349 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
14-Apr-2021 12:38:05.436 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [C:\dev\apache-tomcat-10.0.5\webapps\server-test-1-0.0.1-SNAPSHOT.war] has finished in [3,413] ms

但通常情况下,SpringBoot 相关的输出(如Initializing Spring DispatcherServlet 'dispatcherServlet')也应该出现在这个 Catalina 控制台上。但这并没有出现。

我的问题是: 我的 Maven 依赖文件夹中有 tomcat-embed-core-9.0.44。但我已经在我的机器上安装了独立的 Tomcat 版本 10.x.xx。

我在我的机器上安装了 Tomcat 版本 9.0.xx,应用程序运行良好。

【讨论】:

    【解决方案2】:

    如果您要创建新应用而不是转换现有应用,创建基于 WAR 的 Spring Boot 应用最简单的方法是通过Spring Initializr

    它会自动为您生成应用程序。默认情况下它会创建 Jar,但在高级选项中,您可以选择创建 WAR。这场战争也可以直接执行。

    更简单的是直接从 IntelliJ IDEA 创建项目:

    文件→新建项目→Spring Initializr

    【讨论】:

      【解决方案3】:

      使用 Spring Boot 1.5.8.RELEASE 更新 2018-02-03。

      在 pom.xml 中,你需要在构建时告诉 Spring 插件它是一个 war 文件,方法是将包更改为 war,如下所示:

      <packaging>war</packaging>
      

      此外,您必须在构建包时通过添加以下内容排除嵌入式 tomcat:

          <!-- to deploy as a war in tomcat -->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-tomcat</artifactId>
              <scope>provided</scope>
          </dependency>
      

      完整的可运行示例在这里https://www.surasint.com/spring-boot-create-war-for-tomcat/

      【讨论】:

      • 这还不够。主应用程序类必须实现 SpringBootServletInitializer 以兼容容器和独立执行。 Op 的示例缺少它。
      【解决方案4】:

      使用 Gradle 的人的解决方案

      将插件添加到build.gradle

      apply plugin: 'war'
      

      添加 provided 对 tomcat 的依赖

      dependencies {
          // other dependencies
          providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
      }
      

      【讨论】:

        【解决方案5】:

        我遇到了同样的问题,我通过关注guide 找到了解决方案。我在 Maven 中带着目标奔跑。

        干净的包装

        Thanq 对我有用

        【讨论】:

          【解决方案6】:

          请确保对 pom.xml 进行此更改

          <packaging>war</packaging>
          

          在依赖项部分确保指明提供了 tomcat,这样您就不需要嵌入的 tomcat 插件。

              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-tomcat</artifactId>
                  <scope>provided</scope>
              </dependency>       
          
              <dependency>
                  <groupId>org.apache.tomcat.embed</groupId>
                  <artifactId>tomcat-embed-jasper</artifactId>
                  <scope>provided</scope>
              </dependency>       
          

          这是整个 pom.xml

          <?xml version="1.0" encoding="UTF-8"?>
          <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
              <modelVersion>4.0.0</modelVersion>
          
              <groupId>com.example</groupId>
              <artifactId>demo</artifactId>
              <version>0.0.1-SNAPSHOT</version>
              <packaging>war</packaging>
          
              <name>demo</name>
              <description>Demo project for Spring Boot</description>
          
              <parent>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-parent</artifactId>
                  <version>1.4.0.RELEASE</version>
                  <relativePath/> <!-- lookup parent from repository -->
              </parent>
          
              <properties>
                  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
                  <java.version>1.8</java.version>
                  <start-class>com.example.Application</start-class>
              </properties>
          
              <dependencies>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-web</artifactId>
                  </dependency>
          
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-test</artifactId>
                      <scope>test</scope>
                  </dependency>
          
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-tomcat</artifactId>
                      <scope>provided</scope>
                  </dependency>       
          
                  <dependency>
                      <groupId>org.apache.tomcat.embed</groupId>
                      <artifactId>tomcat-embed-jasper</artifactId>
                      <scope>provided</scope>
                  </dependency>       
          
              </dependencies>
          
              <build>
                  <plugins>
                      <plugin>
                          <groupId>org.springframework.boot</groupId>
                          <artifactId>spring-boot-maven-plugin</artifactId>
                      </plugin>
                  </plugins>
              </build>
          
          
          </project>
          

          而Application类应该是这样的

          Application.java

          package com.example;
          
          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.autoconfigure.SpringBootApplication;
          import org.springframework.boot.builder.SpringApplicationBuilder;
          import org.springframework.boot.web.support.SpringBootServletInitializer;
          
          @SpringBootApplication
          public class Application extends SpringBootServletInitializer {
          
          
              /**
               * Used when run as JAR
               */
              public static void main(String[] args) {
                  SpringApplication.run(Application.class, args);
              }
          
              /**
               * Used when run as WAR
               */
              @Override
              protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
                  return builder.sources(Application.class);
              }
          
          }
          

          你可以添加一个控制器来测试 MyController.java

          package com.example;
          
          import org.springframework.stereotype.Controller;
          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.ResponseBody;
          
          @Controller
          public class MyController {
          
              @RequestMapping("/hi")
              public @ResponseBody String hiThere(){
                  return "hello world!";
              }
          }
          

          然后就可以在tomcat 8版本中运行项目,像这样访问控制器

          http://localhost:8080/demo/hi

          如果由于某种原因您无法将项目添加到 tomcat,请在项目中单击鼠标右键,然后转到构建路径->配置构建路径->项目面

          确保只选择这 3 个

          动态网络模块 3.1 Java 1.8 Javascript 1.0

          【讨论】:

            【解决方案7】:

            公共类应用扩展 SpringBootServletInitializer {}

            只是扩展了 SpringBootServletInitializer。它可以在你的 AWS/tomcat 中运行

            【讨论】:

            • 您能否澄清您的答案带来了什么,而您的答案在您之前 3 小时发布的答案或 2015 年接受的答案中均未涵盖?
            【解决方案8】:

            您的 Application.java 类应该扩展 SpringBootServletInitializer 类 例如:

            public class Application extends SpringBootServletInitializer {}
            

            【讨论】:

              【解决方案9】:

              按照指南(或使用 Spring Initializr)后,我有一个 WAR 可以在我的本地计算机上运行,​​但不能远程运行(在 Tomcat 上运行)。

              没有错误信息,只是说“找到了 Spring servlet 初始化程序”,但什么也没做。

              17-Aug-2016 16:58:13.552 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.4
              17-Aug-2016 16:58:13.593 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive /opt/tomcat/webapps/ROOT.war
              17-Aug-2016 16:58:16.243 INFO [localhost-startStop-1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
              

              17-Aug-2016 16:58:16.301 INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log 2 Spring WebApplicationInitializers detected on classpath
              17-Aug-2016 16:58:21.471 INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log Initializing Spring embedded WebApplicationContext
              17-Aug-2016 16:58:25.133 INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log ContextListener: contextInitialized()
              17-Aug-2016 16:58:25.133 INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log SessionListener: contextInitialized()
              

              没有其他事情发生。 Spring Boot 只是没有运行。

              显然我用 Java 1.8 编译了服务器,而远程计算机有 Java 1.7。

              用 Java 1.7 编译后,它开始工作了。

              <properties>
                  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
                  <java.version>1.7</java.version> <!-- added this line -->
                  <start-class>myapp.SpringApplication</start-class>
              </properties>
              

              【讨论】:

                【解决方案10】:

                我认为您对这里的不同范例感到困惑。首先,war 文件和服务器部署——这些东西属于 Java Enterprise Edition (Java EE)。这些概念在遵循不同模型的 spring-boot 应用程序中没有真正的位置。

                Spring-boot 负责创建一个嵌入式容器并直接从标准 jar 文件在其中运行您的服务(尽管它可以做更多事情)。我认为这个模型的目的是支持微服务开发——每个服务都有自己的容器并且是完全自包含的。您也可以使用您的代码生成 Java EE 应用程序,但考虑到 spring-boot 更容易(对于某些类型的应用程序/服务),这将是愚蠢的。

                因此,鉴于这些信息,您现在必须决定要遵循的范式,并且您需要遵循并且仅此而已。

                Spring-boot 是可执行的——您只需在 App 类中运行 main 方法,您可以从命令行或使用您最喜欢的 IDE 或 maven 或 gradle 来执行此操作(提示:maven 是正确的答案)。这将打开一个 tomcat 服务器(默认情况下),您的服务将在其中可用。鉴于您在服务上方发布的配置应该在以下位置可用:http://localhost:7777/context/help - context 旨在替换为您尚未共享的上下文名称。

                您并不是要制造战争、运行 tomcat 或部署任何东西。在 spring-boot 中这些都不是必需的。你的 pom 中的包装应该是jar,而不是war,并且应该删除spring-boot-starter-tomcat 中的scope——它肯定没有提供。

                当你运行你的 main 方法时,控制台输出应该告诉你你已经注册的上下文;使用它来获取正确的 URL。

                说了这么多,spring-boot 现在必须存在于 JEE 世界中(直到它被广泛采用)。出于这个原因,spring 人员记录了一种构建战争而不是可执行 jar 的方法,用于部署到 servlet 或 JEE 容器。这允许在限制使用除战争(或耳朵)之外的任何东西的环境中使用许多 spring-boot 技术。然而,这只是对这样一个事实的回应,即此类环境非常普遍,并且不被视为解决方案的必要部分,甚至是不可取的部分。

                【讨论】:

                • 我很想避免部署到 Tomcat,但这似乎是将我的应用程序部署到 AWS 的最简单和最简单的方法。
                • 不,使用 spring-boot 和 docker——这是在任何地方部署的最简单方法,包括 AWS(相信我——我是根据经验说话)
                • 我不认为这是完全正确的。 Spring Boot 确实允许将 war 文件部署到容器中。但是对于大多数用例来说它是正确的。所以我很想对这个问题投反对票和赞成票。见docs.spring.io/spring-boot/docs/current/reference/html/…
                • 如果你已经有一堆现有的经典spring应用在tomcat上运行,spring boot war文件部署是一个很好的开始使用spring boot的方法,一次不用做太多改动。
                【解决方案11】:

                如果您的目标是将 Spring Boot 应用程序部署到 AWSBoxfuse 为您提供了一个非常简单的解决方案。

                您需要做的就是:

                boxfuse run my-spring-boot-app-1.0.jar -env=prod
                

                这将:

                • 融合为您的应用量身定制的最小操作系统映像(比典型的 Linux 发行版小约 100 倍)
                • 将其推送到安全的在线存储库
                • 在大约 30 秒内将其转换为 AMI
                • 创建和配置新的弹性 IP 或 ELB
                • 为其分配一个新域名
                • 根据您的新 AMI 启动一个或多个实例

                所有图像都在几秒钟内生成并且是不可变的。它们可以在 VirtualBox (dev) 和 AWS (test & prod) 上原封不动地运行。

                所有更新都以零停机蓝/绿部署的形式执行,您还可以通过一个命令启用自动缩放。

                Boxfuse 还了解您的 Spring Boot 配置将根据您的 application.properties自动配置安全组和 ELB 健康检查。

                以下是帮助您入门的教程:https://boxfuse.com/getstarted/springboot

                免责声明:我是 Boxfuse 的创始人兼 CEO

                【讨论】:

                  【解决方案12】:

                  本指南详细解释了如何在 Tomcat 上部署 Spring Boot 应用程序:
                  http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-create-a-deployable-war-file

                  基本上我需要添加以下类:

                  public class WebInitializer extends SpringBootServletInitializer {   
                      @Override
                      protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
                          return application.sources(App.class);
                      }    
                  }
                  

                  我还向 POM 添加了以下属性:

                  <properties>        
                      <start-class>mypackage.App</start-class>
                  </properties>
                  

                  【讨论】:

                  • 我会更新对以下内容的引用 - docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…“将 jar 转换为战争 maven”部分仅在您的参考中指向嵌入式版本。总之谢谢
                  • 这个修复对我有用!我可以确认文档已按照上面评论中的建议进行了更新。 docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
                  • 我不确定是否需要添加 属性。我的配置不需要它,参考文档中也没有提到它。
                  • 由于应用程序在没有此“ServeletInitializer”文件的情况下在 STS 中运行,因此我满怀荣耀地删除了该文件并敲了 2 天的脑袋,想知道为什么它不能在 Tomcat 上运行。谢谢你的回答。通过查看这个 Servlet 名称,我想起了我的错误,并且在将那个文件替换回来后,它就被修复了。
                  • 对我来说不需要,运行 Spring Boot 2.1。
                  猜你喜欢
                  • 2018-12-05
                  • 2020-06-17
                  • 2018-05-18
                  • 1970-01-01
                  • 2016-08-11
                  • 2015-09-03
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-03-14
                  相关资源
                  最近更新 更多