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
的代码,并将其替换为对SpringApplication
或SpringApplicationBuilder
的调用。 Spring MVC Web 应用程序通常适合首先创建可部署的 war 应用程序,然后再将其迁移到可执行的 war 或 jar。参见将Jar子转换为 War 的 Starter 指南。
要通过扩展SpringBootServletInitializer
(例如,在名为Application
的类中)并添加 Spring Boot @SpringBootApplication
Comments 来创建可部署的 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
上下文添加一些配置,如下所示:
-
类型为
Servlet
或ServletRegistrationBean
的@Bean
将该 bean 安装在容器中,就好像它是web.xml
中的<servlet/>
和<servlet-mapping/>
一样。 -
Filter
或FilterRegistrationBean
类型的@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")
// ...
}