Главная » Spring » Внедрение аспектов AspectJ

0

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

Например, точки сопряжения с конструкторами удобно исполь- зовать для применения советов к операциям создания объектов. В отличие от конструкторов в других объектно-ориентированных языках, конструкторы в языке Java отличаются от обычных методов, что не позволяет применять к ним аспекты Spring, основанные на прокси-объектах.

Аспекты расширения AspectJ независимы по отношению к Spring. Они могут быть вплетены в любое Java-приложение, включая при- ложения на основе Spring, но сам фреймворк при этом остается практически непричастен к ним.

Любой, хорошо спроектированный аспект, скорее всего, будет за- висеть от других классов, играющих вспомогательную роль. Если выполнение совета аспекта зависит от одного или более классов, можно вручную создать их экземпляры вместе с аспектом. Или, еще лучше, использовать прием внедрения зависимостей для связыва- ния компонентов с аспектами AspectJ.

Для иллюстрации создадим новый аспект в нашем примере

«Spring Idol». В любом состязании должен участвовать судья, по- этому создадим аспект с использованием расширения AspectJ, пред- ставляющий судью, и назовем его JudgeAspect.

Листинг 5.9. Реализация судьи в конкурсе талантов в виде аспекта AspectJ

package com.springinaction.springidol;

public  aspect  JudgeAspect  { public  JudgeAspect()  {}

pointcut performance() : execution(* perform(..)); after() returning() : performance() {

System.out.println(criticismEngine.getCriticism());

}

// внедряется

private CriticismEngine criticismEngine;

public   void   setCriticismEngine(CriticismEngine   criticismEngine)   { this.criticismEngine     =     criticismEngine;

}

}

Основная цель аспекта JudgeAspect – в том, чтобы дать коммента- рий к выступлению по его завершении. Срез множества точек со- пряжения performance() в листинге 5.9 соответствует методу perform(). При объединении его с советом after() returning() получается аспект, реагирующий на завершение выступления.

Самое интересное, что можно заметить в листинге 5.9, – сам судья не дает собственных комментариев. Вместо этого аспект JudgeAspect использует вспомогательный объект CriticismEngine, вы- зывая его  метод getCriticism(),  возвращающий критический  ком- ментарий к выступлению. Чтобы избежать тесной связи между JudgeAspect и CriticismEngine, аспект JudgeAspect получает ссылку на объект CriticismEngine посредством внедрения зависимости через ме- тод записи. Схематически эти отношения изображены на рис. 5.8.

Рис. 5.8. Аспекты тоже должны внедряться. Фреймворк Spring может внедрять аспекты AspectJ в виде зависимостей, как если бы они были обычными компонентами

CriticismEngine – это интерфейс, объявляющий метод getCriticism(). А его реализация в виде класса CriticismEngine представлена в лис- тинге 5.10.

Листинг 5.10. Реализация интерфейса CriticismEngine, используемого аспектом JudgeAspect

package com.springinaction.springidol;

public class CriticismEngineImpl implements CriticismEngine { public CriticismEngineImpl() {}

public  String  getCriticism()  {

int  i =  (int)  (Math.random()  *  criticismPool.length); return    criticismPool[i];

}

// внедряется

private String[] criticismPool;

public  void  setCriticismPool(String[]  criticismPool)  { this.criticismPool  =  criticismPool;

}

}

Класс CriticismEngineImpl реализует интерфейс CriticismEngine, вы- бирая случайным образом комментарий из внедренного массива. Этот класс можно объявить компонентом Spring, как показано ниже:

<bean id="criticismEngine" class="com.springinaction.springidol.CriticismEngineImpl">

<property   name="criticisms">

<list>

<value>I’m  not  being  rude,  but  that  was  appalling.</value>

<value>You may be the least talented person  in  this  show.</value>

<value>Do  everyone  a  favor  and  keep  your  day  job.</value>

</list>

</property>

</bean>

Пока все идет неплохо. Теперь у нас есть реализация интерфей- са CriticismEngine для передачи аспекту JudgeAspect. Осталось лишь внедрить объект CriticismEngineImpl в JudgeAspect.

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

<bean  class="com.springinaction.springidol.JudgeAspect"

factory-method=”aspectOf”>

<property name="criticismEngine" ref="criticismEngine" />

</bean>

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

В заключение

235

Экземпляры обычных компонентов Spring создаются контейнером Spring, но аспекты AspectJ создаются самим расширением AspectJ во время выполнения. К тому моменту, когда Spring получит возмож- ность внедрить объект CriticismEngine в аспект JudgeAspect, последний уже будет создан.

Поскольку фреймворк Spring не участвует в создании аспекта JudgeAspect, недостаточно просто объявить его компонентом Spring. Нам нужно дать фреймворку возможность получить ссылку на эк- земпляр JudgeAspect, который уже создан расширением AspectJ, что- бы ее можно было связать с объектом CriticismEngine. Все аспекты AspectJ имеют статический метод aspectOf(), возвращающий один и тот же экземпляр аспекта. Поэтому, вместо того чтобы пытаться вы- звать конструктор JudgeAspect для получения ссылки на экземпляр аспекта, необходимо задействовать атрибут factory-method для вызова метода  aspectOf().

Проще говоря, фреймворк Spring не использует объявление компо- нента, представленное выше, для создания экземпляра JudgeAspect – он создается расширением AspectJ во время выполнения. Вместо этого Spring получает ссылку на аспект вызовом фабричного метода aspectOf() и затем выполняет внедрение зависимости, как предусмот- рено логикой работы элемента <bean>.

В заключение

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

Spring предоставляет фреймворк AOP, позволяющий окружать аспектами вызовы методов. Вы узнали, как вплетать советы до и/или после вызова метода, а также добавлять собственную обра- ботку исключений.

Существуют несколько вариантов использования аспектов в при- ложениях на основе Spring. Определять советы и срезы множества точек сопряжения в Spring проще с помощью аннотаций @AspectJ и упрощенной схемы конфигурирования.

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

На данный момент мы познакомились с основами фреймворка Spring Framework. Было показано, как настроить контейнер Spring и как применять аспекты к объектам, управляемым фреймворком. Эти основные приемы позволяют создавать приложения, сконструи- рованные из слабосвязанных объектов. В следующей главе рассмат- ривается, как DI и AOP способствуют тестированию и как охватить программный код тестами.

 

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии