部署 Spring Boot 应用程序

工程 | Josh Long | 2014年3月7日 | ...

Spring Boot 1.0 RC4 刚刚发布,1.0 版本也即将到来,并且有各种很酷的功能即将推出!

我经常被问到的问题之一是如何部署 Boot 应用程序。Spring Boot 基于 Spring,可以在 Spring 可运行的任何地方运行。它具有 Spring 的可移植性。Spring Boot 允许开发人员首先专注于应用程序的开发,并无需过度关注其生命周期的其他各个方面,包括部署和管理。

它旨在开箱即用,可用于生产环境。为此,Spring Boot 默认情况下做了一些不同的事情,起初可能会让一些人感到陌生。在这篇文章中,我希望简要介绍一些部署 Spring Boot 应用程序的常用策略。我将非常简要地介绍它,并提供一些示例代码,然后再深入探讨。随意跳过本节,从嵌入式 Web 服务器部署部分开始。

Spring Boot 快速入门

如果您尚未使用 Spring Boot,请尝试一下!有很多方法可以开始,包括start.spring.io 上的 Spring Initializr 网络服务,以及 - 如果您正在使用Spring Tool Suite - 还有一个更熟悉的集成向导,最终会调用相同的网络服务。我通常首先选中执行器Web复选框,然后选择生成一个Maven 项目。这将为您提供两个启动类,Application.javaApplicationTests.java,以及一个可立即使用的 Maven pom.xml 文件。

这是解压缩后的启动项目

➜  pwd
/Users/jlong/Downloads/starter
➜  starter  tree
.
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── demo
    │           └── Application.java
    └── test
        └── java
            └── demo
                └── ApplicationTests.java

7 directories, 3 files
➜  starter  

Maven 构建依赖于 Spring Boot 启动的依赖项。这些依赖项是有主见的。它们引入了与您面前的任务相关的已知、可立即使用的堆栈,而不是您可能使用的技术堆栈:换句话说,如果您想构建一个 Web 应用程序,只需依赖 Spring Boot 启动 Web 依赖项,如下所示

 <dependency> 
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

Maven 构建继承了有关要使用的依赖项版本的信息,这些信息来自其父 pom,也由 Spring Boot 提供。您无需担心对齐常见的 Spring 项目版本和第三方依赖项。

生成的 Java 类是样板代码(这就是它们是生成的原因!)。您通常不会更改类本身,尽管您可以这样做。在本博客结束时,您将获得一个部署 Spring Boot 应用程序的通用方法。这(希望如此!)是您在 Spring Boot 中遇到的唯一样板代码。以下是 Spring Boot 提供的Application.java

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

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

为了在文章中进行演示,我们将添加一个 RESTful Spring MVC 控制器。以下是修订后的Application.java 代码页,其中包含一个 Spring MVC REST 控制器,当请求/hello/World时,它将响应“Hello, World

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

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

@RestController
class GreetingController {
    
    @RequestMapping("/hello/{name}")
    String hello(@PathVariable String name) {
        return "Hello, " + name + "!";
    }
}

嵌入式 Web 服务器部署

开箱即用,Spring Boot 使用public static void main入口点为您启动嵌入式 Web 服务器。

如果您使用 Spring Boot Initializr 提供的 Maven 构建 (mvn clean install),您将获得一个胖 JAR。这个jar很方便,因为它包含所有其他依赖项以及您的 Web 服务器等内容。您可以将这个.jar文件提供给任何人,他们无需任何麻烦即可运行您的整个 Spring 应用程序:无需构建工具,无需设置,无需 Web 服务器配置,等等:只需java -jar ...your.jar

Tomcat

运行应用程序时,Spring Boot 默认情况下会检测到您有一个 Spring MVC 控制器并启动嵌入式 Apache Tomcat 7 实例。您应该能够通过打开浏览器并访问https://127.0.0.1:8080/hello/World来测试 REST 端点。

嵌入式 Tomcat 有很多配置选项。您可以通过提供EmbeddedServletContainerCustomizer(如本例所示)轻松为您的 Web 服务启用 HTTPS(SSL/TLS 终止)。此处描述的模块是一个交钥匙 Web 应用程序,可以在 HTTPS 上运行,只需要 SSL/TLS 证书,并嵌入自己的 Web 服务器。运行该特定应用程序非常简单:java -Dspring.profiles.active=production -Dkeystore.file=file:///$PWD/src/main/resources/keystore.p12 -jar target/oauth-1.0.0.BUILD-SNAPSHOT.jar

