Статьи

Конфигурация Apache Tamaya

После JavaOne 2014, когда тема конфигурации была отменена из списка EE8, Дэвид Блевинс и другие предложили запустить проект Apache по нескольким причинам:

  • Пусть люди с опытом работы в теме идентифицируют общий набор функций.
  • Реализуйте идеи как часть проекта Apache, чтобы предоставить идеи с использованием бесплатной и распространяемой лицензии.
  • Используйте общепринятую проверенную организацию, способную обеспечить успешное принятие. Это было, когда  Apache Tamaya  был помещен в инкубацию. После этого у нас было несколько обсуждений, видеовстреч и электронных писем. В результате  Apache Tamaya  теперь доступен в виде 0.1-инкубатора первого выпуска  , готового к использованию.

Также стоит упомянуть, что Марк Струберг и Герхард Петрачек, ребята из Deltaspike, присоединились к этому проекту и активно участвовали в нем. Я думаю, что стоит более глубоко взглянуть на проект. Об этом и рассказывается в этом блоге.

Проект Apache Tamaya

Как запрос спецификации Java

Apache Tamaya  построен аналогично запросу спецификации Java (JSR). Он представляет собой API, который определяет артефакты, с которыми обычно взаимодействуют пользователи, и предоставляет эталонную реализацию, которая реализует API, поэтому его можно использовать для реальных проектов. Причиной этого являются следующие:

  1. Отделение API от реализации дает вам очень четкое и ясное представление о проблеме. Вы должны изолировать суть вашей проблемы и опустить все виды чрезмерно специфических аспектов. Если все сделано правильно, это приводит к простому и всеобъемлющему API, который в то же время достаточно мощный, чтобы поддерживать по крайней мере большинство или все другие требования (например, использование точек расширения или хуков для плагинов) в адаптированном или дополнительном функционале (иначе интерфейсы / SPI поставщика услуг).
  2. API может быть более независимым, чем эталонная реализация, относительно его требований совместимости. Например, API на основе Java 7 Apache Tamaya фактически также совместим с платформами Java 6 и Java ME.
  3. Вы можете начать с минимального набора функций в API и постепенно расширять его по мере необходимости. Каждое расширение должно быть проверено, если это действительно необходимо или требование не может быть реализовано с использованием существующего API / SPI. Это гарантирует, что ваш API действительно фокусируется на минимальных аспектах, поэтому становится понятным и понятным.
  4. И последнее, но не менее важное, что-то в соответствии с предыдущим пунктом, добавление новых функций не мешает базовому API / реализации, что позволяет очень легко добавлять новые функции. Проект Apache Tamaya также содержит довольно много так называемых расширений, которые зависят только от API, поэтому проект уже доказал, что способен очень эффективно охватить этот аспект.

Единственным отличием от JSR является отсутствие в настоящее время комплекта технической совместимости (TCK), который обеспечивает совместимость различных реализаций API с общим набором правил. Точно так же у нас нет чего-то вроде «спецификации» (но у нас есть очень обширная документация, чем-то очень похожая на спецификацию, также охватывающая многие аспекты / обсуждения, проведенные на этапе оценки для Java EE JSR 2 года назад).

Совместимость

Apache Tamaya в  настоящее время поддерживает как Java 7, так и Java 8. Причины этого в том, что на Java 7 по-прежнему много кода, особенно в корпоративном контексте, и мы хотели, чтобы люди могли использовать Apache Tamaya, прежде чем перейти к платформа Java 8. Тем не менее, API можно легко добавить в вашу сборку maven:

<dependency>
  <groupId>org.apache.tamaya</groupId>
  <artifactId>tamaya-java7-api</artifactId>
  <version>0.1-incubating</version>
</dependency>

Или при использовании его с Java 8:

<dependency>
  <groupId>org.apache.tamaya</groupId>
  <artifactId>tamaya-api</artifactId>
  <version>0.1-incubating</version>
</dependency>

Аналогичным образом может быть добавлен модуль реализации (называемый ядром ), например, для Java 7 и выше:

<dependency>
  <groupId>org.apache.tamaya</groupId>
  <artifactId>tamaya-java7-core</artifactId>
  <version>0.1-incubating</version>
</dependency>

Совместим с Java 8:

