将 Spring Cloud 应用从 Spring Boot 1.2 迁移到 1.3

工程 | Dave Syer | 2015年11月25日 | ...

在Brixton发布列车中的Spring Cloud中,现在可以使用Spring Boot 1.3中的一些有趣的新功能。 Spring Cloud的Angel发布列车与Spring Boot 1.3部分不兼容,因此升级时需要注意一些重要事项。本文将帮助您了解这些更改,并更新任何现有应用程序以使用新功能。在尝试将Spring项目的新版本应用到现有代码库时,它通常也很有用。

提示:您可以使用mvn dependency:treegradle 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 Boot 与 Spring Cloud

由于 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" 
  }
}

注意:Spring Cloud 的 Brixton.M2 和所有早期版本都与 Spring Boot 1.3.0.RELEASE *不*兼容。您至少需要 Brixton.M3。

升级 Spring Boot 到 1.3.0 以上版本

假设您想使用 Spring Boot 快照,或者在发布时升级到 1.3.1,但是 Spring Cloud 没有明确依赖于您所需 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 工具中的此问题

使用自定义父级与 Maven

如果您不使用现成的父 POM,则可以自由使用 *不* 包含<dependencyManagement>的父 POM,这使得控制更加容易。在这种情况下,您需要将 Spring Boot 和 Spring Cloud 都放入<dependencyManagement>中,并且顺序很重要:第一个获胜(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>

BOM 的顺序

请注意,在 Maven 和 Gradle 中,BOM 的顺序都很重要:如果在顶级(显式声明的依赖项)存在冲突,则首先声明的 BOM 通常在 Maven 中获胜(Gradle 中的最后一个)。Maven 的一个重大区别在于父级是特殊的:如果它包含<dependencyManagement>,它总是获胜。

理解特定依赖项版本是否会以您需要的方式解析非常复杂。它取决于 BOM 的顺序,*以及*您的依赖项声明在传递依赖树中的深度。例如,Spring Boot BOM 为spring-core声明了显式(级别 1)依赖管理,但没有为任何其他 Spring Framework jar 声明(这些 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 也一样,因为它继承自 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'

其他BOM

Spring框架有自己的BOM,因此我们可以用它来管理Spring版本,而不是在Maven中使用自定义父POM(不包含`<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框架版本已由父POM固定。要将Spring Boot父POM与Spring框架快照一起使用,最好使用属性方法(如上所述)。

在Gradle中更简单(因为没有父POM来设置冲突的版本)。

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指南中的示例应用程序现已全部更新到Spring Boot 1.3,即使这意味着它们依赖于Spring Cloud的里程碑版本(这仅适用于Zuul代理示例)。许多不再需要Spring Cloud。如果您需要Spring Cloud的GA版本,目前您需要保留Spring Boot 1.2。该组合的示例可以从git历史记录中提取。

获取Spring新闻通讯

通过Spring新闻通讯保持联系

订阅

领先一步

VMware提供培训和认证,以加快您的进步。

了解更多

获得支持

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

了解更多

即将举行的活动

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

查看全部