Перейти к основному содержимому

Spring Cloud — начальная загрузка

· 13 мин. чтения

1. Обзор

Spring Cloud — это платформа для создания надежных облачных приложений. Платформа облегчает разработку приложений, предоставляя решения многих распространенных проблем, возникающих при переходе в распределенную среду.

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

С другой стороны, когда мы используем микросервисный подход, возникают другие проблемы:

  • Экстернализация конфигурации, чтобы она была гибкой и не требовала перестроения службы при изменении.
  • Обнаружение службы
  • Скрытие сложности сервисов, развернутых на разных хостах

В этой статье мы создадим пять микрослужб: сервер конфигурации, сервер обнаружения, сервер шлюза, службу книг и, наконец, службу оценки. Эти пять микросервисов образуют надежное базовое приложение для начала разработки облака и решения вышеупомянутых проблем.

2. Сервер конфигурации

При разработке облачного приложения одной из проблем является поддержка и распространение конфигурации для наших служб. Мы действительно не хотим тратить время на настройку каждой среды перед горизонтальным масштабированием нашего сервиса или рисковать нарушениями безопасности, внедряя нашу конфигурацию в наше приложение.

Чтобы решить эту проблему, мы объединим всю нашу конфигурацию в один репозиторий Git и подключим его к одному приложению, которое управляет конфигурацией для всех наших приложений. Мы собираемся настроить очень простую реализацию.

Чтобы узнать больше деталей и увидеть более сложный пример, ознакомьтесь с нашей статьей Spring Cloud Configuration .

2.1. Настраивать

Перейдите на https://start.spring.io и выберите Maven и Spring Boot 2.2.x. ``

Установите для артефакта значение «config » . В разделе зависимостей найдите «config server» и добавьте этот модуль. Затем нажмите кнопку « Создать », и мы сможем загрузить zip-файл с предварительно настроенным проектом внутри и готовым к работе.

В качестве альтернативы мы можем создать проект Spring Boot и вручную добавить некоторые зависимости в файл POM.

Эти зависимости будут общими для всех проектов:

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/>
</parent>

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

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

Давайте добавим зависимость для сервера конфигурации:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>

Для справки мы можем найти последнюю версию на Maven Central ( spring-cloud-dependencies , test , config-server ).

2.2. Весенняя конфигурация

Чтобы включить сервер конфигурации, мы должны добавить некоторые аннотации к основному классу приложения:

@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {...}

@EnableConfigServer превратит наше приложение в сервер конфигурации.

2.3. Характеристики

Давайте добавим application.properties в src/main/resources :

server.port=8081
spring.application.name=config

spring.cloud.config.server.git.uri=file://${user.home}/application-config

Наиболее важной настройкой для сервера конфигурации является параметр git.uri . В настоящее время установлен относительный путь к файлу, который обычно разрешается в c:\Users\{имя пользователя}\ в Windows или /Users/{имя пользователя}/ в *nix. Это свойство указывает на репозиторий Git, в котором хранятся файлы свойств для всех других приложений. При необходимости можно установить абсолютный путь к файлу.

Совет : на компьютере с Windows предваряйте значение «file:///», на *nix используйте «file://».

2.4. Git-репозиторий

Перейдите в папку, определенную spring.cloud.config.server.git.uri , и добавьте папку application-config . CD в эту папку и введите git init . Это инициализирует репозиторий Git, где мы можем хранить файлы и отслеживать их изменения.

2.5. Бежать

Запустим конфигурационный сервер и убедимся, что он работает. В командной строке введите mvn spring-boot:run . Это запустит сервер.

Мы должны увидеть этот вывод, указывающий, что сервер работает:

Tomcat started on port(s): 8081 (http)

2.6. Конфигурация начальной загрузки

На наших последующих серверах мы хотим, чтобы свойства их приложений управлялись этим сервером конфигурации. Чтобы сделать это, нам на самом деле нужно сделать немного курицы и яйца: настроить свойства в каждом приложении, которое знает, как общаться с этим сервером.

Это процесс начальной загрузки, и каждое из этих приложений будет иметь файл с именем bootstrap.properties . Он будет содержать такие же свойства, как application.properties, но с изюминкой:

Родительский Spring ApplicationContext сначала загружает bootstrap.properties . Это очень важно, чтобы Config Server мог начать управлять свойствами в application.properties . Именно этот специальный ApplicationContext также будет расшифровывать любые зашифрованные свойства приложения.

Разумно хранить эти файлы свойств отдельно. bootstrap.properties предназначен для подготовки сервера конфигурации, а application.properties — для свойств, специфичных для нашего приложения. Однако технически можно поместить свойства приложения в bootstrap.properties .

