85. Traditional deployment

85.1 创建可部署的 War 文件

生成可部署 war 文件的第一步是提供SpringBootServletInitializer子类并覆盖其configure方法。这利用了 Spring Framework 的 Servlet 3.0 支持,并允许您在 Servlet 容器启动应用程序时对其进行配置。通常,您更新应用程序的主类以扩展SpringBootServletInitializer

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }

}

下一步是更新构建配置,以便您的项目生成 war 文件而不是 jar 文件。如果您使用的是 Maven 并使用spring-boot-starter-parent(将为您配置 Maven 的 war 插件),则只需修改pom.xml即可将包装更改为 war:

<packaging>war</packaging>

如果您使用的是 Gradle,则需要修改build.gradle才能将 war 插件应用于项目:

apply plugin: 'war'

该过程的最后一步是确保嵌入式 servlet 容器不会干扰将要部署 war 文件的 servlet 容器。为此,您需要标记所提供的嵌入式 servlet 容器依赖性。

如果您使用的是 Maven:

<dependencies>
    <!-- … -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <!-- … -->
</dependencies>

如果您正在使用 Gradle:

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

Note

如果您使用的 Gradle 版本仅支持编译依赖关系(2.12 或更高版本),则应 continue 使用providedRuntime。除其他限制外,compileOnly依赖项不在测试 Classpath 上,因此任何基于 Web 的集成测试都将失败。

如果您使用的是Spring Boot 构建工具,则将嵌入式 servlet 容器的相关性标记为已提供将生成一个可执行的 war 文件,其中所提供的相关性打包在lib-provided目录中。这意味着,除了可以部署到 Servlet 容器之外,还可以在命令行上使用java -jar运行应用程序。

Tip

查看上述配置的Maven-based example的 Spring Boot 的示例应用程序。

85.2 为较旧的 servlet 容器创建可部署的 war 文件

较早的 Servlet 容器不支持 Servlet 3.0 中使用的ServletContextInitializer引导程序。您仍然可以在这些容器中使用 Spring 和 Spring Boot,但是您将需要在应用程序中添加web.xml并将其配置为通过DispatcherServlet加载ApplicationContext

85.3 将现有应用程序转换为 Spring Boot

对于非 Web 应用程序,它应该很容易(丢弃创建ApplicationContext的代码,并用SpringApplicationSpringApplicationBuilder的调用替换它)。 Spring MVC Web 应用程序通常适合首先创建可部署的 war 应用程序,然后再将其迁移到可执行的 war 和/或 jar 中。有用的读物在将Jar子转换为 War 的 Starter 指南中。

通过扩展SpringBootServletInitializer(例如在名为Application的类中)创建可部署的 War,并添加 Spring Boot @SpringBootApplicationComments。例:

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        // Customize the application or call application.sources(...) to add sources
        // Since our example is itself a @Configuration class (via @SpringBootApplication)
        // we actually don't need to override this method.
        return application;
    }

}

请记住,您在sources中 Importing 的内容仅仅是 Spring ApplicationContext,通常任何已经起作用的东西都应该在这里工作。可能有些 bean 可以稍后删除,然后让 Spring Boot 为它们提供自己的默认值,但是应该有可能先使某些东西工作。

可以将静态资源移至 Classpath 根目录中的/public(或/static/resources/META-INF/resources)。与messages.properties相同(Spring Boot 在 Classpath 的根目录中自动检测到此情况)。

在 Spring DispatcherServlet和 Spring Security 上使用 Vanilla 不需要进一步更改。如果您的应用程序中具有其他功能(例如,使用其他 servlet 或过滤器),则可能需要向Application上下文中添加一些配置,以替换web.xml中的那些元素,如下所示:

  • 类型ServletServletRegistrationBean@Bean将那个 bean 安装在容器中,就好像它是web.xml中的<servlet/><servlet-mapping/>一样。

  • 类型FilterFilterRegistrationBean@Bean的行为类似(例如<filter/><filter-mapping/>)。

  • 可以通过Application中的@ImportResource添加 XML 文件中的ApplicationContext。或者可以在几行中以@Bean定义重新创建已经大量使用注解配置的简单情况。