EmbeddedServletContainerCustomizer配置 SPI 允许您利用独立 Apache Tomcat 实例的显式 XML 配置的大部分功能。较小的内容,例如服务器运行的端口,可以通过命令行(作为--D样式参数)或通过加载的属性文件(例如,Spring Boot 会自动查阅CLASSPATH上名为application.properties的文件中的任何属性)来配置。因此,要更改 Tomcat 侦听的端口,您可以指定--Dserver.port=8081,使其侦听 8081 端口。如果您指定server.port=0,它将自动查找一个未使用的端口来侦听。

默认情况下,Spring Boot 使用 Tomcat 7。如果您想使用 Tomcat 8,只需说明!您只需覆盖 Maven 构建的tomcat.version属性,这将触发解析更高版本的 Apache Tomcat。

<properties>
  <tomcat.version>8.0.3</tomcat.version>
</properties>

Jetty

当然,你们中的一些人可能希望使用Jetty 嵌入式 servlet 容器。Jetty 也是一个不错的选择。您可以简单地排除 Spring Boot 启动 Tomcat 模块,然后导入 Spring Boot 启动 Jetty 模块。Spring Boot 将自动改为此模块进行委托。这是我们 Maven 构建中修改后的dependencies部分

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
		</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
		</dependency>
	</dependencies>

如果您想切换到 Jetty 9,也很容易。确保您的 Maven 构建中包含以下properties

<properties>
    <java.version>1.7</java.version>
    <jetty.version>9.1.0.v20131115</jetty.version>
    <servlet-api.version>3.1.0</servlet-api.version>
</properties>

Java EE 应用服务器怎么办?

但是,我想您可能会想,“如何将其部署到现有的 Tomcat 安装中,或者部署到经典的 Java EE 应用服务器(其中一些服务器价格昂贵!)例如 WebSphere、WebLogic 或 JBoss?”很简单!毕竟它仍然只是 Spring,因此只需要做很少的更改。您需要进行三个直观的更改:在 Maven 中将jar构建更改为war构建:注释掉pom.xml文件中spring-boot-maven-plugin插件的声明,然后将 Maven 的packaging类型更改为war。最后,在您的应用程序中添加一个 Web 入口点。Spring 使用 Servlet 3 Java 配置为您配置几乎所有内容。您只需要给它机会。修改您的Application入口点类,如下所示

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {

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

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(applicationClass);
    }

    private static Class<Application> applicationClass = Application.class;
}


@RestController
class GreetingController {

    @RequestMapping("/hello/{name}")
    String hello(@PathVariable String name) {
        return "Hello, " + name + "!";
    }
} 

这个新的基类 - `SpringBootServletInitializer` - 利用了 Servlet 3 风格的 Java 配置 API,它允许你用代码描述以前只能在 `web.xml` 中描述的内容。这些配置类会在应用程序启动时被发现并调用。这使得 Spring Boot 有机会告诉 Web 服务器有关应用程序的信息,包括各种 Spring 项目通常所需的 `Servlet`、`Filter` 和 `Listener`。

现在可以使用这个新类在内部使用嵌入式 Jetty 或 Tomcat 运行应用程序,也可以将其部署到任何 Servlet 3 容器。如果你有与作为大型应用程序服务器一部分提供的类冲突的类,可能会遇到问题。在这种情况下,请使用构建工具的功能来排除或使相关的 API 成为 `可选` 的。以下是我为了在 JBoss WildFly(以前称为 JBoss AS 的 AS)上启动和运行 Spring Boot REST 服务启动器而必须对 Maven 构建进行的更改。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>org.demo</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>

    <packaging>war</packaging>
	<description>Demo project</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.0.0.BUILD-SNAPSHOT</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
		</dependency>
	</dependencies>

	<properties>
        <start-class>demo.Application</start-class>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.7</java.version>
	</properties>
	<repositories>
		<repository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>http://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>http://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>http://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</pluginRepository>
		<pluginRepository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>http://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</pluginRepository>
	</pluginRepositories>
</project>

然后,我能够重新运行构建并将构建的 `.war` 文件复制到 `$WILDFLY_HOME/standalone/deployments` 目录。

如果应用程序服务器尚未运行,请启动它,然后你应该能够在 `https://127.0.0.1:8080/$YOURAPP/hello/World` 访问该应用程序。再次声明,我用 `$YOURAPP` 代替了你构建的应用程序的名称。

云部署!