Наконец, поскольку Config Server управляет свойствами нашего приложения, может возникнуть вопрос, зачем вообще нужен файл application.properties ? Ответ заключается в том, что они по-прежнему пригодятся в качестве значений по умолчанию, которых, возможно, нет в Config Server.

3. Открытие

Теперь, когда мы позаботились о конфигурации, нам нужен способ, чтобы все наши серверы могли найти друг друга. Мы решим эту проблему, настроив сервер обнаружения Eureka . Поскольку наши приложения могут работать с любой комбинацией IP/порта, нам нужен центральный реестр адресов, который может служить для поиска адресов приложений.

При инициализации нового сервера он связывается с сервером обнаружения и регистрирует свой адрес, чтобы с ним могли связываться другие пользователи. Таким образом, другие приложения могут использовать эту информацию при выполнении запросов.

Чтобы узнать больше деталей и увидеть более сложную реализацию обнаружения, загляните в статью Spring Cloud Eureka .

3.1. Настраивать

Мы снова перейдем к start.spring.io . Установите артефакт на «обнаружение». Найдите «eureka server» и добавьте эту зависимость. Найдите «config client» и добавьте эту зависимость. Наконец, сгенерируйте проект.

В качестве альтернативы мы можем создать проект Spring Boot , скопировать содержимое POM с сервера конфигурации и поменять местами эти зависимости:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>

Для справки, мы найдем пакеты на Maven Central ( config-client , eureka-server ).

3.2. Весенняя конфигурация

Добавим конфиг Java в основной класс:

@SpringBootApplication
@EnableEurekaServer
public class DiscoveryApplication {...}

@EnableEurekaServer настроит этот сервер в качестве сервера обнаружения с помощью Netflix Eureka . Spring Boot автоматически обнаружит зависимость конфигурации от пути к классам и найдет конфигурацию на сервере конфигурации.

3.3. Характеристики

Теперь мы добавим два файла свойств:

Во- первых, мы добавляем bootstrap.properties в src/main/resources :

spring.cloud.config.name=discovery
spring.cloud.config.uri=http://localhost:8081

Эти свойства позволят серверу обнаружения запрашивать сервер конфигурации при запуске.

И во-вторых, мы добавляем discovery.properties в наш репозиторий Git.

spring.application.name=discovery
server.port=8082

eureka.instance.hostname=localhost

eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

Имя файла должно соответствовать свойству spring.application.name .

Кроме того, мы сообщаем этому серверу, что он работает в зоне по умолчанию, это соответствует настройке региона клиента конфигурации. Мы также говорим серверу не регистрироваться в другом экземпляре обнаружения.

В рабочей среде у нас было бы более одного из них для обеспечения избыточности в случае сбоя, и этот параметр был бы верным.

Давайте зафиксируем файл в репозиторий Git. В противном случае файл не будет обнаружен.

3.4. Добавить зависимость к серверу конфигурации

Добавьте эту зависимость в файл POM сервера конфигурации:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

Для справки мы можем найти пакет на Maven Central ( eureka-client ).

Добавьте эти свойства в файл application.properties в src/main/resources сервера конфигурации:

eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5
eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

3.5. Бежать

Запустите сервер обнаружения с помощью той же команды mvn spring-boot:run . Вывод из командной строки должен включать:

Fetching config from server at: http://localhost:8081
...
Tomcat started on port(s): 8082 (http)

Остановите и перезапустите службу конфигурации. Если все в порядке, вывод должен выглядеть так:

DiscoveryClient_CONFIG/10.1.10.235:config:8081: registering service...
Tomcat started on port(s): 8081 (http)
DiscoveryClient_CONFIG/10.1.10.235:config:8081 - registration status: 204

4. Шлюз

Теперь, когда у нас решены проблемы с конфигурацией и обнаружением, у нас все еще есть проблема с доступом клиентов ко всем нашим приложениям.

Если мы оставим все в распределенной системе, то нам придется управлять сложными заголовками CORS, чтобы разрешить кросс-доменные запросы на клиентах. Мы можем решить эту проблему, создав сервер шлюза. Это будет действовать как обратный прокси-сервер, перенаправляющий запросы от клиентов на наши внутренние серверы.

Сервер шлюза — отличное приложение в микросервисной архитектуре, поскольку он позволяет отправлять все ответы с одного хоста. Это устранит необходимость в CORS и даст нам удобное место для решения распространенных проблем, таких как аутентификация.

4.1. Настраивать

