Introduzione ai tipi di consigli in primavera

1. Panoramica

In questo articolo, discuteremo diversi tipi di consigli AOP che possono essere creati in primavera.

Il consiglio è un'azione intrapresa da un aspetto in un particolare punto di unione. Diversi tipi di consigli includono consigli "intorno", "prima" e "dopo". Lo scopo principale degli aspetti è supportare le preoccupazioni trasversali, come la registrazione, la creazione di profili, la memorizzazione nella cache e la gestione delle transazioni.

E se vuoi approfondire le espressioni pointcut, dai un'occhiata alla precedente introduzione a queste.

2. Consentire la consulenza

Con Spring, puoi dichiarare consigli usando le annotazioni AspectJ, ma devi prima applicare l' annotazione @EnableAspectJAutoProxy alla tua classe di configurazione , che abiliterà il supporto per la gestione dei componenti contrassegnati con l' annotazione @Aspect di AspectJ .

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

2.1. Spring Boot

Nei progetti Spring Boot, non è necessario utilizzare esplicitamente @EnableAspectJAutoProxy . C'è un AopAutoConfiguration dedicato che abilita il supporto AOP di Spring se Aspect o Advice si trova sul classpath.

3. Prima del consiglio

Questo consiglio, come suggerisce il nome, viene eseguito prima del punto di unione. Non impedisce l'esecuzione continua del metodo consigliato a meno che non venga generata un'eccezione.

Considera il seguente aspetto che registra semplicemente il nome del metodo prima che venga chiamato:

@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); } }

L' avviso logMethodCall verrà eseguito prima di qualsiasi metodo di repository definito dal pointcut repositoryMethods .

4. Dopo il consiglio

Dopo il consiglio, dichiarato utilizzando l' annotazione @After , viene eseguito dopo l'esecuzione di un metodo corrispondente, indipendentemente dal fatto che sia stata generata un'eccezione.

In un certo senso, è simile ad un finalmente blocco. Nel caso in cui sia necessario attivare un consiglio solo dopo la normale esecuzione, è necessario utilizzare il consiglio di restituzione dichiarato dall'annotazione @AfterReturning . Se vuoi che il tuo consiglio venga attivato solo quando il metodo di destinazione genera un'eccezione, dovresti usare il consiglio di lancio, dichiarato usando l' annotazione @AfterThrowing .

Supponiamo di voler notificare ad alcuni componenti dell'applicazione quando viene creata una nuova istanza di Foo . Potremmo pubblicare un evento da FooDao , ma ciò violerebbe il principio di responsabilità unica.

Invece, possiamo ottenere ciò definendo il seguente aspetto:

@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)); } }

Si noti, in primo luogo, che utilizzando l' annotazione eturning @AfterR possiamo accedere al valore di ritorno del metodo di destinazione. In secondo luogo, dichiarando un parametro di tipo JoinPoint, possiamo accedere agli argomenti dell'invocazione del metodo di destinazione.

Successivamente creiamo un listener che registrerà semplicemente l'evento:

@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. Intorno consiglio

Intorno al consiglio circonda un punto di unione come un'invocazione di metodo.

Questo è il tipo di consiglio più potente. Around Advice può eseguire comportamenti personalizzati sia prima che dopo l'invocazione del metodo. È anche responsabile della scelta se procedere al punto di unione o abbreviare l'esecuzione del metodo consigliato fornendo il proprio valore di ritorno o generando un'eccezione.

Per dimostrare il suo utilizzo, supponiamo di voler misurare il tempo di esecuzione del metodo. Creiamo un aspetto per questo:

@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; } }

Questo consiglio viene attivato quando viene eseguito uno qualsiasi dei punti di unione corrispondenti al pointcut repositoryClassMethods .

Questo consiglio accetta un parametro di tipo ProceedingJointPoint . Il parametro ci dà l'opportunità di agire prima della chiamata al metodo di destinazione. In questo caso, salviamo semplicemente l'ora di inizio del metodo.

In secondo luogo, il tipo di restituzione del consiglio è Object poiché il metodo di destinazione può restituire un risultato di qualsiasi tipo. Se il metodo di destinazione è void, verrà restituito null . Dopo la chiamata al metodo di destinazione, possiamo misurare il tempo, registrarlo e restituire il valore del risultato del metodo al chiamante.

6. Panoramica

In questo articolo, abbiamo imparato i diversi tipi di consigli in Spring e le loro dichiarazioni e implementazioni. Abbiamo definito gli aspetti utilizzando un approccio basato su schema e utilizzando le annotazioni AspectJ. Abbiamo anche fornito diverse possibili applicazioni di consulenza.

L'implementazione di tutti questi esempi e frammenti di codice può essere trovata nel mio progetto GitHub.