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

17.1. 创建可部署的战争文件

由于Spring WebFlux不严格依赖Servlet API,并且默认情况下将应用程序部署在嵌入式Reactor Netty服务器上,因此WebFlux应用程序不支持War部署。

产生可部署war文件的第一步是提供一个SpringBootServletInitializer子类并覆盖其configure方法。这样做利用了Spring Framework的Servlet 3.0支持,并允许您在由Servlet容器启动应用程序时对其进行配置。通常,应将应用程序的主类更新为extend SpringBootServletInitializer,如以下示例所示:

  1. @SpringBootApplication
  2. public class Application extends SpringBootServletInitializer {
  3. @Override
  4. protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  5. return application.sources(Application.class);
  6. }
  7. public static void main(String[] args) {
  8. SpringApplication.run(Application.class, args);
  9. }
  10. }

下一步是更新构建配置,以便您的项目生成war文件而不是jar文件。如果您使用Maven和spring-boot-starter-parent(为您配置Maven的war插件),那么您要做的就是修改pom.xml以将包装更改为war,如下所示:

  1. <packaging>war</packaging>

如果使用Gradle,则需要进行修改,build.gradle以将war插件应用于项目,如下所示:

  1. apply plugin: 'war'

该过程的最后一步是确保嵌入式servlet容器不干扰war文件所部署到的servlet容器。为此,您需要将嵌入式Servlet容器依赖性标记为已提供。
如果使用Maven,则以下示例将servlet容器(在本例中为Tomcat)标记为已提供:

  1. <dependencies>
  2. <!-- … -->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-tomcat</artifactId>
  6. <scope>provided</scope>
  7. </dependency>
  8. <!-- … -->
  9. </dependencies>

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

  1. dependencies {
  2. // …
  3. providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
  4. // …
  5. }
providedRuntime比Gradle的compileOnly配置更可取。除其他限制外,compileOnly依赖项不在测试类路径上,因此任何基于Web的集成测试都将失败。

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

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

要将现有的非Web Spring应用程序转换为Spring Boot应用程序,请替换创建您的代码ApplicationContext并将其替换为SpringApplication或的调用SpringApplicationBuilder。Spring MVC Web应用程序通常适合首先创建可部署的war应用程序,然后再将其迁移到可执行的war或jar。请参阅有关将罐子转换为战争的入门指南
要通过扩展SpringBootServletInitializer(例如,在名为的类中Application)并添加Spring Boot@SpringBootApplication注释来创建可部署的战争,请使用类似于以下示例中所示的代码:

  1. @SpringBootApplication
  2. public class Application extends SpringBootServletInitializer {
  3. @Override
  4. protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  5. // Customize the application or call application.sources(...) to add sources
  6. // Since our example is itself a @Configuration class (via @SpringBootApplication)
  7. // we actually don't need to override this method.
  8. return application;
  9. }
  10. }

请记住,无论您放置什么,sources都仅是Spring ApplicationContext。通常,任何已经起作用的东西都应该在这里工作。也许有些bean可以稍后删除,然后让Spring Boot为它们提供自己的默认值,但是应该可以使某些东西工作,然后再执行此操作。
可以将静态资源移至类路径根目录中/public(或/static/resources/META-INF/resources)。这同样适用于messages.properties(Spring Boot自动在类路径的根目录中检测到)。
SpringDispatcherServlet和Spring Security的香草用法应该不需要进一步更改。如果您的应用程序具有其他功能(例如,使用其他servlet或过滤器),则可能需要Application通过从中替换这些元素来向上下文中添加一些配置web.xml,如下所示:

  • @Bean类型的ServletServletRegistrationBean将安装豆在容器中,好像它是一个<servlet/><servlet-mapping/>web.xml
  • @Bean型的FilterFilterRegistrationBean表现得类似(作为<filter/><filter-mapping/>)。
  • 一个ApplicationContextXML文件可以通过添加@ImportResource在你的Application。或者,可以在几行中重新创建已经大量使用注释配置的情况作为@Bean定义。

war文件运行后,可以通过向中添加main方法来使其可执行Application,如以下示例所示:

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

