Маскот языка Kotlin – Котлина

Недавно прочитал книгу "Предметно-ориентированное проектирование" Эрика Эванса и загорелся его принципами. Она наконец позволила мне уложить в голове многие непонятные ранее вещи в программировании. У меня есть объектно-ориентированные языки программирования, фреймворки, схемы типа MVC, и надо с помощью этого как-то реализовать задачу или бизнес-процесс реального мира. Как это все использовать, с чего начать разрабатывать приложение, где писать бизнес-логику – в сервисах, контроллерах или где-то еще? Идея, что проектирование приложения надо начинать с классов-моделей предметной области, реализующих бизнес-логику и хранящих необходимые данные, дала мне ответы на эти вопросы. Сразу все стало понятно, как белый день – слоеная архитектура, MVC и все остальное. Когда модели предметной области на первом месте, все остальное будет на своем. Это далеко не все, чему нас учит DDD (domain-driven design), но с этого можно начать.

Я разрабатываю серверные приложения на языке Kotlin и фреймворке Spring Boot. Обычно в приложениях на нем сущности являются "анемичными", то есть служат только контейнерами для данных и не содержат бизнес-логики, которая располагается в сервисах-синглтонах. По правилам DDD бизнес-логика должна содержаться в моделях, а сервисы должны выполнять только логику, в которой участвуют несколько моделей, логику уровня приложения, а не отдельных моделей. Таким образом, сущности-модели должны иметь возможность обращаться к сервисам, то есть нужна возможность внедрения зависимостей (сервисов и других бинов) в объекты, не управляемые контекстом Spring'а.

Для этого Spring предлагает аннотацию @Configurable. Она позволяет фреймворку внедрять зависимости в объекты, создаваемые в приложении через оператор new.

Чтобы эта магия работала, в приложении должно быть настроено load-time weaving или compile-time weaving, то есть, применительно к аннотации @Configurable, перехват создания объектов и добавление к нему кода для внедрения зависимостей на этапе выполнения или компиляции. С этим мне пришлось повозиться в свое время, понять, чем одно отличается от другого, и как это все настроить.

Мне не очень нравится концепция LTW. Она усложняет запуск, вместе с jar-файлом приложения нужно еще поставлять jar-файл spring-instrument.jar и запускать сервер с параметром -javaagent:spring-instrument.jar.

Вот CTW другое дело, все необходимые действия производятся во время компиляции, сервер как обычно запускается через java -jar ... Для этого используется AspectJ, который запускает свой компилятор ajc для обработки java-файлов. Понятно, что для исходников на языке Kotlin это не сработает. К счастью, AspectJ также умеет работать с уже скомпилированными классами (слава байткод-совместимости Котлина и Джавы).

Для сборки приложений я использую Maven. Плагину aspectj-maven-plugin нужно указать параметр конфигурации weaveDirectories с путем к папке со скомпилированными классами. Соответственно, плагин должен быть запущен в фазе, когда классы уже скомпилированы. Документация по параметру.

Итак, для работы аннотации @Configurable в Spring Boot нужно проделать следующее:

  1. Подключить Maven-плагин aspectj-maven-plugin в фазе process-classes или более поздней.
  2. Указать параметр конфигурации плагина weaveDirectories с путем к папке со скомпилированными классами.
  3. Указать параметр конфигурации плагина aspectLibraries с ссылкой на зависимость spring-aspects.
  4. Объявить аннотацию @EnableSpringConfigured на одном из классов конфигурации приложения.

Таким образом можно настроить AspectJ-CTW в приложении на Spring и языке Kotlin, чтобы работала аннотация @Configurable. Я создал пример минимального проекта на Github, чтобы наглядно показать требуемые настройки для работы @Configurable и других аспектов Spring: spring-boot-aspectj-kotlin-example

Советую прочитать книгу "Предметно-ориентированное проектирование", если еще не. Даже если она не перевернет ваш взгляд на программирование, это в любом случае очень крутая книга.

Поиск