Вступ до типів порад навесні

1. Огляд

У цій статті ми обговоримо різні типи рекомендацій щодо AOP, які можна створити навесні.

Порада - це дія, яку здійснює аспект у певній точці об’єднання. Різні типи порад включають рекомендації “навколо”, “до” та “після”. Основною метою аспектів є підтримка наскрізних проблем, таких як реєстрація, профілювання, кешування та управління транзакціями.

А якщо ви хочете глибше заглибитися у вирази точки, перегляньте попереднє вступ до них.

2. Включення консультацій

За допомогою Spring ви можете оголосити поради, використовуючи анотації AspectJ, але спочатку потрібно застосувати анотацію @EnableAspectJAutoProxy до вашого класу конфігурації , що дозволить підтримку роботи з компонентами, позначеними анотацією @Aspect AspectJ .

@Configuration @EnableAspectJAutoProxy public class AopConfiguration { ... }

2.1. Весняний черевик

У проектах Spring Boot нам не потрібно явно використовувати @EnableAspectJAutoProxy . Існує спеціальний AopAutoConfiguration, який забезпечує підтримку AOP Spring, якщо Aspect або Advice знаходиться на шляху до класу.

3. Перед порадою

Ця порада, як випливає з назви, виконується перед точкою з’єднання. Це не заважає продовженню виконання методу, який він радить, якщо не буде вилучено виняток.

Розглянемо наступний аспект, який просто реєструє ім'я методу до його виклику:

@Component @Aspect public class LoggingAspect { private Logger logger = Logger.getLogger(LoggingAspect.class.getName()); @Pointcut("@target(org.springframework.stereotype.Repository)") public void repositoryMethods() {}; @Before("repositoryMethods()") public void logMethodCall(JoinPoint jp) { String methodName = jp.getSignature().getName(); logger.info("Before " + methodName); } }

LogMethodCall рада буде виконуватися перед будь-яким способом сховища , визначеного repositoryMethods зрізом точок.

4. Після поради

Після поради, оголошеної за допомогою анотації @After , виконується після виконання відповідного методу, незалежно від того, чи було створено виняток.

У чомусь це схоже на блок нарешті . Якщо вам потрібна порада, яка буде ініційована лише після нормального виконання, вам слід скористатися порадою щодо повернення, оголошеною анотацією @AfterReturning . Якщо ви хочете, щоб ваша порада спрацьовувала лише тоді, коли цільовий метод видає виняток, вам слід скористатися порадою метання, оголошеною за допомогою анотації @AfterThrowing .

Припустимо, що ми хочемо повідомляти деякі компоненти програми, коли створюється новий екземпляр Foo . Ми могли б опублікувати подію від FooDao , але це порушило б принцип єдиної відповідальності.

Натомість ми можемо досягти цього, визначивши наступний аспект:

@Component @Aspect public class PublishingAspect { private ApplicationEventPublisher eventPublisher; @Autowired public void setEventPublisher(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } @Pointcut("@target(org.springframework.stereotype.Repository)") public void repositoryMethods() {} @Pointcut("execution(* *..create*(Long,..))") public void firstLongParamMethods() {} @Pointcut("repositoryMethods() && firstLongParamMethods()") public void entityCreationMethods() {} @AfterReturning(value = "entityCreationMethods()", returning = "entity") public void logMethodCall(JoinPoint jp, Object entity) throws Throwable { eventPublisher.publishEvent(new FooCreationEvent(entity)); } }

По-перше, зауважте, що за допомогою аннотації @AfterR eturning ми можемо отримати доступ до поверненого значення цільового методу. По-друге, оголосивши параметр типу JoinPoint, ми можемо отримати доступ до аргументів виклику цільового методу.

Далі ми створюємо слухач, який просто реєструє подію:

@Component public class FooCreationEventListener implements ApplicationListener { private Logger logger = Logger.getLogger(getClass().getName()); @Override public void onApplicationEvent(FooCreationEvent event) { logger.info("Created foo instance: " + event.getSource().toString()); } }

5. Навколо Поради

Навколо поради оточує точку об’єднання, таку як виклик методу.

Це найпотужніша порада. Навколо консультації можуть виконувати власну поведінку як до, так і після виклику методу. Він також відповідає за вибір, чи продовжувати до точки приєднання, чи скоротити ярлик виконання рекомендованого методу, надаючи своє власне значення повернення або створюючи виняток.

Щоб продемонструвати його використання, припустимо, що ми хочемо виміряти час виконання методу. Давайте створимо для цього аспект:

@Aspect @Component public class PerformanceAspect { private Logger logger = Logger.getLogger(getClass().getName()); @Pointcut("within(@org.springframework.stereotype.Repository *)") public void repositoryClassMethods() {}; @Around("repositoryClassMethods()") public Object measureMethodExecutionTime(ProceedingJoinPoint pjp) throws Throwable { long start = System.nanoTime(); Object retval = pjp.proceed(); long end = System.nanoTime(); String methodName = pjp.getSignature().getName(); logger.info("Execution of " + methodName + " took " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms"); return retval; } }

Ця порада спрацьовує, коли виконується будь-яка з точок об'єднання, що відповідає точці repositoryClassMethods .

Ця порада приймає один параметр типу ProceedingJointPoint . Параметр дає нам можливість вжити заходів до виклику цільового методу. У цьому випадку ми просто зберігаємо час запуску методу.

По-друге, типом повернення поради є Object, оскільки цільовий метод може повертати результат будь-якого типу. Якщо цільовий метод недійсний, буде повернуто null . Після виклику цільового методу ми можемо виміряти час, записати його в журнал і повернути значення результату методу абоненту.

6. Огляд

У цій статті ми дізнались про різні типи порад навесні та їх декларації та реалізації. Ми визначили аспекти, використовуючи підхід на основі схеми та використовуючи анотації AspectJ. Ми також надали декілька можливих додаткових порад.

Реалізацію всіх цих прикладів та фрагментів коду можна знайти в моєму проекті GitHub.