关于部署的故事,如果不提及当今增长最快的部署目标:云,那就不会完整!当然,当我们谈论云时,具体说明会有所帮助:如果你谈论的是直接部署到 Amazon Web Services 或 Google Compute Engine,那么它就像往常一样,就像你正在自己的数据中心运行 Linux 机器上的应用程序一样。因为基本上,这就是你正在做的。

Cloud Foundry 和 Heroku 上的 PaaS 部署

如果你尝试将应用程序部署到平台即服务 (PaaS),Spring 的良好可移植性在这里为你提供了许多选择。特别是使用胖 JAR 方法部署到 Heroku,对于 Heroku 来说是现状,因为该平台即服务期望你自带容器!只需将 `java -jar` 命令添加到你的 `Procfile` 中,你就可以开始了。

使用 Cloud Foundry,你可以独立部署应用程序,或者将其作为 `.war` 样式的 Web 应用程序部署。一旦你构建了应用程序(例如,使用 `mvn clean install`)并安装了 `cf` 命令行工具,只需按照我下面的方式回答 `cf push` 命令的提示即可。

➜  cf push --path target/demo-0.0.1-SNAPSHOT.jar

Name> $YOURAPP

Instances> 1

1: 128M
2: 256M
3: 512M
4: 1G
Memory Limit> 256M

Creating $YOURAPP... OK

1: $YOURAPP
2: none
Subdomain> $YOURAPP

1: cfapps.io
2: none
Domain> cfapps.io

Creating route $YOURAPP.cfapps.io... OK
Binding $YOURAPP.cfapps.io to $YOURAPP... OK

Create services for application?> n

Bind other services to application?> n

Save configuration?> y

Saving to manifest.yml... OK
Uploading $YOURAPP... OK
Preparing to start $YOURAPP... OK
-----> Downloaded app package (8.7M)
-----> Java Buildpack source: system
-----> Downloading Open JDK 1.7.0_51 from http://d2vm4m9hl67ira.cloudfront.net/openjdk/lucid/x86_64/openjdk-1.7.0_51.tar.gz (1.4s)
       Expanding Open JDK to .java-buildpack/open_jdk (1.3s)
-----> Downloading Spring Auto Reconfiguration 0.8.7 from http://d2vm4m9hl67ira.cloudfront.net/auto-reconfiguration/auto-reconfiguration-0.8.7.jar (0.0s)
-----> Uploading droplet (43M)
Checking status of app '$YOURAPP'...
  0 of 1 instances running (1 starting)
  0 of 1 instances running (1 starting)
  1 of 1 instances running (1 running)
Push successful! App '$YOURAPP' available at http://$YOURAPP.cfapps.io

应用程序应该已经启动并运行,并且可以从 `http://$YOURAPP.cfapps.io/hello/Cloud%20Foundry` 访问,再次声明,我使用 `$YOURAPP` 作为应用程序名称的占位符。

结论

对于一个小的 `Application` 类和对构建文件的少量调整来说还不错!

Spring Boot 旨在默认情况下即可用于生产环境。这意味着它开箱即用地提供了有用的默认设置,如有必要,可以覆盖这些设置。默认情况下,Spring Boot 提供了嵌入式 Apache Tomcat 构建。默认情况下,Spring Boot 会以最自然的方式为你配置所有内容,从当今的平台到领先的平台即服务,都是如此。

Spring Boot 提供了大量覆盖配置的机会,包括可配置属性和自定义回调。

展望未来,我已经可以看到另外几篇文章将继续讨论有关使用监控和管理工具(JMX 和 JConsole、New Relic 等)管理 Spring Boot 应用程序以及安全问题等内容。Spring Boot 很高兴地为所有这些问题以及更多问题提供了答案。

你的下一步:Boot

随着 Spring Boot 迈向 1.0 版本,其文档正在快速完善,同时还有许多优秀的资源可以继续探索。查看我最喜欢的技巧集锦页面之一,即“如何操作”文档,并且不要忘记查看 Spring IO 指南,其中大部分内容都基于 Spring Boot!

我很乐意在线继续讨论。我想知道你在研究 Spring Boot 时还有什么其他问题需要解答,所以不要害羞。我将于 2014 年 4 月 9 日进行关于 Spring Boot 的虚拟 JUG直播!该活动面向全球,并且是互动的,所以请带上你的问题、评论和反馈。

获取 Spring 新闻通讯

关注 Spring 新闻通讯

订阅

领先一步

VMware 提供培训和认证,以加速你的进步。

了解更多

获得支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部