<dependency>
  <groupId>org.apache.tamaya</groupId>
  <artifactId>tamaya-core</artifactId>
  <version>0.1-incubating</version>
</dependency>

Основные понятия

Абстракция конфигурации и доступ 

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

public interface Configuration {

  default String get(String key) {...}
  default <T> T get(String key, Class<T> type) {...}
  default Configuration with(ConfigOperator operator) {...}
  default <T> T query(ConfigQuery<T> query) {...}
  <T> T get(String key, TypeLiteral<T> type);   Map<String, String> getProperties();

  // not available for Java 7
  default Optional<String> getOptional(String key) {...}
  default <T> Optional<T> getOptional(String key, Class<T> type) {...}
  default <T> Optional<T> getOptional(String key, TypeLiteral<T> type) {...}
  default Optional<Boolean> getBoolean(String key) {...}
  default OptionalInt getInteger(String key) {...}
  default OptionalLong getLong(String key) {...}
  default OptionalDouble getDouble(String key) {...}
}

Поэтому, глядя на этот интерфейс, можно определить некоторые важные ключевые решения:

  • Доступ к записям конфигурации осуществляется с помощью  строковых  ключей.
  • Значения конфигурации в основном моделируются как строки.
  • Типизированный доступ также поддерживается с использованием Class или  TypeLiteral .
  • Конфигурация может быть доступна ключ за ключом или с помощью полной карты свойств ( getProperties ). Таким образом, существует ограничение, что возвращаемая карта может содержать не все записи, которые также будут доступны при доступе к ним по отдельности. Причина заключается в том, что некоторые источники конфигурации могут не иметь возможности перечислять все записи (или быть  сканируемыми ). 
  • Методы  с параметром query  определяют так называемые функциональные точки расширения, что позволяет добавлять дополнительные функции в качестве операторов / запросов, которые можно применять к конфигурации.
  • Наконец, все методы, возвращающие дополнительные  значения , определяются только в версии API в зависимости от Java 8  . Добавлена ​​поддержка нового  необязательного  артефакта, представленного в Java 8. Аналогичным образом все стандартные методы были заменены в варианте Java 7 соответствующими реализациями абстрактных базовых компонентов, поставляемыми с эталонной реализацией.

Экземпляры конфигурации могут быть доступны из  ConfigurationProvider  одноточечного:

Configuration config = ConfigurationProvider.getConfiguration();

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

Функциональные точки расширения

В предыдущем разделе мы уже упоминали методы  with  и  query . Они принимают в качестве аргумента  ConfigurationOperator  или  ConfigurationQuery <T> , которые определены следующим образом:

@FunctionalInterface
public interface ConfigOperator {
    Configuration operate(Configuration config);
}

@FunctionalInterface
public interface ConfigQuery<T> {
    T query(Configuration config);
}

Таким образом, в основном  ConfigOperator  действует как отображение, которое выводит  конфигурацию  из другой  конфигурации , тогда как  ConfigurationQuery <T>  может возвращать любой вид результата. Обе конструкции позволяют добавлять функциональность несколькими способами, не прибегая к ней в интерфейсе конфигурации, например, такие аспекты, как:

  • Фильтрация конфигурации для конкретных вариантов использования, например, рекомбинация записей или удаление записей вне области действия для определенного варианта использования
  • Маскировка записей или разделов по соображениям безопасности
  • Создание типизированных объектов на основе конфигурации
  • Статистические данные о заданной конфигурации, например, определенные разделы
  • Проверка конфигурации и документация
  • Преобразование конфигурации, например, в представление JSON
  • И многое другое.

Для запуска примеров вы можете взглянуть на  модуль расширения  tamaya-functions , в котором уже реализовано немало аспектов.

Минималистичный пример

