83. 消息

Spring Boot 提供了一些包含消息传递的启动器。本节回答使用 Spring Boot 消息时出现的问题。

83.1 禁用事务的 JMS 会话

如果你的 JMS 代理不支持事务会话,则必须完全禁用事务的支持。如果你创建了自己的 JmsListenerContainerFactoryy,则没有任何事情可做,因为默认情况下无法进行事务处理。如果要使用 DefaultJmsListenerContainerFactoryConfigurer 重用 Spring Boot 的默认设置,可以禁用事务会话,如下:

@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(
		ConnectionFactory connectionFactory,
		DefaultJmsListenerContainerFactoryConfigurer configurer) {
	DefaultJmsListenerContainerFactory listenerFactory =
			new DefaultJmsListenerContainerFactory();
	configurer.configure(listenerFactory, connectionFactory);
	listenerFactory.setTransactionManager(null);
	listenerFactory.setSessionTransacted(false);
	return listenerFactory;
}

前面的示例重写默认工厂,并且应该将其应用于应用程序定义的任何其它工厂(如果有的话)。

84. 批处理应用程序

本节回答通过 Spring Boot 使用 Spring 批处理产生的问题。

[Note] Note

默认情况下,批处理应用程序需要 DataSource 来存储作业细节。如果你想偏离这一点,你需要实现 BatchConfigurer。有关的更多详细信息请参阅 @EnableBatchProcessing 的 Javadoc 。

有关 Spring 批处理的更多内容,请参阅 Spring Batch 项目页面。

84.1 在启动时执行 Spring 批处理作业

通过在上下文中添加 @EnableBatchProcessing(来自S Spring Batch),可以实现 Spring 批处理自动配置。

默认情况下,它在启动时执行应用程序上下文中的所有作业(详情请参阅 JobLauncherCommandLineRunner)。可以通过指定 spring.batch.job.names(使用逗号分隔的作业名模式列表)缩小到特定作业或多个作业的范围。

如果应用程序上下文包含 JobRegistry,则在注册表中查找 spring.batch.job.names 中的作业,而不是从上下文自动连接。这是一个常见的模式,具有更复杂的系统,其中多个作业在子上下文中定义并集中注册。

更多详细信息请参阅 BatchAutoConfiguration 和 @EnableBatchProcessing。

85. 执行器

Spring Boot 包含 Spring Boot 执行器。本节回答使用的常见问题。

85.1 更改执行器节点的 HTTP 端口或地址

在独立的应用程序中,执行器 HTTP 端口默认与主 HTTP 端口相同。要使应用程序在不同的端口上监听,请设置外部属性:management.server.port。要监听完全不同的网络地址(例如,当你具有用于管理的内部网络和用户应用程序的外部网络时),还可以将 management.server.address 设置为服务器能够绑定的有效 IP 地址。

更多详细信息请参阅 ManagementServerProperties 源代码和 “Production-ready features” 部分中的 “小节 52.2, “自定义和管理服务器端口””。

85.2 自定义白名单错误页面

Spring Boot 安装了一个白名单错误页面,如果遇到服务器错误,你将在浏览器客户端中看到该错误页面(使用 JSON 和其它媒体类型的机器客户端应该看到具有正确错误代码的合理响应)。

[Note] Note

设置 server.error.whitelabel.enabled=false 来关闭默认错误页面。这样做恢复了正在使用的 servlet 容器的默认值。注意,Spring Boot 仍然试图解决错误视图,所以你应该添加自己的错误页面,而不是完全禁用它。

用自己的方式重写错误页面取决于所使用的模板技术。例如,如果使用 Thymeleaf,则可以添加 error.html 模板。如果使用 FreeMarker,则可以添加 error.ftl 模板。通常,你需要一个用 error 名称解析的 View 或处理 /error 路径的 @Controller。除非你替换了一些默认配置,否则你应该在 ApplicationContext 中找到 BeanNameViewResolver,因此命名 error 的 @Bean 将是一种简单的方法。有关的更多选项请参阅 ErrorMvcAutoConfiguration。

有关如何在 servlet 容器中注册处理程序的详细信息请参阅 “错误处理” 章节。

85.3 清除合理的值

env 和 configprops 端点返回的信息可能有些敏感,因此匹配特定模式的键在默认情况下被审查(即,它们的值被 替换)。

