Научная статья на тему 'Управление настройками Java-приложений с использованием механизма аннотаций'

Управление настройками Java-приложений с использованием механизма аннотаций Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
436
26
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
ПРОГРАММИРОВАНИЕ / JAVA / БИБЛИОТЕКА / ФРЕЙМВОРК / АННОТАЦИИ / НАСТРОЙКИ

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Денисов Виктор Сергеевич

В статье рассматривается библиотека options-util, реализующая управление настройками времени выполнения для Java-приложений. Конфигурация свойств приложения и их отображение на источники конфигурационной информации настраивается при помощи аннотаций над специальными интерфейсами настроек, что упрощает внедрение библиотеки, гарантирует строгую типизацию и обеспечивает самодокументированность кода.

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Управление настройками Java-приложений с использованием механизма аннотаций»

Денисов В.С.

Московский государственный университет им. М.В.Ломоносова, ф-т ВМК, науч. сотр.

УПРАВЛЕНИЕ НАСТРОЙКАМИ JAVA-ПРИЛОЖЕНИЙ С ИСПОЛЬЗОВАНИЕМ

МЕХАНИЗМА АННОТАЦИЙ

КЛЮЧЕВЫЕ СЛОВА

Программирование, Java, библиотека, фреймворк, аннотации, настройки. АННОТАЦИЯ

В статье рассматривается библиотека options-util, реализующая управление настройками времени выполнения для Java-приложений. Конфигурация свойств приложения и их отображение на источники конфигурационной информации настраивается при помощи аннотаций над специальными интерфейсами настроек, что упрощает внедрение библиотеки, гарантирует строгую типизацию и обеспечивает самодокументированность кода.

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

Цели разработки библиотеки

Библиотека options-util разрабатывается для упрощения управления настройками времени выполнения в проектах различного уровня и назначения на платформе Java, исполняющихся как на классических серверных и настольных системах, так и в облачных вычислительных сервисах. Библиотека должна использовать все современные языковые, технические и функциональные возможности платформы Java 8, а также применять передовые подходы и эффективные шаблоны, сложившиеся в области Java-программирования. После окончания разработки библиотека должна соответствовать следующим функциональным требованиям1: Общие требования:

• независимость от целевой платформы;

• использование юнит- и интеграционных тестов;

• поддержка внедрения зависимостей.

• Специальные требования:

• минимальное количество зависимостей;

• описание конфигурационной информации с помощью аннотаций;

• самодокументация объектов конфигурации;

• поддержка облачных сервисов;

• безопасность типов (type safety);

• поддержка различных источников информации о настройках/постоянных хранилищ;

• расширяемость;

• поддержка сложных структур данных;

• поддержка валидации и конверсии значений;

• поддержка извещений об изменении настроек;

• поддержка структурированной информации.

На сегодня библиотека options-util находится в состоянии альфа-версии, исходный текст библиотеки доступен на платформе GitHub [3], а первый релиз, версия 0.1, может быть получен из Maven-репозитория Maven Central [4].

Примеры использования библиотеки

Основным понятием библиотеки options-util является интерфейс настроек (options interface), определяющий все настройки (свойства), используемые приложением, с помощью набора геттеров и сеттеров, которые, в свою очередь, декорируются аннотациями, содержащими

1 Более подробно существующие библиотеки управления настройками рассматриваются в [1], а требования излагаются и анализируются в [2]

дополнительную семантическую информацию, обеспечивающую функционал библиотеки. В самом простом случае интерфейс настроек может выглядеть так, как на Рис. 1: BPirsisWïice (FersistenceTyps. 2Rflii.SZEWTi t>ublic interface TestOptions exteiuis Options { 80ption(key « "int") int getlntC); void 3etlnt(int vaiue);

OOprion[defauxtvaiue ■ "5")

int Çfetlnt*! thD e£ ault();

void setlntWithDefault(int value);

}

Рис. 1. Простейшее использование интерфейса настроек

Даже такой простой пример показывает ряд интересных возможностей библиотеки:

• интерфейс может быть декорирован аннотацией @PersistenceProvider, определяющей тип постоянного хранилища, используемого для хранения настроек;

• все интерфейсы настроек наследуют общий интерфейс org.plukh.options.Options, который определяет некоторые общие полезные методы для работы с настройками (в частности, загрузку и сохранение настроек).

• аннотация @Option передаёт библиотеке дополнительную информацию о конфигурационном свойстве, в данном случае — значение ключа свойства в постоянном хранилище для первого свойства и значение по умолчанию для второго.

Для получения доступа к настройкам приложение должно породить экземпляр объекта, реализующего интерфейс настроек, за эту операцию отвечает фабрика OptionsFactory, см. Рис. 2:

TestOptions options = (TestOptions) OptionsFactorY-ff^tOptionsInstaпсе(ТезtOptions.class);

Рис. 2. Порождение объекта настроек с помощью фабрики OptionsFactory

Фабрика порождает динамический прокси-объект, реализующий доступ к настройкам при вызове методов интерфейса. Всем классам предоставляется один и тот же экземпляр прокси-объекта, таким образом, все компоненты приложения получают в своё распоряжение одно и то же множество настроек. Прокси-объекты потоко-безопасны и могут быть свободно использоваться одновременно несколькими потоками в многопоточном приложении. Реализация функциональных требований

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

Независимость от целевой платформы. Библиотека не делает никаких предположений относительно платформы, на которой она выполняется, в том числе:

• не предполагается наличие на платформе файловой системы, кроме случаев, когда используется один из провайдеров файлового постоянного хранилища;

• не используется манипуляция байт-кодом;

• не использует иных способов журналирования, кроме вывода на консоль, и то только в том случае, когда информация не может быть передана никаким иным образом;

• не порождает потоков и не использует связанные с ними функции;

• использует небольшое количество памяти и ресурсов процессора (менее 2 Мб динамической памяти для интерфейса из нескольких сот свойств);

Использование юнит- и интеграционных тестов. Библиотека покрыта набором тестов, обеспечивающим покрытие 74% строк; непокрытые строки, в основном, принадлежат тривиальным методам — геттерам, сеттерам, конструкторам и т. п. По мере обнаружения и исправления ошибок в коде библиотеки, пишутся дополнительные регрессионные тесты.

Поддержка внедрения зависимостей. На текущий момент, поддержка технологий внедрения зависимостей не реализована. В будущих версиях планируется поддержка фреймворков Spring [5] и Guice [6].

Минимальное количество зависимостей. Текущая версия не имеет внешних зависимостей

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

Описание конфигурационной информации с помощью аннотаций. Как можно видеть из примера на Рис. 1, библиотека options-util предоставляет аннотации, с помощью которых приложение может передать библиотеке различную дополнительную информацию о свойствах настроек.