Чтобы прояснить ситуацию немного подробнее, давайте создадим небольшой пример, который просто использует базовый механизм, предоставляемый базовой реализацией Tamaya. Давайте предположим, что мы строим небольшой узел с микросервисом, выполняющим простое сложное вычисление процентной ставки (финансовые подробности опущу, см. Https://en.wikipedia.org/wiki/Compound_interest  для получения более подробной информации).

Мы предполагаем, что процентная ставка настроена для этого компонента, поэтому в наш компонент мы просто добавляем следующий код:

BigDecimal interestRate = ConfigurationProvider.getConfiguration()
                .get("com.mycomp.ratecalculator.rate", BigDecimal.class);

При использовании Java 8 мы также можем легко объединить его со значением по умолчанию:

BigDecimal interestRate = ConfigurationProvider.getConfiguration()
                .getOptional("com.mycomp.ratecalculator.rate", bBigDecimal.class)
                .orElse(BigDecimal.of(0.05d));

Учитывая, что мы можем легко реализовать нашу бизнес-логику, также используя тип JSR 354 (см.  Http://javamoney.org/ ):

public class MyRateCalculator implements RateCalculator{

  private BigDecimal interestRate = ConfigurationProvider.getConfiguration()
                .getOptional("com.mycomp.ratecalculator.rate", BigDecimal.class)
                .orElse(BigDecimal.of(0.05d));

  public MonetaryAmount calcRate(MonetaryAmount amt, int periods){
    ...
  }

}

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

  • … как часть настольного приложения.
  • … как часть приложения Java EE.
  • … в контейнере OSGI.
  • … легко как отдельный микро-сервис (с соответствующим API, например, REST).

Как сделать поддержку Tamaya опциональной

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

  • Гарантирует, что Tamaya API находится на вашем пути к классам
  • Дополнительно проверяет, доступна ли  конфигурация  из заданного контекста.
  • Запрос конфигурации  делегатов  для Tamaya или — если не доступен — делегату, переданному из вашей логики, при создании делегата:
import org.apache.tamaya.ext.optional.OptionalConfiguration;

private BigDecimal interestRate = Optional.ofNullable(
                 OptionalConfiguration.of(
                    (k) -> MyConfigMechanism.get(k)) // String get(String key);                  )
                .get("com.mycomp.ratecalculator.rate", BigDecimal.class))
                .orElse(BigDecimal.of(0.05d));

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

Что-то еще?

С точки зрения API в этом нет необходимости. Класс  TypeLiteral,  использовавшийся ранее, является тем же, что также хорошо известно из Java EE (CDI), и единственным другим не упомянутым артефактом является  класс ConfigException  . Конечно, эта функциональность сама по себе очень минималистична, но она точно делает то, что должна: она предоставляет  API-интерфейс для минималистического доступа для конфигурации . И почему мы думаем, что это так важно? Вот почему:

  1. Все, кто пишет компоненты, обычно пишут некоторую логику конфигурации, но все делают это по-разному: разные форматы, местоположения, схемы ключей, переопределения и т. Д. Кроме того, Apache Tamaya также не хочет определять,  что  вы конфигурируете,  где находится  ваша конфигурация и как ее можно  переопределить . Но мы определяем общий API для доступа к конфигурации.
  2. Принимая во внимание, что компоненты из разных групп легче интегрировать в проект, но также в конкретный корпоративный контекст, поскольку все компоненты ссылаются на один и тот же механизм конфигурации.
  3. Более того, при использовании основных  правил конфигурации Tamaya  можно более или менее игнорировать, поскольку механизмы Tamaya (я буду представлять соответствующий SPI в следующем блоге здесь) уже предоставляют эти механизмы, поэтому они могут быть адаптированы по мере необходимости.
  4. Точно так же  форматы,  используемые для конфигурации, а также тот факт, что конфигурация может храниться локально в файловой системе или быть  удаленно  распределенной, больше не важны.

Это само по себе должно сделать Apache Tamaya очень интересной и важной частью любой архитектуры приложений или модулей. Кроме того, его SPI приносит дополнительные преимущества, особенно в более крупных контекстах предприятия. Мы рассмотрим SPI и расширения в следующих постах блога здесь. Так что следите за обновлениями!

Как всегда комментарии приветствуются. Если кто-то еще думает внести свой вклад в проект, пожалуйста, свяжитесь с нами по  адресу mailto: dev@tamaya.incbuator.apache.org .

И, конечно же, помогите нам распространить слово, писать твиты, блоги, принимать его, использовать его, любить его! 

Хотите услышать больше?

Хотите узнать больше о Apache Tamaya? Посетите наш  сайт проекта  или даже лучше присоединиться и увидеть нас на