War 爆发后,我们可以通过向Application添加main方法(例如,

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

Note

如果您打算以 War 或可执行应用程序的形式启动应用程序,则需要使用SpringBootServletInitializer回调和main方法都可用的方法来共享构建器的自定义项,例如:

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return configureApplication(builder);
}

public static void main(String[] args) {
configureApplication(new SpringApplicationBuilder()).run(args);
}

private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
return builder.sources(Application.class).bannerMode(Banner.Mode.OFF);
}

}

应用程序可以分为多个类别:

  • 没有web.xml的 Servlet 3.0 应用程序。

  • 带有web.xml的应用程序。

  • 具有上下文层次结构的应用程序。

  • 没有上下文层次结构的应用程序。

所有这些都应该适合翻译,但是每一个都可能需要稍微不同的技巧。

如果 Servlet 3.0 应用程序已经使用了 Spring Servlet 3.0 初始化程序支持类,则它们可能很容易转换。通常,现有WebApplicationInitializer中的所有代码都可以移到SpringBootServletInitializer中。如果您现有的应用程序具有多个ApplicationContext(例如,如果使用AbstractDispatcherServletInitializer),则可以将所有上下文源压缩为一个SpringApplication。您可能会遇到的主要并发症是,如果这不起作用,则需要维护上下文层次结构。有关示例,请参见构建层次结构的 Starter。通常将需要分解包含特定于 Web 的功能的现有父上下文,以便所有ServletContextAware组件都位于子上下文中。

还不是 Spring 应用程序的应用程序可以转换为 Spring Boot 应用程序,上面的指南可能会有所帮助,但是您的里程可能会有所不同。

85.4 将 WAR 部署到 WebLogic

要将 Spring Boot 应用程序部署到 WebLogic,必须确保 Servlet 初始化程序直接实现WebApplicationInitializer(即使您是从已经实现它的 Base Class 扩展的)。

WebLogic 的典型初始化器如下所示:

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.web.WebApplicationInitializer;

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer implements WebApplicationInitializer {

}

如果使用 logback,则还需要告诉 WebLogic 首选打包版本,而不是服务器预先安装的版本。您可以通过添加包含以下内容的WEB-INF/weblogic.xml文件来做到这一点:

<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app
    xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd
        http://xmlns.oracle.com/weblogic/weblogic-web-app
        http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
    <wls:container-descriptor>
        <wls:prefer-application-packages>
            <wls:package-name>org.slf4j</wls:package-name>
        </wls:prefer-application-packages>
    </wls:container-descriptor>
</wls:weblogic-web-app>

85.5 在旧的(Servlet 2.5)容器中部署 WAR

Spring Boot 使用 Servlet 3.0 API 初始化ServletContext(寄存器Servlets等),因此您不能在 Servlet 2.5 容器中立即使用同一应用程序。不过,可以使用某些特殊工具在旧容器上运行 Spring Boot 应用程序。如果您将org.springframework.boot:spring-boot-legacy作为依赖项(到 Spring Boot 的核心maintained separately且当前在 1.0.2.RELEASE 中可用),您需要做的就是创建一个web.xml并声明一个上下文侦听器以创建应用程序上下文以及您的过滤器和小服务程序。上下文侦听器是用于 Spring Boot 的专用侦听器,但其余部分对于 Servlet 2.5 中的 Spring 应用程序是正常的。例:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>demo.Application</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.boot.legacy.context.web.SpringBootContextLoaderListener</listener-class>
    </listener>

    <filter>
        <filter-name>metricsFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>metricsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextAttribute</param-name>
            <param-value>org.springframework.web.context.WebApplicationContext.ROOT</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

在此示例中,我们使用单个应用程序上下文(由上下文侦听器创建的上下文),并使用 init 参数将其附加到DispatcherServlet。这在 Spring Boot 应用程序中很正常(通常只有一个应用程序上下文)。