| | 如果打算以战争或可执行应用程序的形式启动应用程序,则需要使用对SpringBootServletInitializer回调函数可用的方法和main类似于以下类的方法共享构建器的自定义项:``` @SpringBootApplication public class Application extends SpringBootServletInitializer {

  1. **@Override**
  2. **protected** SpringApplicationBuilder **configure**(SpringApplicationBuilder builder) {
  3. **return** configureApplication(builder);
  4. }
  5. **public** **static** **void** **main**(String[] args) {
  6. configureApplication(**new** SpringApplicationBuilder()).run(args);
  7. }
  8. **private** **static** SpringApplicationBuilder **configureApplication**(SpringApplicationBuilder builder) {
  9. **return** builder.sources(Application.class).bannerMode(Banner.Mode.OFF);
  10. }

}

  1. |
  2. | :---: | --- |
  3. 应用程序可以分为多个类别:
  4. - 没有的Servlet 3.0+应用程序`web.xml`。<br />
  5. - 带有的应用程序`web.xml`。<br />
  6. - 具有上下文层次结构的应用程序。<br />
  7. - 没有上下文层次结构的应用程序。<br />
  8. 所有这些都应该适合翻译,但是每种可能都需要稍微不同的技术。<br />如果Servlet 3.0+应用程序已经使用了Spring Servlet 3.0+初始化程序支持类,那么它们可能会很容易转换。通常,来自现有代码的所有代码`WebApplicationInitializer`都可以移入`SpringBootServletInitializer`。如果您现有的应用程序有多个`ApplicationContext`(例如,如果使用`AbstractDispatcherServletInitializer`),则可以将所有上下文源组合为一个`SpringApplication`。您可能遇到的主要并发症是,如果合并不起作用,并且您需要维护上下文层次结构。有关示例,请参见[有关构建层次结构](https://docs.spring.io/spring-boot/docs/2.4.0-SNAPSHOT/reference/html/howto.html#howto-build-an-application-context-hierarchy)的[条目](https://docs.spring.io/spring-boot/docs/2.4.0-SNAPSHOT/reference/html/howto.html#howto-build-an-application-context-hierarchy)。通常需要分解包含特定于Web的功能的现有父上下文,以便所有`ServletContextAware`组件都在子上下文中。<br />还不是Spring应用程序的应用程序可以转换为Spring Boot应用程序,前面提到的指南可能会有所帮助。但是,您可能仍然遇到问题。在这种情况下,建议您[使用标记来在Stack Overflow上提问`spring-boot`](https://stackoverflow.com/questions/tagged/spring-boot)。
  9. <a name="howto-weblogic"></a>
  10. ### 17.3. 将WAR部署到WebLogic
  11. 要将Spring Boot应用程序部署到WebLogic,必须确保servlet初始化程序**直接**实现`WebApplicationInitializer`(即使从已经实现它的基类扩展)。<br />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 { }

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

<?xml version=”1.0” encoding=”UTF-8”?>

org.slf4j

  1. <a name="howto-use-jedis-instead-of-lettuce"></a>
  2. ### 17.4. 使用Jedis代替生菜
  3. 默认情况下,Spring Boot入门(`spring-boot-starter-data-redis`)使用[Lettuce](https://github.com/lettuce-io/lettuce-core/)。您需要排除该依赖性,而改为包含[Jedis](https://github.com/xetorthio/jedis/)。Spring Boot管理这两个依赖关系,因此您无需指定版本即可切换到Jedis。<br />以下示例显示了如何在Maven中执行此操作:

org.springframework.boot spring-boot-starter-data-redis io.lettuce lettuce-core

redis.clients jedis

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

dependencies { implementation(‘org.springframework.boot:spring-boot-starter-data-redis’) { exclude group: ‘io.lettuce’, module: ‘lettuce-core’ } implementation ‘redis.clients:jedis’ // … }

  1. <a name="howto-testcontainers"></a>
  2. ### 17.5. 使用Testcontainer进行集成测试
  3. 该[Testcontainers](https://www.testcontainers.org/)库提供了一种方法来管理Docker容器中运行的服务。它与JUnit集成,允许您编写一个测试类,该类可以在运行任何测试之前启动容器。Testcontainers在编写与真实的后端服务(例如MySQL,MongoDB,Cassandra等)进行通信的集成测试时特别有用。Testcontainers可以在Spring Boot测试中使用,如下所示:

@SpringBootTest @Testcontainers class ExampleIntegrationTests { @Container static Neo4jContainer<?> neo4j = new Neo4jContainer<>(); }

  1. 在运行任何测试之前,这将启动运行Neo4jDocker容器(如果Docker在本地运行)。在大多数情况下,您将需要使用正在运行的容器中的详细信息(例如容器IP或端口)来配置应用程序。<br />这可以通过`@DynamicPropertySource`允许将动态属性值添加到Spring Environment的静态方法来完成。

@SpringBootTest @Testcontainers class ExampleIntegrationTests { @Container static Neo4jContainer<?> neo4j = new Neo4jContainer<>(); @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { registry.add(“spring.neo4j.uri”, neo4j::getBoltUrl); } } ``` 上面的配置允许应用程序中与Neo4j相关的Bean与在Testcontainers管理的Docker容器中运行的Neo4j通信。