Статьи

Миграция приложений Spring Cloud из Spring Boot 1.2 в 1.3

В Spring Boot 1.3 есть несколько интересных новых функций , которые теперь доступны в Spring Cloud в выпуске Brixton. Выпуск Angel Cloud от Spring Cloud частично несовместим с Spring Boot 1.3, поэтому при обновлении необходимо учитывать некоторые важные вещи. Эта статья поможет вам перемещаться по изменениям и обновлять любые существующие приложения, чтобы использовать новые функции. Это также должно быть полезно в целом при попытке перенести новые версии проектов Spring в существующие кодовые базы.

ПРЕДУПРЕЖДЕНИЕ. Правила разрешения зависимостей в случае конфликта при использовании Gradle представляются неясными и могут зависеть от большего, чем мы говорим в статье. Это стало известно в результате тестирования кода в блоге, поэтому мы все еще обсуждаем, как решить проблемы. Это может быть ошибка в инструменте Gradle .

СОВЕТ: Вы можете использовать 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». Пока все просто.

СОВЕТ: чтобы увидеть «типичный» Maven POM с самой последней версией Spring Boot, вы можете curl start.spring.io/pom.xml. Чтобы добавить Spring Cloud вы можете добавить -d style=cloud-config-client. Версия Spring Boot может быть изменена путем добавления -d bootVersion=1.3.1.BUILD-SNAPSHOT(например). Чтобы сделать то же самое для использования Gradle build.gradleвместо pom.xml.

Использование Spring Cloud с Spring Boot

Поскольку Spring Cloud построен на основе Spring Boot, может быть сложно и сложно найти комбинацию, которая работает вместе. Далее мы опишем несколько сценариев обновлений и покажем, чего можно ожидать с помощью управления зависимостями.

Большое обновление

В целом самое большое изменение произойдет при обновлении (Spring Boot 1.2 до 1.3 или Spring Cloud Angel до Brixton). Если вы загрузили проект из Spring Initializr, он будет использовать POM родительского загрузчика Spring:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.2.7.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>

и спецификация Spring Cloud в <dependencyManagement>разделе:

<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 есть старые версии 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 загрузки 1.3.0.RELEASE. Вам нужен как минимум Brixton.M3.

Обновление Spring Boot Beyond 1.3.0

Предположим, что вы хотите использовать моментальные снимки Spring Boot или обновиться до 1.3.1 после его выпуска, но Spring Cloud не имеет версии, которая явно зависит от версии Boot, которую вы хотите.

В Maven помните, что если вы используете одну из готовых родительских POM, которые они содержат <dependencyManagement>и будут иметь приоритет. Имея это в виду, если вы используете эти родительские 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 может применяться с другой версией, нежели управление зависимостями (хотя рекомендуется всегда использовать самый последний плагин). Пример:

buildscript {
    ext {
        springBootVersion = '1.3.0.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 
    }
}
dependencyManagement {
  imports { 
    mavenBom "org.springframework.bootspring-boot-starter-parent:1.3.1.BUILD-SNAPSHOT" 
    mavenBom "org.springframework.cloud:spring-cloud-starter-parent:Brixton.M3" 
  }
}

Использование Maven с пользовательским родителем

Если вы не используете готовые родительские POM, у вас есть свобода, если вы используете тот, который не содержит <dependencyManagement>, и это облегчает управление. В этом случае вам нужно поставить Spring Boot и Spring Cloud в, <dependencyManagement>и порядок значим: выигрывает первый. Например, чтобы использовать Spring Boot 1.3.1.BUILD-SNAPSHOT и Spring Cloud Brixton.M3 в Maven:

<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 порядок спецификаций является существенным: тот, который объявлен первым, обычно побеждает, если существует конфликт на верхнем уровне (явно объявленные зависимости). Разница с Maven в том, что родитель особенный: если он содержит, <dependencyManagement>он всегда побеждает.

Понять, будет ли конкретная версия зависимости разрешаться так, как вам нужно, сложно. Это зависит от порядка спецификаций и глубины в транзитивном дереве зависимостей, в котором объявлена ​​ваша зависимость. Например, в Spring Boot BOM объявляется явное (уровень 1) управление зависимостями для, spring-coreно не для каких-либо других jar-файлов Spring Framework (которые вводятся посредством ссылки на Spring Framework BOM). Правило гласит, что при первом объявлении он выигрывает, но включается все дерево (включая все спецификации) с поиском сверху, уровень за уровнем.

ПРИМЕЧАНИЕ: Gradle не имеет этого правила «первый выиграл» без плагина Spring Boot (или Spring Dependency Management). Чтобы сделать то же самое с «нативной» сборкой Gradle, часто требуется тщательная и утомительная работа по исправлению версий транзитивных зависимостей.

Дальнейшее управление версиями зависимостей

Если вы хотите изменить версию зависимости, выходящую за рамки, указанные в спецификациях Spring Boot и Spring Cloud, все может стать сложным. Вообще говоря, есть 2 варианта: свойства и дополнительные спецификации. Первое (свойства) работает с готовыми родительскими POM, а другое — нет. Второй (более ВОМ) работает только при наличии в спецификации доступны для зависимости вас интересует, и только тогда , когда переходные зависимости не вступают в противоречие с вашими требованиями. Например, все проекты Spring Cloud имеют собственную спецификацию, как и Spring Framework, так что это только начало.

свойства

Родительское POM Spring Boot (и Spring Cloud, если вы его используете, поскольку оно наследуется от Boot) извлекает все версии зависимостей <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 имеет собственную спецификацию, поэтому мы можем использовать ее для управления версиями 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>

ПРИМЕЧАНИЕ: этот пример на самом деле не будет работать с POM-модулем Spring Boot (если только он не совпадает <spring.version/>), потому что версия Spring Framework уже исправлена ​​родителем. Для использования родителя Spring Boot со снимком Spring Framwork лучше использовать подход свойств (см. Выше).

В 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 разные графики выпуска, поэтому всегда могут быть конфликты, но они, как правило, всегда движутся к конвергенции, поэтому, если вы будете ждать достаточно долго, все выровняется. Проекты Umbrella, такие как 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.