传统部署
Spring Boot 支持传统部署方式以及更现代的部署形式。本节解答有关传统部署的常见问题。
创建一个可部署的 War 文件
由于 Spring WebFlux 并不严格依赖于 Servlet API,并且应用程序默认部署在内嵌的 Reactor Netty 服务器上,因此 WebFlux 应用程序不支持 War 部署。
生成可部署的 war 文件的第一步是提供一个 SpringBootServletInitializer 的子类,并重写其 configure 方法。这样做利用了 Spring Framework 对 Servlet 3.0 的支持,使你能够在应用由 servlet 容器启动时对其进行配置。通常,你应该将应用程序的主类修改为继承 SpringBootServletInitializer,如下例所示:
- Java
- Kotlin
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.builder.SpringApplicationBuilder
import org.springframework.boot.runApplication
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
@SpringBootApplication
class MyApplication : SpringBootServletInitializer() {
override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
return application.sources(MyApplication::class.java)
}
}
fun main(args: Array<String>) {
runApplication<MyApplication>(*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 容器。
对于 Maven,你需要将嵌入式 servlet 容器依赖标记为 provided。例如:
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- ... -->
</dependencies>
如果你使用 Gradle,则只需将运行时依赖项移至 providedRuntime 配置中。例如:
dependencies {
// ...
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat-runtime'
// ...
}
providedRuntime 优于 Gradle 的 compileOnly 配置。除了其他限制之外,compileOnly 依赖项不在测试类路径中,因此任何基于 Web 的集成测试都会失败。
如果你使用 Spring Boot 的 构建工具插件,将嵌入式 servlet 容器依赖标记为 provided,将会生成一个可执行的 war 文件,并将 provided 依赖打包到 lib-provided 目录中。这意味着,除了可以部署到 servlet 容器之外,你还可以通过命令行使用 java -jar 来运行你的应用程序。
将现有应用程序转换为 Spring Boot
要将现有的非 Web Spring 应用程序转换为 Spring Boot 应用程序,请将创建 ApplicationContext 的代码替换为对 SpringApplication 或 SpringApplicationBuilder 的调用。Spring MVC Web 应用程序通常可以先创建一个可部署的 war 应用程序,然后再将其迁移到可执行的 war 或 jar。
要创建一个可部署的 war 文件,可以通过继承 SpringBootServletInitializer(例如,在一个名为 Application 的类中)并添加 Spring Boot 的 @SpringBootApplication 注解,使用类似于以下示例所示的代码:
- Java
- Kotlin
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class MyApplication 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 (through
// @SpringBootApplication)
// we actually do not need to override this method.
return application;
}
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.builder.SpringApplicationBuilder
import org.springframework.boot.runApplication
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
@SpringBootApplication
class MyApplication : SpringBootServletInitializer() {
override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
// Customize the application or call application.sources(...) to add sources
// Since our example is itself a @Configuration class (through @SpringBootApplication)
// we actually do not need to override this method.
return application
}
}
请记住,无论你在 sources 中放入什么,它都只是一个 Spring ApplicationContext。通常情况下,任何已经能正常工作的内容在这里也应该能正常工作。你可能会在稍后移除一些 Bean,让 Spring Boot 为其提供自己的默认实现,但在那之前,你应该能够先让某些功能运行起来。
静态资源可以移至 classpath 根目录下的 /public(或 /static、/resources、/META-INF/resources)。messages.properties 文件同样适用此规则(Spring Boot 会自动在 classpath 根目录下检测该文件)。
直接使用 Spring 的 DispatcherServlet 和 Spring Security 通常无需额外更改。如果你的应用程序中包含其他功能(例如,使用了其他 servlet 或 filter),你可能需要通过替换 web.xml 中的相应元素,在 Application 上下文中添加一些配置,如下所示:
-
类型为 Servlet 或 ServletRegistrationBean 的 @Bean 会将该 Bean 安装到容器中,其效果等同于在
web.xml中声明了<servlet/>和<servlet-mapping/>。 -
类型为 Filter 或 FilterRegistrationBean 的 @Bean 行为类似(相当于
<filter/>和<filter-mapping/>)。 -
XML 文件中的 ApplicationContext 可以通过在你的
Application类中使用 @ImportResource 来添加。或者,对于已经大量使用注解配置的场景,也可以用几行 @Bean 定义来重新实现。
一旦 war 文件可以正常运行,你可以通过在 Application 中添加一个 main 方法使其可执行,如下例所示:
- Java
- Kotlin
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
如果你打算将你的应用程序以 war 包形式或可执行应用程序的方式启动,你需要将构建器的自定义配置放在一个方法中,该方法同时对 SpringBootServletInitializer 回调和 main 方法可用,如下所示:
- Java
- Kotlin
import org.springframework.boot.Banner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return customizerBuilder(builder);
}
public static void main(String[] args) {
customizerBuilder(new SpringApplicationBuilder()).run(args);
}
private static SpringApplicationBuilder customizerBuilder(SpringApplicationBuilder builder) {
return builder.sources(MyApplication.class).bannerMode(Banner.Mode.OFF);
}
}
import org.springframework.boot.Banner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.builder.SpringApplicationBuilder
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
@SpringBootApplication
class MyApplication : SpringBootServletInitializer() {
override fun configure(builder: SpringApplicationBuilder): SpringApplicationBuilder {
return customizerBuilder(builder)
}
companion object {
@JvmStatic
fun main(args: Array<String>) {
customizerBuilder(SpringApplicationBuilder()).run(*args)
}
private fun customizerBuilder(builder: SpringApplicationBuilder): SpringApplicationBuilder {
return builder.sources(MyApplication::class.java).bannerMode(Banner.Mode.OFF)
}
}
}
应用程序可以属于多个类别:
-
没有
web.xml的 Servlet 3.0+ 应用程序。 -
带有
web.xml的应用程序。 -
带有上下文层次结构的应用程序。
-
不带上下文层次结构的应用程序。
所有这些都应该可以进行翻译,但每种可能需要略有不同的技术。
如果 Servlet 3.0+ 应用程序已经使用了 Spring 的 Servlet 3.0+ 初始化器支持类,那么它们通常可以相当容易地进行迁移。通常,现有 WebApplicationInitializer 中的所有代码都可以移入一个 SpringBootServletInitializer。如果你的现有应用程序包含多个 ApplicationContext(例如,使用了 AbstractDispatcherServletInitializer),那么你或许可以将所有上下文配置源合并为一个单一的 SpringApplication。你可能遇到的主要复杂情况是:当合并不可行时,你需要维持上下文的层次结构。有关构建层次结构的示例,请参阅关于构建层次结构的条目。如果现有的父上下文包含 Web 特定的功能,通常需要将其拆分,以确保所有 ServletContextAware 组件都位于子上下文中。
尚未基于 Spring 的应用程序可能可以转换为 Spring Boot 应用程序,前面提到的指导可能会有所帮助。然而,你仍可能会遇到问题。在这种情况下,我们建议 在 Stack Overflow 上提问,并加上 spring-boot 标签。
将 WAR 部署到 WebLogic
要将 Spring Boot 应用程序部署到 WebLogic,必须确保你的 servlet 初始化器直接实现 WebApplicationInitializer(即使你继承了一个已经实现该接口的基类)。
WebLogic 的典型初始化程序应类似于以下示例:
- Java
- Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.WebApplicationInitializer;
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer implements WebApplicationInitializer {
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
import org.springframework.web.WebApplicationInitializer
@SpringBootApplication
class MyApplication : SpringBootServletInitializer(), 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
https://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd
http://xmlns.oracle.com/weblogic/weblogic-web-app
https://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>