Spring Boot 为这些密钥使用合理的默认值:例如,任何以 "password"、"secret"、"key" 或 "token" 结尾的密钥都被清除。也可以使用正则表达式来代替,例如 credentials.。将包含单词 credentials 的任何键作为密钥的一部分进行清除。

可以使用 management.endpoint.env.keys-to-sanitize 和 management.endpoint.configprops.keys-to-sanitize 分别定制要使用的模式。

86. 安全性

本节讨论使用 Spring Boot 时的安全性问题,包括通过 Spring Boot 使用 Spring Security 时产生的问题。

有关 Spring Security 更多的详细信息请参阅 Spring Security 项目页面。

86.1 关闭 Spring Boot 安全性配置

如果在应用程序中使用 WebSecurityConfigurerAdapter 定义 @Configurationn,那么它将关闭 Spring Boot 中的默认 webapp 安全设置。

86.2 更改 UserDetailsService 并添加用户帐户

如果提供类型为 AuthenticationManager、AuthenticationProvider 或 UserDetailsService 的 @Bean,则不会创建默认的 InMemoryUserDetailsManager 的 @Bean,因此你可以使用 Spring Security 的完整特性(例如, 各种身份验证选项)。

添加用户帐户最简单的方法是提供自己的 UserDetailsService bean。

86.3 在代理服务器后面运行时启用 HTTPS

确保所有的主要端点仅在 HTTPS 上可用是任何应用程序的重要任务。如果使用 Tomcat 作为 servlet 容器,那么 Spring Boot 在检测到某些环境设置时自动添加 Tomcat 自己的 RemoteIpValve,并且应该能够依靠 HttpServletRequest 报告它是否安全(甚至在代理服务器的下游处理真实的 SSL 终端)。标准行为由某些请求头(x-forwarded-for 和 x-forwarded-proto)的存在或不存在决定,这些请求头的名称是传统的,因此它应该与大多数前端代理一起工作。你可以通过在 application.properties 中添加一些条目来打开阀门,如下面的示例所示:

server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto

(这两种属性中的任何一种都存在于阀门上。或者,你可以通过添加 TomcatServletWebServerFactory bean 来添加 RemoteIpValve。)

要将 Spring Security 配置为需要用于所有(或一些)请求的安全通道,请考虑添加你自己的 WebSecurityConfigurerAdapter,它添加以下 HttpSecurity 配置:

@Configuration
public class SslWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// Customize the application security
		http.requiresChannel().anyRequest().requiresSecure();
	}

}

87. 热交换

Spring Boot 支持热交换。本节回答有关它如何工作的问题。

87.1 重新加载静态内容

热重新加载有几种选择。推荐的方法是使用 spring-boot-devtools,因为它提供了额外的开发时特性,比如支持快速应用程序重启和在线重载,以及合理的开发时配置(比如模板缓存)。Devtools 通过监视类路径来进行更改。这意味着静态资源更改必须 "built",以便进行更改。默认情况下,当你保存更改时,Eclipse 会自动发生这种情况。在 IntelliJ IDEA 中,Project 命令触发必要的构建。由于默认重启排除,对静态资源的更改不会触发应用程序的重新启动。然而,它们确实触发了一次在线重载。

或者,在 IDE 中运行(尤其是在调试上)是一种很好的开发方法(所有的现代 IDE 都允许重新加载静态资源,通常也允许 Java 类更改的热交换)。

最后,可以配置 Maven 和 Gradle插件(详见 addResources 属性),以支持从命令行运行直接从源重新加载静态文件。如果你使用高级工具编写代码,则可以使用外部 css/js 编译器进程。

87.2 不重启容器而重载模版

Spring Boot 支持的大多数模板技术都包含禁用缓存的配置选项(本文稍后描述)。如果使用 spring-boot-devtools 模块,这些属性将在开发时为你自动配置。

87.2.1 Thymeleaf 模版

如果你使用 Thymeleaf,将 spring.thymeleaf.cache 设置为 false。请参阅 ThymeleafAutoConfiguration 的其它 Thymeleaf 定制选项。

87.2.2 FreeMarker 模版

如果你使用 FreeMarker,将 spring.freemarker.cache 设置为 false。请参阅 FreeMarkerAutoConfiguration 的其它 FreeMarker 定制选项。

87.2.3 Groovy 模版

