传统部署
Spring Boot 支持传统部署以及更现代的部署形式。本节回答了有关传统部署的常见问题。
创建可部署的 War 文件
由于 Spring WebFlux 并不严格依赖于 Servlet API,并且应用默认部署在嵌入式的 Reactor Netty 服务器上,因此 WebFlux 应用不支持 War 包部署。
生成可部署的 war 文件的第一步是提供一个 SpringBootServletInitializer 子类并重写其 configure
方法。这样做利用了 Spring 框架的 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 容器。为此,你需要将嵌入式 servlet 容器依赖标记为 provided
。
如果你使用 Maven,以下示例将标记 Servlet 容器(在这种情况下是 Tomcat)为 provided:
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- ... -->
</dependencies>
如果你使用 Gradle,以下示例将标记 servlet 容器(在本例中为 Tomcat)为 provided
:
dependencies {
// ...
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
// ...
}
providedRuntime
比 Gradle 的 compileOnly
配置更受欢迎。除了其他限制外,compileOnly
依赖项不在测试类路径上,因此任何基于 Web 的集成测试都会失败。
如果你使用了 Spring Boot 构建工具插件,将嵌入式 servlet 容器依赖标记为 provided
会生成一个可执行的 war 文件,其中提供的依赖项打包在 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 为它们提供默认的实现,但在你需要这样做之前,应该已经能够使某些功能正常工作了。
静态资源可以移动到类路径根目录下的 /public
(或 /static
或 /resources
或 /META-INF/resources
)目录中。对于 messages.properties
文件也是如此(Spring Boot 会自动检测类路径根目录下的该文件)。
Spring DispatcherServlet 和 Spring Security 的常规使用应该不需要进一步的更改。如果你的应用程序中有其他功能(例如,使用其他 servlet 或过滤器),你可能需要在 Application
上下文中添加一些配置,通过替换 web.xml
中的元素来实现,如下所示:
-
一个类型为 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
的应用程序。 -
具有上下文层次结构的应用程序。
-
没有上下文层次结构的应用程序。
如果已经使用了 Spring Servlet 3.0+ 的初始化器支持类,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>