Одной из наиболее интересных возможностей Spring Cloud является его расширение. Вы можете расширить для поддержки других облаков, улучшения поддержки уже существующих, для поддержки новых сервисов, новых подключений — и все это без изменения самого кода Spring Cloud. В этой статье мы рассмотрим эту возможность. Прочитайте, пожалуйста, первую и вторую статьи из этой серии, если вы ещё не читали их, чтобы получить достаточную информацию.
Три оси расширения
Spring Cloud предоставляет расширяемость по трем ортогональным направлениям. Вы можете расширять его в одном из этих направлений, а ортогональность гарантирует, что вы будуте извлекать пользу из других.
- Cloud Platforms: На данный момент Spring Cloud поддерживает Cloud Foundry, Heroku и локально настроенное облако(протестировать локально в облачной среде), но вы не ограничены этим выбором. Вы можете добавить вашу собственную облачную платформу и использовать остальные возможности Spring Cloud, такие как Spring Java Config
- Cloud Services: Облачные платформы предлагают различные сервисы от реляционных СУБД до обмена сообщениями. Сервисы, предложенные каждой из платформ, очень различаются, даже для множества установок на одной и той же платформе. Это в основном верно для PaaS-платформ, таких как Cloud Foundry, где закрытые экземпляры Cloud Foundry, как правило, имеют сервисы, специфичные для каждой установки. Spring Cloud предлагает простой способ для расширение сервисов за пределами ядра приложения. Также как и для расширения облачной платформы, вы не можете изменить Spring Cloud код для расширения новых сервисов, но вы по-прежнему сможете использовать другие части
- Frameworks: Spring Cloud в настоящее время поддерживает Spring Framawork через spring-service-connector модуль. Кроме того, ничего, кроме этого модуля, в Spring Cloud не зависит от Spring. Таким образом, вы должны иметь возможность использовать другие части из любых JVM-фреймворков или расширить из для фреймворка, добавив новый модуль
В предыдущей статье мы рассмотрели как вы можете использовать CloudFactory
и Cloud
для программного использования Spring Cloud. Когда дело доходит до расширяемости, вы не будете работать таким образом; вместо этого, вы реализуете другие типы в модуле ядра. Давайте рассмотрим их.
Расширяемость Cloud Platform
Главный тип, с которым вам нужно ознакомиться для расширения Spring Cloud для новой облачной платформы — это CloudConnector
, в виде простого интерфейса с тремя методами:
public interface CloudConnector {
boolean isInMatchingCloud();
ApplicationInstanceInfo getApplicationInstanceInfo();
List<ServiceInfo> getServiceInfos();
}
Метод isInMatchingCloud()
должен изучить его окружение, чтобы решить, работает ли он в правильном окружении. К примеру, Cloud Foundry коннектор проверяет на наличие переменной окружения VCAP_APPLICATION
, в то время как Heroku коннектор смотрит на существование переменной окружения DYNO
. Метод getApplicationInstanceInfo()
возвращает список, где каждый элемент содержит достаточно информации о том, как приложению подключиться к каждому из сервисов. Точная информация содержится в каждом ServiceInfo
объекте для каждой реализации(ServiceInfo
для этого имеет только один метод getId()
).
После того, как вы создадите реализацию CloudConnector
, вам необходимо как-то оповестить об этом Spring Cloud . Для всех расширений Spring Cloud использует единый механизм, основанный на ServiceLoader. В частности, для расширения платформы Spring Cloud это сводится к включению файла /META-INF/services/org.springframework.cloud.CloudConnector
, в котором содержится запись с полным именем класса реализации. Как правило, вы будете связывать этот файл вместе с реализацией и поддерживающих классов. Затем, все, что нужно сделать приложению, это включить этот jar в classpath.
Расширяемость сервиса
Интерфейс ServiceInfoCreator
предоставляет точку расширения для работы с новым сервисом.
public interface ServiceInfoCreator<SI extends ServiceInfo, SD> {
public boolean accept(SD serviceData);
public SI createServiceInfo(SD serviceData);
}
Параметр SI
определяет, каким образом будет создан ServiceInfo
, тогда как SD
параметр исходный тип данных сервиса, с которым можно работать. Исходный тип данных сервиса зависит от облачной платформы. К примеру, в Cloud Foundry это будет Map
, основанный на переменной окружения VCAP_SERVICES
, в то время как в Heroku это будет пара, состоящая из переменные окружения конкретного сервиса и их значения. Поскольку исходный тип данных зависит от платформы, то делается реализация от ServiceInfoCreator
. Метод accept()
анализирует данные сервиса и определяет, возможно ли обработать их. Если да, то метод createServiceInfo()
должен вернуть ServiceInfo
объект. Если это совершенно новый сервис, то возможно вам придется реализовать ServiceInfo
для того, чтобы вы могли использовать один из существующих.
После того, как вы реализовали ServiceInfoCreator
, вы должны оповестить Spring Cloud об этом. Здесь применяется та же идея, которая обсуждалась ранее для расширения облачной платформы. В этом случае имя файла зависит от используемого CloudConnector
. Для Cloud Foundry это будет /META-INF/services/org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator
(теоретически, CloudConnector
реализация может быть решена за счет использования другого механизма расширения, но Spring Cloud не рекомендует этого).
Как обсуждалось в предыдущей статье, разработчик облачного приложения может работать напрямую с ServiceInfo
объектом. В связи с этим, если вы просто реализуете ServiceInfoCreator
, вы бы уже имели некоторую выгоду. Кроме того, работа с сырым ServiceInfo
объектом может быть не оценено некоторыми разработчиками приложений, т.к. вы реализуете следующее расширение с таким же успехом.
Расширяемость фреймворка
Последней точкой расширения является ServiceConnectorCreator
. Его задачей является изменение ServiceInfo
в подключение к сервису, что соответствует взаимодействию фреймворка с используемым приложением. К примеру, в облаке MysqlServiceInfo
превращается в DataSource
объект. По умолчанию, Spring Cloud поддерживает коннекторы для DataSource
, а также некоторым Spring Data и Spring AMQP типам. Если вы хотите расширить Spring Cloud для других фреймворков или добавить поддержку других Spring Data типов(таких как Neo4J, Elasticsearch, Cassandra), либо Spring-совместимых типов(например, S3), но пока не поддерживаемые Spring Cloud, то это та точка расширения, которая вам нужна.
public interface ServiceConnectorCreator<SC, SI extends ServiceInfo> {
SC create(SI serviceInfo, ServiceConnectorConfig serviceConnectorConfig);
...
}
Здесь парочка методов, однако вы можете как обычно расширяться от AbstractServiceConnectorCreator
, который берет на себя всю реализацию. SC
параметр привязан к типу создаваемого подключения, такого как DataSource
, в то время как SI
параметр означает тип ServiceInfo
с которым возможна работа.
Метод create()
в составе ServiceInfo
объекта и объекта конфигурации, который содержит информацию конкретного сервиса в виде объединения параметров. Это необходимо для того, чтобы использовать эти параметры для создания соответствующего подключения.
После того, как реализация будет готова, просто поместите её в файл /META-INF/services/org.springframework.cloud.service.ServiceConnectorCreator
. Spring Cloud будет использовать механизм Service Loader, упомянутый ранее.
Итог
Как видите, Spring Cloud предлагает существенное расширение по всей платформе, сервисам и направлениям фреймворка. В следующий раз вы столкнетесь с новыми видами, вы должны быть в состоянии расширять Spring Cloud для работы с ними. Если вы можете открыть код ваших расширений, дайте нам знать, чтобы мы могли продемонстрировать их другим с пользой для других. Если это достаточно распостраненное расширение, сделайте pull request.