如果你使用 Groovy 模版,将 spring.groovy.template.cache 设置为 false。请参阅 GroovyTemplateAutoConfiguration 的其它 Groovy 定制选项。

87.3 快速重启应用程序

spring-boot-devtools 模块包含对应用程序自动重新启动的支持。虽然不像 JRebel 这样的技术快,但它通常比冷启动快得多。在研究本文档后面讨论的一些更复杂的重新加载选项之前,你应该尝试一下。

更多详细信息请参阅 小节 20, 开发者工具 部分。

87.4 不重启容器而重新加载 Java 类

许多现代 IDE(Eclipse、IDEA 等)支持字节码的热交换。因此,如果你做出不影响类或方法签名的更改,则应该重新加载而没有副作用。

88. 构建

Spring Boot 包含 Maven 和 Gradle 的构建插件。本节回答关于这些插件的常见问题。

88.1 生成构建信息

Maven 插件和 Gradle 插件都允许生成包含项目坐标、名称和版本的构建信息。插件还可以被配置为通过配置添加附加属性。当存在这样一个文件时,Spring Boot 会自动配置 BuildProperties bean。

若要使用 Maven 生成构建信息,请为 build-info 添加执行目标,如下面的示例所示:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<version>2.1.0.BUILD-SNAPSHOT</version>
			<executions>
				<execution>
					<goals>
						<goal>build-info</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>
[Tip] Tip

更多详细信息请参阅 Spring Boot Maven 插件文档。

下面的例子使用 Gradle 做相同的事:

springBoot {
	buildInfo()
}
[Tip] Tip

更多详细信息请参阅 Spring Boot Gradle 插件文档。

88.2 生成 Git 信息

Maven 和 Gradle 都允许生成 git.properties 文件,该文件包含有关构建项目时 git 源代码存储库状态的信息。

对于 Maven 用户,spring-boot-starter-parent POM 包含预配置插件来生成 git.properties 文件。若要使用它,请将以下声明添加到 POM 中:

<build>
	<plugins>
		<plugin>
			<groupId>pl.project13.maven</groupId>
			<artifactId>git-commit-id-plugin</artifactId>
		</plugin>
	</plugins>
</build>

Gradle 用户可以通过使用 gradle-git-properties 插件实现相同的结果,如下面的示例所示:

plugins {
	id "com.gorylenko.gradle-git-properties" version "1.5.1"
}
[Tip] Tip

git.properties 中的提交时间预计与以下格式匹配:yyyy-MM-dd’T’HH:mm:ssZ。这是上面列出的两个插件的默认格式。使用这种格式,可以将时间解析为 Date 及其格式,在序列化为 JSON 时,由 Jackson 的日期序列化配置设置进行控制。

88.3 自定义依赖项版本

如果你使用 Maven 构建,并直接或间接从 spring-boot-dependencies(例如,spring-boot-starter-parent)继承,但是希望覆盖特定的第三方依赖项,则可以添加适当的 <properties> 元素。浏览 spring-boot-dependencies POM以获得完整的属性列表。例如,要选择一个不同的 slf4j 版本,你将添加以下属性:

<properties>
	<slf4j.version>1.7.5<slf4j.version>
</properties>
[Note] Note

如果你的 Maven 项目从 spring-boot-dependencies 继承(直接或间接),那么这样做是有效的。如果在你自己的 dependencyManagement 部分中添加了带有 <scope>import</scope> 的 spring-boot-dependencies,那么你必须自己重新定义工件,而不是重写属性。

[Warning] Warning

每个 Spring Boot 发行都是针对这个特定的第三方依赖集来设计和测试的。重写版本可能会导致兼容性问题。

要覆盖 Gradle 中的依赖项版本,请参阅 Gradle 插件的文档的这一部分。

88.4 使用 Maven 创建一个可执行的 JAR

spring-boot-maven-plugin 可以用来创建一个可执行的 “fat” jar。如果使用 spring-boot-starter-parent POM,则可以声明插件和你的 jar 被重新打包如下:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>

如果不使用父 POM,仍然可以使用插件。但是,你必须另外添加一个 <executions> 部分,如下:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<version>2.1.0.BUILD-SNAPSHOT</version>
			<executions>
				<execution>
					<goals>
						<goal>repackage</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

完整的使用详细信息请参阅插件文档。

88.5 使用 Spring Boot 应用程序作为依赖项

