快人一步
VMware 提供培训和认证,助力您加速前进。
了解更多Spring Boot 1.3 中有一些有趣的新特性,这些特性现已在 Brixton 发布分支的 Spring Cloud 中可用。Spring Cloud 的 Angel 发布分支与 Spring Boot 1.3 部分不兼容,因此在升级时有一些重要事项需要注意。本文旨在帮助您了解这些变化并更新现有应用以使用新特性。对于将 Spring 项目的新版本引入现有代码库的一般情况,本文也应有所帮助。
提示:您可以使用
mvn dependency:tree
或gradle dependencies
命令列出项目中的依赖项并检查版本。
如果您使用的是旧版本的 Spring Boot,您的 Maven POM 中可能包含类似以下内容:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.7.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
或
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.7.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
或者,如果您使用 Gradle,则类似以下内容:
buildscript {
ext {
springBootVersion = '1.2.7.RELEASE'
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
要升级到 Spring Boot 1.3.0,您只需将上面的 '1.2.7' 更改为 '1.3.0'。目前看来很简单。
提示:要查看包含最新版 Spring Boot 的“典型”Maven POM,您可以使用
curl start.spring.io/pom.xml
命令。要添加 Spring Cloud,您可以附加-d style=cloud-config-client
。可以通过添加-d bootVersion=1.3.1.BUILD-SNAPSHOT
(例如) 来更改 Spring Boot 版本。对于 Gradle,可以使用build.gradle
代替pom.xml
来执行同样的操作。
由于 Spring Cloud 构建在 Spring Boot 之上,因此找到能够协同工作的组合可能令人困惑且困难。接下来我们将描述几种升级场景,并展示您在依赖管理方面可以实现的目标。
通常,最大的变化在于升级(Spring Boot 1.2 到 1.3,或 Spring Cloud Angel 到 Brixton)。如果您从 Spring Initializr 下载的项目,它将使用 Spring Boot 父 POM
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
并在 <dependencyManagement>
部分中使用 Spring Cloud BOM
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Angel.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在 Gradle 中,您将看到类似这样的内容:
buildscript {
ext {
springBootVersion = '1.2.7.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-starter-parent:Angel.SR4"
}
}
简单地更新 Spring Boot 版本在这两种情况下都不会奏效,因为 Spring Cloud Angel BOM 包含旧版本的 Spring Boot 和 Spring(以及其他一些东西)。因此,我们确实需要同时升级 Spring Boot 和 Spring Cloud。例如在 Maven 中:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.M3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在 Gradle 中:
buildscript {
ext {
springBootVersion = '1.3.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-starter-parent:Brixton.M3"
}
}
注意:Brixton.M2 及所有早期版本的 Spring Cloud 不兼容 Spring Boot 1.3.0.RELEASE。您至少需要 Brixton.M3。
假设您想使用 Spring Boot 的 snapshot 版本,或在 1.3.1 发布时升级到该版本,但 Spring Cloud 没有明确依赖于您想要的 Spring Boot 版本的版本。
在 Maven 中,请记住,如果您使用现成的父 POM 之一,它们包含 <dependencyManagement>
并且会优先。考虑到这一点,如果您使用这些父 POM,请务必使用依赖集与您所需版本最接近的父 POM(在此场景中是 Boot 的父 POM)。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.1.BUILD-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.M3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
原则上,Gradle 更简单,因为它没有“父级”的概念。实践中,除非您手动应用依赖管理插件,否则 Spring Boot 插件无法与依赖管理使用不同版本。因此,您需要在 build.gradle
中做一些调整
buildscript {
ext {
springBootVersion = '1.3.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath "io.spring.gradle:dependency-management-plugin:0.5.3.RELEASE"
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: "io.spring.dependency-management"
...
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-starter-parent:Brixton.M3"
mavenBom "org.springframework.bootspring-boot-starter-parent:1.3.1.BUILD-SNAPSHOT"
}
}
apply plugin: 'spring-boot'
规则是您必须 a) 手动导入依赖管理插件,并且在 Spring Boot 插件之前导入,b) 在应用 Spring Boot 插件之前声明 dependencyManagement
。完成这些步骤后,您可以在 dependencyManagement
声明中列出依赖项,并且最后一个声明的会生效(与 Maven 相反)。
注意:这种对声明顺序的敏感性是当前版本工具的“特性”。未来版本中可能会有所不同。有关更多详细信息,请参阅 Gradle 工具中的此问题。
如果您不使用现成的父 POM,则可以自由使用一个不包含 <dependencyManagement>
的父 POM,这使得控制更容易。在这种情况下,您需要将 Spring Boot 和 Spring Cloud 都放在 <dependencyManagement>
中,并且顺序很重要:Maven 中第一个声明的生效(Gradle 中是最后一个)。例如,要在 Maven 中使用 Spring Boot 1.3.1.BUILD-SNAPSHOT 和 Spring Cloud Brixton.M3:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.1.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.M3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
请注意,在 Maven 和 Gradle 中,BOM 的顺序都很重要:如果在顶层(显式声明的依赖项)存在冲突,Maven 中通常是第一个声明的生效(Gradle 中是最后一个)。与 Maven 的一个巨大区别是父级是特殊的:如果它包含 <dependencyManagement>
,它总是生效。
要了解特定依赖项版本是否会按您需要的方式解析是很复杂的。这取决于 BOM 的顺序,以及您的依赖项在传递依赖树中的深度。例如,Spring Boot BOM 为 spring-core
声明了显式的(一级)依赖管理,但没有针对任何其他 Spring Framework jar 包(这些是通过引用 Spring Framework BOM 引入的)。规则是第一次声明的生效,但整个树(包括所有 BOM)都会被包含,从顶部逐层搜索。
注意:如果没有 Spring Boot(或 Spring 依赖管理)插件,Gradle 没有这个“最后一个生效”的规则。要使用“原生”Gradle 构建实现同样的效果,通常需要仔细且繁琐地手动修复传递依赖项版本。
如果您想将某个依赖项的版本提升到 Spring Boot 和 Spring Cloud BOM 中指定的版本之上,事情可能会变得复杂。概括来说,有两种选择:属性和附加 BOM。第一种(属性)适用于现成的父 POM,而另一种不适用。第二种(更多 BOM)仅在您感兴趣的依赖项存在可用 BOM 的情况下才有效,并且仅在传递依赖项与您的需求不冲突的情况下才有效。例如,所有 Spring Cloud 项目都有自己的 BOM,Spring Framework 也是如此,这是一个好的开始。
Spring Boot 父 POM(以及您使用的 Spring Cloud 父 POM,因为它继承自 Spring Boot 父 POM)将其所有依赖项版本提取到 <properties/>
中。因此,您通常只需更改属性值即可。Maven 中的示例:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<spring.version>4.2.4.BUILD-SNAPSHOT</spring.version>
</properties>
Gradle 中对应的功能是 ext
属性,例如:
ext['spring.version'] = '4.2.4.BUILD-SNAPSHOT'
Spring Framework 有自己的 BOM,因此我们可以使用它来管理 Spring 版本。在 Maven 中使用自定义父级(不包含 <dependencyManagement>
):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.2.4.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
注意:这个示例实际上不适用于 Spring Boot 父 POM(除非它碰巧具有相同的
<spring.version/>
),因为 Spring Framework 版本已经被父级固定了。要在使用 Spring Boot 父级的同时使用 Spring Framework snapshot 版本,最好采用属性方法(如上所述)。
在 Gradle 中更简单(因为没有父级来设置冲突的版本):
dependencyManagement {
imports {
mavenBom "org.springframework:spring-framework-bom:4.2.4.BUILD-SNAPSHOT"
mavenBom "org.springframework.boot:spring-boot-starter-parent:1.3.0.RELEASE"
}
}
依赖管理很困难,但希望我们通过概述升级 Spring Boot 和 Spring Cloud 时的一些常见场景来减轻难度。根据您选择 Maven 还是 Gradle,行为会略有不同,但至少如果您选择 Gradle 并使用 Spring Boot 插件,差异会最小化。归根结底,Spring 项目有不同的发布计划,因此总可能存在冲突,但它们通常会朝着收敛的方向发展,所以如果您等待足够长的时间,情况会趋于平衡。像 Spring Cloud、Spring Boot 和 Spring IO Platform 这样的伞形项目也有助于消除障碍:如果您可以使用其中一个来管理所有依赖项,事情就会简单得多。
Spring Guides 中的示例应用现在都已更新到 Spring Boot 1.3,即使这意味着它们依赖于 Spring Cloud 的一个里程碑版本(这仅适用于 Zuul 代理示例)。许多应用不再需要 Spring Cloud。如果您需要 Spring Cloud 的 GA 版本,现在需要停留在 Spring Boot 1.2 版本。该组合的示例可以从 git 历史记录中获取。