Я использовал АОП много с Java. Похоже, что традиционные подходы к Java могут быть легко использованы с Котлином. Учитывая Котлин акцент на неизменности JDK прокси, как представляется, наиболее подходящим решением в Котлин при условии, что вы следуете за один и тот же интерфейс, первый (лучше сказать, черта-первая в Котлин) стиль программирования, например:АОП с Kotlin
trait MyService {
fun add(a: Int, b: Int): Int
}
class MyServiceImpl: MyService {...}
Так что теперь можно легко написать аспект, скажем, в Spring/AOP, и применить его к экземплярам MyServiceImpl. Следует отметить, что сгенерированные прокси на основе интерфейса Java могут быть более предпочтительными разработчиками Kotlin, поскольку cglib требует избавиться от окончательного (т. Е. Прибегать к открытым классам в Котлине) и использовать безпараметрические публичные конструкторы для каждого класса, которые должны быть обернуты прокси-серверами AOP ,
В то же время, сгенерированные прокси-серверы на основе интерфейса Java, к сожалению, налагают значительное снижение производительности, поэтому я задаюсь вопросом, возможно ли программирование AOP более интуитивно или изначально для Kotlin в некоторых случаях.
Итак, рассмотрим следующий пример, когда я хочу использовать АОП:
- аргументы Logging и возвращать результат каждого метода открытой от службы.
- Запуск транзакции перед вызовом функции и ее закрытие после завершения вызова функции (фиксация/откат в зависимости от того, было ли исключение выбрано при выполнении определенного вызова службы).
Наиболее эффективный, но, к сожалению, самые многословное решение перебора в вышеупомянутом примере с MyService/MyServiceImpl может выглядеть следующим образом:
class MyServiceLoggingWrapper(val delegate: MyService): MyService {
val logger = LoggerFactory.getLogger(this.javaClass)
override fun add(a: Int, b: Int): Int {
val result = delegate.add(a, b);
logger.info("MyService.add({}, {}) = {}", a, b, result);
return result;
}
}
class MyServiceTxWrapper(val delegate: MyService, val txManager: TransactionManager): MyService {
// similar lengthy implementation
}
ЛСС сложность такого подхода является O (N * K), где N - это число методов, а K - ряд аспектов, которые я хочу применить.
То, что я ищу, является эффективным (как с точки зрения производительности, так и LoC) решением для аспектов в Kotlin предпочтительнее, не прибегая к созданным cglib прокси, поскольку они налагают слишком много ограничений, таких как прощание с конечными классами, а не беззазорные публичные конструкторы.
Я предполагаю, что любой инструмент AOP, который работает в двоичных файлах Java, также работает с двоичными файлами Kotlin, но я никогда не пробовал. –
Я попробовал (все они работают), но я обнаружил, что некоторые ограничения существующих библиотек (cglib) расстраивают разработчика Kotlin, который принял стиль программирования Kotlin. Для тестирования Kotlin я написал простой веб-сайт (классическая трехуровневая архитектура) с Spring MVC + Freemarker + JDBC + Spring TX (Управление транзакциями). Он работает как прелесть. – Alex
О, и, кстати, библиотеки AOP широко используются разработчиками приложений. Обычно он включает в себя, но не ограничиваясь: создание протоколирования, профилирование, перевод исключений, повторные попытки с отсрочкой, управление транзакциями и т. Д. И т. Д. Поэтому я считаю, что было бы неплохо в будущем иметь более интуитивный стиль создания прокси-серверов AOP в Котлине - это может быть супер полезной функцией. Наследственные способы сделать это подразумевают серьезные компромиссы - производительность (прокси-серверы интерфейса Java) или выразительность (cglib) – Alex