类似于 war 文件,Spring Boot 应用程序不打算用作依赖项。如果你的应用程序包含希望与其它项目共享的类,推荐的方法是将该代码移动到单独的模块中。单独的模块可以依赖于你的应用程序和其它项目。

如果不能按照上面的建议重新排列代码,则 Spring Boot 的 Maven 和 Gradle 插件必须被配置为生成适合用作依赖项的独立构件。可执行归档文件不能用作依赖项,因为可执行 jar 格式将应用程序类封装在 BOOT-INF/classes 中。这意味着当可执行的 jar 用作依赖项时无法找到它们。

为了产生两个构件,一个可以用作依赖项,一个是可执行的,必须指定分类器。此分类器应用于可执行文件的名称,留下默认的档案作为依赖项使用。

若要配置 Maven 中的 exec 分类器,可以使用以下配置:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<configuration>
				<classifier>exec</classifier>
			</configuration>
		</plugin>
	</plugins>
</build>

88.6 当可执行 jar 运行时提取特定的库

在可执行的 jar 中,大多数嵌套库不需要解包以便运行。但是,某些库可能存在问题。例如,JRuby 包含它自己的嵌套 jar 支持,它假定 jruby-complete.jar 本身总是作为文件直接可用。

为了处理任何有问题的库,你可以标记当可执行 jar 首次运行时,应该将特定的嵌套 jar 自动解压缩到 temp 文件夹。

例如,为了指示 JRuby 应该被标记为使用 Maven 插件进行拆包,你需要添加以下配置:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<configuration>
				<requiresUnpack>
					<dependency>
						<groupId>org.jruby</groupId>
						<artifactId>jruby-complete</artifactId>
					</dependency>
				</requiresUnpack>
			</configuration>
		</plugin>
	</plugins>
</build>

88.7 创建一个带有排除项的不可执行 jar

通常,如果将可执行和不可执行 jar 作为两个独立的构建产品,那么可执行版本具有库 jar 中不需要的附加配置文件。例如,application.yml 配置文件可能会从不可执行的 JAR 中排除。

在 Maven中,可执行 jar 必须是主要工件,并且可以为该库添加分类 jar,如下:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
		<plugin>
			<artifactId>maven-jar-plugin</artifactId>
			<executions>
				<execution>
					<id>lib</id>
					<phase>package</phase>
					<goals>
						<goal>jar</goal>
					</goals>
					<configuration>
						<classifier>lib</classifier>
						<excludes>
							<exclude>application.yml</exclude>
						</excludes>
					</configuration>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

88.8 用 Maven 远程调试一个 Spring Boot 应用程序

要使用 Maven 启动的 Spring Boot 应用程序附加远程调试器,可以使用 maven 插件的 jvmArguments 属性。

更多详细信息请参阅这个示例。

88.9 不使用 spring-boot-antlib 从 Ant 构建一个可执行归档

要用 Ant 构建,需要抓取依赖项、编译、然后创建 jar 或 war 存档。为了使它可执行,你可以使用 spring-boot-antlib 模块,或者你可以遵循这些指令:

  1. 如果你正在构建一个 jar,则在嵌套的 BOOT-INF/classes 目录中打包应用程序的类和资源。如果你正在构建一个 war,那么在嵌套的 WEB-INF/classes 目录中打包应用程序类。
  2. 添加运行时依赖项到 jar 的嵌套的 BOOT-INF/lib 目录或 war 的嵌套的 WEB-INF/lib 目录中。记住不要压缩归档中的条目。
  3. 添加 provided (嵌入式容器) 依赖项到 jar 的嵌套的 BOOT-INF/lib 目录或 war 的嵌套的 WEB-INF/lib 目录中。记住不要压缩归档中的条目。
  4. 添加 spring-boot-loader 到归档的根目录(以便 Main-Class 可用)。
  5. 使用适当的启动器(如 JarLauncher 用于 jar 文件)作为清单中的 Main-Class 属性,并通过设置 Start-Class 属性来指定它需要的其它属性作为清单条目(主要的)。

下面的示例演示如何使用 Ant 构建可执行归档:

<target name="build" depends="compile">
	<jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
		<mappedresources>
			<fileset dir="target/classes" />
			<globmapper from="*" to="BOOT-INF/classes/*"/>
		</mappedresources>
		<mappedresources>
			<fileset dir="src/main/resources" erroronmissingdir="false"/>
			<globmapper from="*" to="BOOT-INF/classes/*"/>
		</mappedresources>
		<mappedresources>
			<fileset dir="${lib.dir}/runtime" />
			<globmapper from="*" to="BOOT-INF/lib/*"/>
		</mappedresources>
		<zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
		<manifest>
			<attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" />
			<attribute name="Start-Class" value="${start-class}" />
		</manifest>
	</jar>
</target>

Ant 示例有一个 build.xml 文件,如果你使用以下命令运行它,则该手动文件应该工作:

$ ant -lib <folder containing ivy-2.2.jar> clean manual

然后可以用以下命令运行应用程序:

$ java -jar target/*.jar

89. 传统部署

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

89.1 创建可部署的 War 文件

[Warning] 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] Tip

providedRuntime 是 Gradle 的 compileOnly 配置的首选。除其它限制外,compileOnly 依赖项不在测试类路径上,因此任何基于 web 的集成测试失败。

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

[Tip] Tip

看一下前面描述配置的基于 Maven 的示例的 Spring Boot 的示例应用程序。

89.2 转换现有应用程序到 Spring Boot

对于非 Web 应用程序,将现有的 Spring 应用程序转换为 Spring Boot 应用程序应该是容易的。为此,丢弃创建 ApplicationContext 的代码,并用对 SpringApplication 或 SpringApplicationBuilder 的调用替换它。Spring MVC web 应用程序通常能够首先创建可部署的 war 应用程序,然后将其迁移到可执行的 war 或 jar。看一开始把瓶子变成战争的指南。请参阅 新手入门指南上的转换 jar 为 war

要通过扩展 SpringBootServletInitializer(例如,在名为 Application 的类中)并添加 Spring Boot @SpringBootApplication 注解来创建可部署的 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;
	}

}

记住,无论你在源代码中使用什么,都只是一个 Spring ApplicationContext。通常,任何已经工作的东西都应该在这里工作。你稍后可以删除一些 bean,让 Spring Boot 为它们提供自己的默认值,但是在你需要这样做之前,应该可以让一些 bean 正常工作。

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

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

  • Servlet 或 ServletRegistrationBean类型的 @Bean 将该 bean 安装在容器中,就好像它是 web.xml 中的 <servlet/> 和 <servlet-mapping/> 一样。
  • Filter 或 FilterRegistrationBean 类型的 @Bean 的行为类似(作为 <filter/> 和 <filter-mapping/>)。
  • XML 文件中的 ApplicationContext 可以通过应用程序中的 @ImportResource 添加。或者,大量使用注解配置的简单情况可以在几行中重新创建为 @Bean 定义。

当 war 文件工作时,你可以通过向应用程序添加一个主方法来使其可执行,如下面的示例所示:

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

如果希望将应用程序作为 war 或可执行应用程序启动,则需要在 SpringBootServletInitializer 回调可用的方法和类似的主方法中共享构建器的自定义:

@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+ 初始化器支持类,则 Servlet 3.0+ 应用程序可以很容易地转译。通常,来自现有 WebApplicationInitializer 的所有代码都可以移动到 SpringBootServletInitializer 中。如果现有应用程序有多于一个 ApplicationContext(例如,如果它使用 AbstractDispatcherServletInitializer),则可以将所有上下文源组合到一个 SpringApplication 中。你可能遇到的主要并发症是如果组合不起作用,则需要维护上下文层次结构。请参阅关于构建应用程序上下文层次结构的示例。包含特定于 web 的特性的现有父上下文通常需要被分解,以便所有 ServletContextAware 组件都在子上下文中。

还不是 Spring 应用程序的应用程序可以转换为 Spring Boot 应用程序,前面提到的指导可能有帮助。然而,你可能会遇到问题。在这种情况下,我们建议用 spring-boot 标记在 Stack Overflow 询问问题。

89.3 部署 WAR 到 WebLogic

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

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>

89.4 使用 Jedis 替代 Lettuce

默认情况下,Spring Boot 启动器(spring-boot-starter-data-redis)使用 Lettuce。你需要排除该依赖项,而代之以 Jedis。Spring Boot 管理这些依赖关系,以帮助尽可能容易地使该过程。

下面的示例展示了如何在 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")
	// ...
}