К настоящему времени мы знаем упражнение. Перейдите на https://start.spring.io . Установите артефакт на «шлюз». Найдите «zuul» и добавьте эту зависимость. Найдите «config client» и добавьте эту зависимость. Найдите «eureka discovery» и добавьте эту зависимость. Наконец, сгенерируйте этот проект.

В качестве альтернативы мы могли бы создать приложение Spring Boot со следующими зависимостями:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>

Для справки, мы можем найти пакет на Maven Central ( config-client , eureka-client , zuul ).

4.2. Весенняя конфигурация

Добавим конфигурацию в основной класс:

@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class GatewayApplication {...}

4.3. Характеристики

Теперь мы добавим два файла свойств:

bootstrap.properties в src/main/resources :

spring.cloud.config.name=gateway
spring.cloud.config.discovery.service-id=config
spring.cloud.config.discovery.enabled=true

eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

gateway.properties в нашем репозитории Git

spring.application.name=gateway
server.port=8080

eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5

zuul.routes.book-service.path=/book-service/**
zuul.routes.book-service.sensitive-headers=Set-Cookie,Authorization
hystrix.command.book-service.execution.isolation.thread.timeoutInMilliseconds=600000

zuul.routes.rating-service.path=/rating-service/**
zuul.routes.rating-service.sensitive-headers=Set-Cookie,Authorization
hystrix.command.rating-service.execution.isolation.thread.timeoutInMilliseconds=600000

zuul.routes.discovery.path=/discovery/**
zuul.routes.discovery.sensitive-headers=Set-Cookie,Authorization
zuul.routes.discovery.url=http://localhost:8082
hystrix.command.discovery.execution.isolation.thread.timeoutInMilliseconds=600000

Свойство zuul.routes позволяет нам определить приложение для маршрутизации определенных запросов на основе сопоставления URL-адресов ant. Наше свойство указывает Zuul направлять любой запрос, поступающий на /book-service/** , в приложение с spring.application.name book - service . Затем Zuul выполнит поиск хоста на сервере обнаружения, используя имя приложения, и перенаправит запрос на этот сервер.

Не забудьте зафиксировать изменения в репозитории!

4.4. Бежать

Запустите приложения конфигурации и обнаружения и подождите, пока приложение конфигурации зарегистрируется на сервере обнаружения. Если они уже запущены, нам не нужно их перезапускать. После этого запустите сервер шлюза. Сервер шлюза должен запускаться на порту 8080 и регистрироваться на сервере обнаружения. Вывод из консоли должен содержать:

Fetching config from server at: http://10.1.10.235:8081/
...
DiscoveryClient_GATEWAY/10.1.10.235:gateway:8080: registering service...
DiscoveryClient_GATEWAY/10.1.10.235:gateway:8080 - registration status: 204
Tomcat started on port(s): 8080 (http)

Одна ошибка, которую легко совершить, — запустить сервер до того, как сервер конфигурации зарегистрируется в Eureka. В этом случае мы увидим лог с таким выводом:

Fetching config from server at: http://localhost:8888

Это URL-адрес и порт по умолчанию для сервера конфигурации, указывающие на то, что у нашей службы обнаружения не было адреса, когда был сделан запрос конфигурации. Просто подождите несколько секунд и повторите попытку, как только сервер конфигурации зарегистрируется в Eureka, проблема будет решена.

5. Служба бронирования

В микросервисной архитектуре мы можем создавать столько приложений, сколько необходимо для достижения бизнес-целей. Часто инженеры делят свои услуги по областям. Мы будем следовать этому шаблону и создадим книжный сервис для обработки всех операций с книгами в нашем приложении.

5.1. Настраивать

Еще раз. Перейдите на https://start.spring.io . Установите артефакт на «книжный сервис». Найдите «web» и добавьте эту зависимость. Найдите «config client» и добавьте эту зависимость. Найдите «eureka discovery» и добавьте эту зависимость. Создайте этот проект.

В качестве альтернативы добавьте эти зависимости в проект:

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

Для справки, мы можем найти пакет на Maven Central ( config-client , eureka-client , web ).

5.2. Весенняя конфигурация

Давайте изменим наш основной класс:

@SpringBootApplication
@EnableEurekaClient
@RestController
@RequestMapping("/books")
public class BookServiceApplication {
public static void main(String[] args) {
SpringApplication.run(BookServiceApplication.class, args);
}

private List<Book> bookList = Arrays.asList(
new Book(1L, "ForEach goes to the market", "Tim Schimandle"),
new Book(2L, "ForEach goes to the park", "Slavisa")
);

@GetMapping("")
public List<Book> findAllBooks() {
return bookList;
}

@GetMapping("/{bookId}")
public Book findBook(@PathVariable Long bookId) {
return bookList.stream().filter(b -> b.getId().equals(bookId)).findFirst().orElse(null);
}
}

Мы также добавили контроллер REST и поле, заданное нашим файлом свойств, чтобы возвращать значение, которое мы установим во время настройки.

Теперь добавим книгу POJO:

public class Book {
private Long id;
private String author;
private String title;

// standard getters and setters
}

5.3. Характеристики

Теперь нам просто нужно добавить два файла свойств:

bootstrap.properties в src/main/resources :

spring.cloud.config.name=book-service
spring.cloud.config.discovery.service-id=config
spring.cloud.config.discovery.enabled=true

eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

book-service.properties в нашем Git-репозитории:

spring.application.name=book-service
server.port=8083

eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5
eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

Зафиксируем изменения в репозитории.

5.4. Бежать

После запуска всех других приложений мы можем запустить книжный сервис. Вывод консоли должен выглядеть так:

DiscoveryClient_BOOK-SERVICE/10.1.10.235:book-service:8083: registering service...
DiscoveryClient_BOOK-SERVICE/10.1.10.235:book-service:8083 - registration status: 204
Tomcat started on port(s): 8083 (http)

Как только он будет запущен, мы можем использовать наш браузер для доступа к конечной точке, которую мы только что создали. Перейдите к http://localhost:8080/book-service/books, и мы получим объект JSON с двумя книгами, которые мы добавили в наш контроллер. Обратите внимание, что мы не обращаемся к сервису книг напрямую через порт 8083, а идем через сервер шлюза.

6. Служба рейтинга

Как и наш книжный сервис, наш рейтинговый сервис будет управляемым доменом сервисом, который будет обрабатывать операции, связанные с рейтингами.

6.1. Настраивать

Еще раз. Перейдите на https://start.spring.io . Установите артефакт на «рейтинг-сервис». Найдите «web» и добавьте эту зависимость. Найдите «config client» и добавьте эту зависимость. Найдите « eureka discovery » и добавьте эту зависимость. Затем создайте этот проект.

В качестве альтернативы добавьте эти зависимости в проект:

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

Для справки, мы можем найти пакет на Maven Central ( config-client , eureka-client , web ).

6.2. Весенняя конфигурация

Давайте изменим наш основной класс:

@SpringBootApplication
@EnableEurekaClient
@RestController
@RequestMapping("/ratings")
public class RatingServiceApplication {
public static void main(String[] args) {
SpringApplication.run(RatingServiceApplication.class, args);
}

private List<Rating> ratingList = Arrays.asList(
new Rating(1L, 1L, 2),
new Rating(2L, 1L, 3),
new Rating(3L, 2L, 4),
new Rating(4L, 2L, 5)
);

@GetMapping("")
public List<Rating> findRatingsByBookId(@RequestParam Long bookId) {
return bookId == null || bookId.equals(0L) ? Collections.EMPTY_LIST : ratingList.stream().filter(r -> r.getBookId().equals(bookId)).collect(Collectors.toList());
}

@GetMapping("/all")
public List<Rating> findAllRatings() {
return ratingList;
}
}

Мы также добавили контроллер REST и поле, заданное нашим файлом свойств, чтобы возвращать значение, которое мы установим во время настройки.

Добавим рейтинг POJO:

public class Rating {
private Long id;
private Long bookId;
private int stars;

//standard getters and setters
}

6.3. Характеристики

Теперь нам просто нужно добавить два файла свойств:

bootstrap.properties в src/main/resources :

spring.cloud.config.name=rating-service
spring.cloud.config.discovery.service-id=config
spring.cloud.config.discovery.enabled=true

eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

rating-service.properties в нашем репозитории Git:

spring.application.name=rating-service
server.port=8084

eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5
eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

Зафиксируем изменения в репозитории.

6.4. Бежать

После запуска всех других приложений мы можем запустить службу оценки. Вывод консоли должен выглядеть так:

DiscoveryClient_RATING-SERVICE/10.1.10.235:rating-service:8083: registering service...
DiscoveryClient_RATING-SERVICE/10.1.10.235:rating-service:8083 - registration status: 204
Tomcat started on port(s): 8084 (http)

Как только он будет запущен, мы можем использовать наш браузер для доступа к конечной точке, которую мы только что создали. Перейдите по адресу http://localhost:8080/rating-service/ratings/all , и мы получим JSON со всеми нашими оценками. Обратите внимание, что мы не обращаемся к службе рейтинга напрямую через порт 8084, а проходим через шлюзовой сервер.

7. Заключение

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

Как всегда, мы можем найти этот исходный код на GitHub .