19.2 构建并部署 WAR 文件

在阅读本书的整个过程中,随着您开发 Taco Cloud 应用程序,您已经在 IDE 中或通过命令运行过可执行 JAR 文件。无论是内嵌的 Tomcat 服务器还是 Netty、SpringWebFlux 应用程序,一直都在提供服务。

这在很大程度上要感谢 Spring Boot 的自动配置。您得以不必创建 web.xml 文件或 servlet 初始类,以声明 Spring MVC 的 DispatcherServlet。但是如果您要部署应用程序到 Java 应用服务器,您需要构建一个 WAR 文件。应用服务器需要知道如何运行应用程序,您还需要在 WAR 文件中包含一个 servlet 初始化类,以充当 web.xml 文件的一部分,并声明 DispatcherServlet。

事实证明,将 Spring Boot 应用程序构建成 WAR 文件并不困难。实际上,如果在使用 Initializr 时选择了 WAR 选项,那么你就没什么需要做的了。

Initializr 确保生成的项目将包含 servlet 初始类,且构建产物是 WAR 文件。但是,如果您使用 Initializr 时选择的是 JAR 文件(或者如果您想知道相关的差异是什么),您需要阅读下面的内容。

首先,您需要使用某种方式配置 Spring 的 DispatcherServlet。可以通过 web.xml 文件完成,但 Spring Boot 通过 SpringBootservletInitializer 很容易实现这一点。SpringBootServletilizer 是对 WebApplicationInitializer 接口的一种特殊的 SpringBootAware 实现。除了配置 Spring 的 DispatcherServlet,SpringBootServletInitializer 也寻找 Spring 应用程序上下文中的任何类型为 Filter、Servlet 或 ServletContextInitializer 的类,并将它们实例化到 servlet 容器。

要使用 SpringBootServletilizer,请创建一个子类并重写 configure() 方法指定 Spring 配置类。清单 19.1 显示了 IngredientServiceServletInitializer。 这是您用于配料服务应用程序的 SpringBootServletInitializer 的子类。

程序清单 19.1 通过 Java 启用 Spring Web 应用程序
package tacos.ingredients;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;

public class IngredientServiceServletInitializer
        extends SpringBootServletInitializer {
  @Override
  protected SpringApplicationBuilder configure(
                    SpringApplicationBuilder builder) {
    return builder.sources(IngredientServiceApplication.class);
  }
}

如您所见,configure() 方法参数中传入了 SpringApplicationBuilder 对象,并将其作为结果返回。方法中调用 sources() 注册 Spring 配置类。在这种情况下,它注册 IngredientServiceApplication 类,起到两个作用。一是指定启动类(用于可执行 JAR 文件),另一个指定 Spring 配置类。

即使配料服务应用程序还有其他 Spring 配置类,但并不需要使用 sources() 方法全部注册它们。这个 IngredientServiceApplication 类,加了 @SpringBootApplication 注解,隐式启用了组件扫描。组件扫描发现并会找到任何其他配置类。

大多数情况下,SpringBootServletInitializer 的子类就是一个模板式文件。除引用应用程序主配置类之外,完全都一样。对于每个要构建 WAR 文件的应用程序,你几乎永远不会需要对其进行更改。

既然您已经编写了一个 servlet 初始化类,那么您必须对项目构建做一些小的修改。如果您使用 Maven 进行构建,要确保 pom.xml 中的 <packaging> 元素设置为 war,所需的更改如下:

<packaging>war</packaging>

如果使用 Gradle 构建,所做的修改也很简单。在 build.gradle 文件中引入 war 插件:

apply plugin: 'war'

现在,您已经准备好构建应用程序了。对于 Maven,您将使用 Maven 包装器执行打包脚本:

$ mvnw package

如果构建成功,那么可以在目标目录中找到 WAR 文件。另一方面,如果您使用 Gradle 来构建项目,那么您将使用 Gradle 包装器:

$ gradlew build

构建完成后,WAR 文件将位于 build/libs 目录中。然后就是部署应用程序了。部署过程因应用服务器不同而异,因此请参阅应用服务器的相关部署文档。

值得注意的是,尽管您已经构建的是一个适合部署到任何 Servlet 3.0(或更高版本)容器的 WAR 文件,但此 WAR 文件仍然可以在命令行上执行,就像它是一个可执行的 JAR 文件一样:

$ java -jar target/ingredient-service-0.0.19-SNAPSHOT.war

实际上,您可以从一个构建产品中获得两种部署选择!

在应用服务器中部署微服务?

配料服务应用程序旨在成为更大的 Taco Cloud 应用程序的微服务组成部分。但是在这里,我们将配料服务作为独立应用程序部署到应用程序服务器。这有意义吗?

微服务通常类似于任何其他应用程序,应该可以独立部署。尽管这样部署配料服务,对于 Taco Cloud 应用程序的其余服务完全没用处,但并不妨碍能将其部署到 Tomcat 或其他应用程序服务器。当然,不要期望用这样的方式,可以像云端部署那样,自由扩展应用程序。

WAR 文件做为 Java 部署的主要方式有 20 多年了,它是为将应用程序部署到传统 Java 应用程序而设计的。现代的云部署并不需要 WAR 文件,有些甚至根本不支持。当我们进入一个云部署的新时代,JAR 文件是一个更好的选择。

最后更新于