Въведение в типовете съвети през пролетта

1. Общ преглед

В тази статия ще обсъдим различни видове AOP съвети, които могат да бъдат създадени през пролетта.

Съветът е действие, предприето от аспект в определена точка на присъединяване. Различните видове съвети включват съвети „около“, „преди“ и „след“. Основната цел на аспектите е да подкрепят междусекторни проблеми, като регистриране, профилиране, кеширане и управление на транзакции.

И ако искате да навлезете по-задълбочено в изразките на точки, разгледайте предишното въведение в тях.

2. Активиране на съвети

С Spring можете да декларирате съвети, като използвате анотации на AspectJ, но първо трябва да приложите анотацията @EnableAspectJAutoProxy към вашия конфигурационен клас , което ще даде възможност за поддръжка за обработка на компоненти, маркирани с анотация на AspectJ @Aspect .

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

2.1. Пролетно зареждане

В проектите за пролетното зареждане не е нужно да използваме изрично @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 ще бъде изпълнен преди всеки метод на хранилище, дефиниран от pointcut на 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, тъй като целевият метод може да върне резултат от всякакъв тип. Ако целевият метод е void, null ще бъде върната. След извикването на целевия метод можем да измерим времето, да го регистрираме и да върнем стойността на резултата от метода на повикващия.

6. Общ преглед

В тази статия научихме различните видове съвети през пролетта и техните декларации и изпълнения. Дефинирахме аспекти, използвайки схематичен подход и използвайки анотации на AspectJ. Предоставихме и няколко възможни приложения за съвети.

Изпълнението на всички тези примери и кодови фрагменти може да се намери в моя проект GitHub.