Перейти к основному содержимому

Посоветуйте методы для аннотированных классов с AspectJ

· 4 мин. чтения

1. Обзор

В этом руководстве мы будем использовать AspectJ для записи вывода журнала трассировки при вызове методов настроенных классов. Используя рекомендацию АОП для записи выходных данных журнала трассировки, мы инкапсулируем логику в единую единицу компиляции.

Наш пример расширяет информацию, представленную во Введении в AspectJ .

2. Аннотация ведения журнала трассировки

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

Создадим аннотацию:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Trace {
}

3. Создание нашего аспекта

Мы создадим аспект, чтобы определить наш pointcut , чтобы он соответствовал интересующим нас точкам соединения и рекомендациям вокруг , содержащим логику для выполнения.

Наш аспект будет выглядеть примерно так:

public aspect TracingAspect {
private static final Log LOG = LogFactory.getLog(TracingAspect.class);

pointcut traceAnnotatedClasses(): within(@Trace *) && execution(* *(..));

Object around() : traceAnnotatedClasses() {
String signature = thisJoinPoint.getSignature().toShortString();
LOG.trace("Entering " + signature);
try {
return proceed();
} finally {
LOG.trace("Exiting " + signature);
}
}
}

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

Наш совет вокруг будет выполняться вместо любой точки соединения, соответствующей нашему pointcut , и будет возвращать Object . Имея тип возвращаемого значения Object , мы можем учитывать рекомендованные методы, имеющие любой тип возвращаемого значения, даже void .

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

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

Мы заключаем вызов continue() в блок try / finally , чтобы обеспечить запись выходного сообщения. Если бы мы хотели отследить сгенерированное исключение, мы могли бы добавить совет after() для записи сообщения в журнал при сгенерированном исключении:

after() throwing (Exception e) : traceAnnotatedClasses() {
LOG.trace("Exception thrown from " + thisJoinPoint.getSignature().toShortString(), e);
}

4. Аннотирование нашего кода

Теперь нам нужно включить нашу трассировку. Давайте создадим простой класс и активируем ведение журнала трассировки с нашей пользовательской аннотацией:

@Trace
@Component
public class MyTracedService {

public void performSomeLogic() {
...
}

public void performSomeAdditionalLogic() {
...
}
}

При наличии аннотации Trace методы в нашем классе будут соответствовать определенному нами pointcut . При выполнении этих методов сообщения трассировки будут записываться в журнал.

После запуска нашего кода, вызывающего эти методы, наш вывод журнала должен включать содержимое, подобное следующему:

22:37:58.867 [main] TRACE c.b.a.c.TracingAspect - Entering MyTracedService.performSomeAdditionalLogic()
22:37:58.868 [main] INFO c.b.a.c.MyTracedService - Inside performSomeAdditionalLogic...
22:37:58.868 [main] TRACE c.b.a.c.TracingAspect - Exiting MyTracedService.performSomeAdditionalLogic()
22:37:58.869 [main] TRACE c.b.a.c.TracingAspect - Entering MyTracedService.performSomeLogic()
22:37:58.869 [main] INFO c.b.a.c.MyTracedService - Inside performSomeLogic...
22:37:58.869 [main] TRACE c.b.a.c.TracingAspect - Exiting MyTracedService.performSomeLogic()

5. Вывод

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

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

Как всегда, полный исходный код статьи доступен на GitHub .