2015-02-06 4 views
6

Я использовал АОП много с 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 прокси, поскольку они налагают слишком много ограничений, таких как прощание с конечными классами, а не беззазорные публичные конструкторы.

+0

Я предполагаю, что любой инструмент AOP, который работает в двоичных файлах Java, также работает с двоичными файлами Kotlin, но я никогда не пробовал. –

+0

Я попробовал (все они работают), но я обнаружил, что некоторые ограничения существующих библиотек (cglib) расстраивают разработчика Kotlin, который принял стиль программирования Kotlin. Для тестирования Kotlin я написал простой веб-сайт (классическая трехуровневая архитектура) с Spring MVC + Freemarker + JDBC + Spring TX (Управление транзакциями). Он работает как прелесть. – Alex

+0

О, и, кстати, библиотеки AOP широко используются разработчиками приложений. Обычно он включает в себя, но не ограничиваясь: создание протоколирования, профилирование, перевод исключений, повторные попытки с отсрочкой, управление транзакциями и т. Д. И т. Д. Поэтому я считаю, что было бы неплохо в будущем иметь более интуитивный стиль создания прокси-серверов AOP в Котлине - это может быть супер полезной функцией. Наследственные способы сделать это подразумевают серьезные компромиссы - производительность (прокси-серверы интерфейса Java) или выразительность (cglib) – Alex

ответ

1

Я не являюсь пользователем Kotlin, но учитывая тот факт, что он нацелен на JVM, я бы предложил попробовать полномасштабный AspectJ вместо прокси-основанного подхода AOP lite, такого как Spring AOP. AspectJ не требует/не использует динамические прокси, он генерирует байт-код либо во время компиляции, либо после компиляции (двоичное переплетение), или даже во время загрузки класса (время загрузки).

+0

Извините за поздний ответ. Проблема, с которой я сталкивалась с cglib и компиляцией во времени, является нетривиально сгенерированными конструкторами в классах Kotlin (я использовал конструктор calloke-style). После безуспешной попытки исправить пару странных ошибок я сдался и начал использовать прокси-серверы интерфейса JDK, поскольку они требуют только черт (они эквивалентны интерфейсам java). Спасибо за предложение в любом случае. – Alex

+0

Spring использует только динамические прокси для интерфейсов. Для конкретных классов используется CGLib - по существу, время загрузки, поскольку в точке, которую должен загружать класс, генерируется исполняемый подкласс класса времени исполнения. И, конечно же, Spring также может быть проинструктирован использовать ткачество AspectJ вместо динамических прокси + CGLib. –

Смежные вопросы