Статьи

Сравнительный анализ между Spring AOP и AspectJ

Аспектно-ориентированное программирование ( AOP ) — это парадигма программирования, целью которой является повышение модульности за счет разделения сквозных задач. АОП предоставляет аспекты, которые обеспечивают модульность задач по объектам. Хотя сегодня доступно несколько платформ AOP, здесь мы будем различать только две популярные среды: Spring AOP и AspectJ. Это должно помочь вам выбрать правильную технологию для использования в вашем проекте на основе ключевой информации.

Spring AOP отличается от большинства других сред AOP. Цель Spring AOP — не предоставить наиболее полную реализацию AOP (хотя Spring AOP вполне способен); это скорее обеспечение тесной интеграции между реализацией AOP и Spring IoC, чтобы помочь решить общие проблемы в корпоративных приложениях. Учитывая тот факт, что Spring AOP прост в реализации, эта цель Spring является одной из самых сильных сторон, если вы планируете модульное решение сквозных задач для компонентов Spring. Но та же цель также действует как ограничение, если вы собираетесь модулировать свои сквозные задачи в простых Java-объектах вместо компонентов Spring. С другой стороны, AspectJ может быть использован для модульного кросса между простыми Java-объектами, но требует хорошего знания предмета перед реализацией.

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

Цель Spring AOP — обеспечить тесную интеграцию между реализацией AOP и Spring IoC, чтобы помочь решить общие проблемы в корпоративных приложениях. Определите, хотите ли вы разделить сквозные задачи (такие как управление транзакциями / ведение журнала или профилирование) между компонентами Spring и / или между простыми объектами. Если ваше приложение новое, вы можете легко выбрать использование Spring в вашей среде. С другой стороны, если вы поддерживаете существующее приложение (которое не имплантировано с помощью Spring), AspectJ становится естественным выбором. Чтобы более подробно остановиться на этом, скажем, что вы хотите добавить «ведение журнала» в качестве рекомендации для вашего приложения и хотели бы отслеживать ход выполнения. Этот совет может быть применен только к точкам соединения Spring-компонентов при использовании Spring AOP.

Например, при настройке следующего pointcut для appbeans.xml совет по ведению журнала будет применяться при вызове метода сервиса для bean-компонента myServices.

<!—Configuration snippet in appbeans.xml -->

  <bean id="myServices" class="com.ashutosh.MyServicesImpl " />

  <aop:config>

    <aop:aspect id="loggingAspect" ref="logging">

       <aop:around method="log" pointcut="execution(public * *(..))"/>

   </aop:aspect>

 </aop:config --> 

// Java file calling service method

ApplicationContext beans =newClassPathXmlApplicationContext("appbeans.xml");

MyServices myServices = (MyServices) beans.getBean("myServices");

myServices.service(); // Logging advice applied here

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

например

// MyServices service method

public void service() {

  performOperation();// Logging advice not going to apply here

}

Если вы хотите применить рекомендации по вызову метода для объекта «this», вам потребуется взять объект currentProxy и вызвать для него метод.

// MyServices service method

public void service() {

  // Logging advice going to apply here

  ((MyServices) AopContext.currentProxy()).performOperation();

}

Точно так же, если вы собираетесь вызывать метод для объекта, вам придется изменить ссылку на Spring bean, если вы хотите применить совет.

public void service() {

  MyObject obj = new MyObject();

  Obj.performOperation();// Logging advice not going to apply here

}

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

public void service() {

  MyObject obj = new MyObject();

 Obj.performOperation();// Logging advice not going to apply here

 ApplicationContext beans =newClassPathXmlApplicationContext("appbeans.xml");

 MyObject obj =(MyObject) beans.getBean("myObject");

 obj.performOperation()// Logging advice applied here

}

С другой стороны, вы можете применять рекомендации к любому объекту Java, использующему «AspectJ», без необходимости создавать / настраивать bean-компонент в любом файле.  

Еще один фактор, который вы должны учитывать, — если вы хотите выполнять ткачество во время компиляции и / или во время посткомпиляции / выполнения. Spring поддерживает только ткачество во время выполнения. Если у вас есть несколько команд, работающих над несколькими модулями (в результате получается несколько jar-файлов, т.е. один jar для каждого модуля), которые написаны с использованием Spring. Если один из членов команды хочет применить рекомендации по ведению журнала для всего проекта (здесь приведен пример ведения журнала для добавления сквозного подхода) ко всем компонентам Spring (т. Е. Включая файлы JAR, упакованные другой группой), это можно легко сделать, настроив аспект в их собственном файле конфигурации Spring. Это возможно благодаря поддержке Spring ткачества во время выполнения.

<!—Configuration -->

<bean id="myServices" class="com.ashutosh.MyServicesImpl " />

 <aop:config>

  <aop:aspect id="loggingAspect" ref="logging">

      <aop:around method="log" pointcut="execution(public * *(..))"/>

  </aop:aspect>

</aop:config -->

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

Поскольку Spring основан на шаблонах прокси (использующих CGLIB), он имеет ограничение, заключающееся в том, что вы не можете применять сквозные задачи для bean-компонентов, которые являются «конечными». Поскольку прокси требует подкласса Java-класса, это невозможно, если вы используете ключевое слово «final».

Например, применение ключевого слова final к бину Spring MyServicesImpl и настройка точки перехода, например, «execute (public * * (..))» , приведет к исключению времени выполнения, поскольку Spring не сможет создать прокси для MyServicesImpl.

// Configuration file

<bean id="myServices" class="com.ashutosh.MyServicesImpl" />

//Java file

public final classMyServicesImpl {

  ---

}

В таких сценариях вы можете рассмотреть AspectJ, который поддерживает ткачество времени компиляции и не создает для него прокси.

Точно так же, если вы хотите применить сквозные проблемы в статических и / или конечных методах, это может оказаться невозможным. Это потому, что Spring основан на шаблоне прокси. Поскольку статические и / или конечные методы не могут быть переопределены, это приведет к исключению времени выполнения, если вы настроите применение рекомендаций к таким методам. В таких случаях вы можете рассмотреть возможность использования AspectJ, который поддерживает ткачество во время компиляции и не будет создавать для него прокси.

Вы, конечно, хотели бы использовать подход, который легко реализовать. Поскольку Spring AOP поддерживает аннотации, проще создавать и настраивать свой аспект с помощью аннотации @Aspect. В случае AspectJ вам может понадобиться создать свой аспект с использованием файлов .aj (в этом случае вы напишите Java, который вы хотели бы модульно) и вам нужно будет скомпилировать ваш код с помощью ajc (AspectJ Compiler). Поэтому, если вы уверены, что вышеупомянутое ограничение не может быть препятствием для вашего проекта, перейдите к Spring AOP.

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

Например, создание аспекта со следующим pointcut с последующим

public aspectLogging {

  Object around() : execution(public * * (..))

  Sysytem.out.println(thisJoinPoint.getSignature());

  return proceed();

}

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

Поэтому, если вы хотите применить сквозную задачу, используя более простой подход к бинам Spring, и бины не имеют модификатора «final», и аналогичным образом метод не имеет модификатора «static / final», перейдите к Весенний АОП. Напротив, если вы хотите применить сквозную озабоченность по поводу упомянутых ограничений или хотите применить заботу о простом коде Java, выберите AspectJ. Вы можете также объединить оба мира, поскольку Spring поддерживает то же самое.

Ссылка: http://docs.spring.io/spring/docs/3.0.x/reference/aop.html