92. Traditional Deployment

Spring Boot 支持传统部署以及更现代的部署形式。本节回答有关传统部署的常见问题。

92.1 创建可部署的 War 文件

Warning

由于 Spring WebFlux 不严格依赖 Servlet API,并且默认情况下将应用程序部署在嵌入式 Reactor Netty 服务器上,因此 WebFlux 应用程序不支持 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,则以下示例将 servlet 容器(在本例中为 Tomcat)标记为已提供:

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

如果使用 Gradle,则以下示例将 servlet 容器(在本例中为 Tomcat)标记为已提供:

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

Tip

providedRuntime比 Gradle 的compileOnly配置更可取。除其他限制外,compileOnly依赖项不在测试 Classpath 上,因此任何基于 Web 的集成测试都将失败。

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

Tip

查看 Spring Boot 的示例应用程序中先前配置的Maven-based example

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

对于非 Web 应用程序,将现有的 Spring 应用程序转换为 Spring Boot 应用程序应该很容易。为此,请丢弃创建您的ApplicationContext的代码,并将其替换为对SpringApplicationSpringApplicationBuilder的调用。 Spring MVC Web 应用程序通常适合首先创建可部署的 war 应用程序,然后再将其迁移到可执行的 war 或 jar。参见将Jar子转换为 War 的 Starter 指南

要通过扩展SpringBootServletInitializer(例如,在名为Application的类中)并添加 Spring Boot @SpringBootApplicationComments 来创建可部署的 War,请使用类似于以下示例中所示的代码:

@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;
	}

}

请记住,无论您 Importingsources只是一个 Spring ApplicationContext。通常,任何已经起作用的东西都应该在这里工作。可能有些 bean 可以稍后删除,然后让 Spring Boot 为它们提供自己的默认值,但是应该可以使某些东西工作,然后再执行此操作。

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

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

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

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

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

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 应用程序,前面提到的指南可能会有所帮助。但是,您可能仍然遇到问题。在这种情况下,我们建议用 spring-boot 标签在 Stack Overflow 上提问

92.3 将 WAR 部署到 WebLogic

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

WebLogic 的典型初始化程序应类似于以下示例:

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 {

}

如果使用 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>

92.4 使用 Jedis 代替 Lettuce

默认情况下,Spring Boot 启动器(spring-boot-starter-data-redis)使用Lettuce。您需要排除该依赖性,而改为包含Jedis个。 Spring Boot Management 这些依赖关系,以帮助简化此过程。

以下示例显示了如何在 Maven 中执行此操作:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	<exclusions>
		<exclusion>
			<groupId>io.lettuce</groupId>
			<artifactId>lettuce-core</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>

以下示例显示了如何在 Gradle 中执行此操作:

configurations {
	compile.exclude module: "lettuce"
}

dependencies {
	compile("redis.clients:jedis")
	// ...
}