Самодокументация объектов конфигурации. Рассмотрим интерфейс настроек на Рис. 3: @Рееsistencе(РееsistencеТуре.PBQPEHT3ES_riiE) public interface TweetCарtuEeOptions entends Options { @0ption(keY = "jdbc.url") StEing getDatabaselJRL ( ) ;

@0ption(keY = "workerthreads", defaultValue = "5") int getWoEfeeEThEeads();

@CollectionOption(bacfeingClass = LiELkedBlocliingQueue.class, tEansientOption = true) Queue getWoEkeEQueue();

> I

Рис. 3. Интерфейс настроек TweetCaptureOptions

Аналогично примеру на Рис. 1, даже не зная специфики библиотеки options-util, можно сделать ряд предположений о настройках, определяемым данным интерфейсом:

• интерфейс определяет ровно три настройки (свойства);

• конфигурация приложения доступна в файле свойств (properties);

• первое свойство возвращает строковое значение - URL для доступа к базе данных; значение доступно только на чтение (так как сеттер отсутствует); наконец, значение ключа в постоянном хранилище — "jdbc.url";

• второе свойство возвращает целое число — количество рабочих потоков в данном приложении; значение ключа и значение по умолчанию также определяются аннотацией;

• наконец, третье свойство возвращает очередь, реализуемую классом LinkedBlockingQueue из Java Collections Framework; для него установлен признак "transient" ("временный"), и значение этого свойства не будет читаться или записываться в постоянное хранилище. Легко видеть, что использование аннотаций вместе со стандартными для Java принципами

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

Поддержка облачных сервисов. Прототипная реализация облачного модуля реализует поддержку конфигурационных файлов в облачном хранилище AWS Simple Storage Service [7]. Конфигурационный файл может определяться идентификатором виртуальной машины EC2 или упорядоченным множеством тэгов, передаваемых библиотеке в аннотации @AWSTags.

Безопасность типов (type safety). Библиотека options-util использует возможности строгой типизации Java для обеспечения безопасности типов — проверка типа гарантирована во время компиляции приложения.

Поддержка различных источников информации о настройках/постоянных хранилищ. Текущая версия библиотеки поддерживает чтение конфигурации из .properties и XML-файлов, а также из источников данных JDBC. Поддерживаются механизмы расширения, позволяющие добавлять реализации произвольных постоянных хранилищ. Дополнительно, в будущих версиях запланирована поддержка следующих источников конфигурационных данных в базовом модуле:

• файлы JSON;

• файлы .properties, XML и JSON через протокол HTTP;

• файлы .properties, XML и JSON из classpath;

• значения переменных окружения Java и переменных окружения ОС;

• поддержка JMX;

Запланированы облачные модули для платформ Amazon Web Services, Google Cloud Computing и Microsoft Azure, со специфическими для каждой платформы источниками

информации. Также запланировано сцепление нескольких источников информации в один мета-источник.

Расширяемость. Библиотека поддерживает несколько точек расширения: провайдеры постоянных хранилищ, провайдер цепочки постоянных хранилищ, обработчик типа свойства и др. По мере развития библиотеки список доступных точек будет естественным образом увеличиваться.

Поддержка сложных структур данных. Библиотека options-util поддерживает произвольные типы данных Java в качестве объектов, хранящих настройки приложения. Единственным требованием является предоставление разработчиком конвертера, обеспечивающего сериализацию/десериализацию значений объектов в строковые значения, доступные для редактирования пользователями2. Библиотека содержит следующие встроенные конверторы:

• все примитивные типа Java и их объектные аналоги;

• java.lang.String;

• java.util.Date;

• все классы, реализующие интерфейс java.util.Collection.

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

Поддержка валидации и конверсии значений. Наличие ошибок в файлах, редактируемых пользователями, абсолютно неизбежно. В задачи обработчиков типа свойства (как встроенных, так и внешних) входит максимально терпимое отношение к незначительным ошибкам в форматировании данных3, а также корректная обработка существенных ошибок.

При получении настроек из постоянного хранилища приложение может выбрать одну из двух стратегий обработки входных данных (представляющих из себя строковые значения, предназначенные для десериализации в соответствующие Java-объекты с помощью обработчиков типа) — гибкую и строгую. При выборе строгой стратегии библиотека выбросит исключение при первой же фатальной ошибке конверсии, и никакие значения настроек не будут изменены — эта стратегия хорошо подходит для не интерактивных приложений, которые, как правило, не могут продолжить выполнение без получения конфигурации. Гибкая политика позволяет считать и применить все корректные значения настроек, а после этого — получить от библиотеки список ошибок конверсии — эта стратегия подходит для интерактивных приложений, которые, например, могут предложить пользователю ввести корректные значения для свойств, которые были считаны с ошибками.

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

Литература

1. V. Denisov. Overview of Java application configuration frameworks. International Journal of Open Information Technologies

ISSN: 2307-8162, 1(6), 2013. URL: http://injoit.org/index.php/j1/article/view/33

2. V. Denisov. Functional requirements for a modern application configuration framework. International Journal of Open

Information Technologies ISSN: 2307-8162 3(10), 2015. URL: http://injoit.org/index.php/j1/article/view/236

3. Options-util: annotation-based Java configuration helper library. URL: https://github.com/options-util/options-util

4. URL: http://search.maven.org/#artifactdetails%7Corg.plukh%7Coptions-util%7C0.1%7Cjar

5. Spring Framework. URL: http://projects.spring.io/spring-framework/

6. Google Guice. URL: https://github.com/google/guice

7. V. Denisov. Annotations-driven configuration framework for Java applications. International Journal of Open Information

Technologies ISSN: 2307-8162 3(10), 2015. URL: http://injoit.org/index.php/j1/article/view/237.

2 В обязанности разработчика конвертера входит задача определения такой схемы сериализации/десериализации, которая, с одной стороны, была бы понятна и доступна для редактирования без применения специальных инструментов, а с другой — обеспечивала однозначность сериализации/десериализации

3 Так, встроенный обработчик типа java.util.Date пробует применить к текстовому значению даты/времени несколько различных длинных, средних и коротких форматов, прежде чем выдать ошибку конверсии

i Надоели баннеры? Вы всегда можете отключить рекламу.