Il framework Spring è sviluppato su due concetti fondamentali: l’Iniezione di Dipendenza e la Programmazione Orientata agli Aspetti (Spring AOP).
Spring AOP
Abbiamo già visto come funziona l’Iniezione di Dipendenza di Spring, oggi vedremo i concetti fondamentali della Programmazione Orientata agli Aspetti e come possiamo implementarli utilizzando il framework Spring.
Panoramica di Spring AOP
La maggior parte delle applicazioni aziendali ha alcune preoccupazioni trasversali comuni che si applicano a diversi tipi di oggetti e moduli. Alcune delle preoccupazioni trasversali comuni sono il logging, la gestione delle transazioni, la validazione dei dati, ecc. Nella programmazione orientata agli oggetti, la modularità dell’applicazione viene raggiunta tramite le classi, mentre nella programmazione orientata agli aspetti la modularità dell’applicazione viene raggiunta tramite gli aspetti e vengono configurati per tagliare attraverso diverse classi. Spring AOP elimina la dipendenza diretta delle attività trasversali dalle classi che non possiamo ottenere attraverso il normale modello di programmazione orientata agli oggetti. Ad esempio, possiamo avere una classe separata per il logging, ma ancora una volta le classi funzionali dovranno chiamare questi metodi per ottenere il logging in tutta l’applicazione.
Concetti fondamentali della programmazione orientata agli aspetti
Prima di approfondire l’implementazione di Spring AOP, dovremmo comprendere i concetti fondamentali dell’AOP.
- Aspetto: Un aspetto è una classe che implementa le preoccupazioni delle applicazioni aziendali che si estendono su più classi, come la gestione delle transazioni. Gli aspetti possono essere una classe normale configurata tramite la configurazione XML di Spring o possiamo utilizzare l’integrazione Spring AspectJ per definire una classe come aspetto utilizzando l’annotazione
@Aspect
. - Punto di unione: Un punto di unione è un punto specifico nell’applicazione, come l’esecuzione di un metodo, la gestione delle eccezioni, la modifica dei valori delle variabili degli oggetti, ecc. In Spring AOP, un punto di unione è sempre l’esecuzione di un metodo.
- Consiglio: I consigli sono azioni intraprese per un particolare punto di unione. In termini di programmazione, sono metodi che vengono eseguiti quando si raggiunge un determinato punto di unione con un pointcut corrispondente nell’applicazione. Si può pensare ai consigli come agli interceptor di Struts2 o ai filtri di Servlet.
- Pointcut: Il pointcut è l’espressione che viene confrontata con i punti di unione per determinare se l’advice deve essere eseguito o meno. Il pointcut utilizza diversi tipi di espressioni che vengono confrontate con i punti di unione e il framework Spring utilizza il linguaggio di espressione del pointcut di AspectJ.
- Oggetto di destinazione: Sono gli oggetti su cui vengono applicati i consigli. Spring AOP viene implementato utilizzando proxy a runtime, quindi questo oggetto è sempre un oggetto proxy. Ciò significa che viene creata una sottoclasse a runtime in cui il metodo di destinazione viene sovrascritto e vengono inclusi i consigli in base alla loro configurazione.
- Proxy AOP: L’implementazione di Spring AOP utilizza il proxy dinamico JDK per creare classi Proxy con classi di destinazione e invocazioni di consigli, chiamate AOP proxy. Possiamo anche utilizzare il proxy CGLIB aggiungendolo come dipendenza nel progetto Spring AOP.
- Tessitura: È il processo di collegamento degli aspetti con altri oggetti per creare gli oggetti proxy consigliati. Ciò può essere fatto durante la compilazione, il caricamento o durante l’esecuzione. Spring AOP esegue la tessitura durante l’esecuzione.
Tipi di Consigli AOP
In base alla strategia di esecuzione del consiglio, essi sono dei seguenti tipi.
- Consiglio Prima: Questi consigli vengono eseguiti prima dell’esecuzione dei metodi del punto di unione. Possiamo utilizzare l’annotazione
@Before
per marcare un tipo di consiglio come consiglio Prima. - Consiglio Dopo (finally): Un consiglio che viene eseguito dopo che il metodo del punto di unione ha finito di eseguire, sia normalmente che lanciando un’eccezione. Possiamo creare un consiglio dopo utilizzando l’annotazione
@After
. - Consiglio Dopo il Ritorno: A volte vogliamo che i metodi del consiglio vengano eseguiti solo se il metodo del punto di unione viene eseguito normalmente. Possiamo utilizzare l’annotazione
@AfterReturning
per marcare un metodo come consiglio dopo il ritorno. - Dopo il Lancio del Consiglio: Questo consiglio viene eseguito solo quando il metodo del punto di unione genera un’eccezione, possiamo usarlo per annullare la transazione dichiarativamente. Utilizziamo l’annotazione
@AfterThrowing
per questo tipo di consiglio. - Consiglio Intorno: Questo è il consiglio più importante e potente. Questo consiglio circonda il metodo del punto di unione e possiamo anche scegliere se eseguire il metodo del punto di unione o meno. Possiamo scrivere codice di consiglio che viene eseguito prima e dopo l’esecuzione del metodo del punto di unione. È responsabilità del consiglio intorno invocare il metodo del punto di unione e restituire valori se il metodo restituisce qualcosa. Utilizziamo l’annotazione
@Around
per creare metodi di consiglio intorno.
I punti sopra menzionati possono sembrare confusi ma quando esamineremo l’implementazione di Spring AOP, le cose saranno più chiare. Iniziamo creando un semplice progetto Spring con implementazioni AOP. Spring fornisce supporto per l’uso di annotazioni AspectJ per creare aspetti e useremo questo per semplicità. Tutte le annotazioni AOP sopra sono definite nel pacchetto org.aspectj.lang.annotation
. Spring Tool Suite fornisce informazioni utili sugli aspetti, quindi ti consiglierei di usarlo. Se non sei familiare con STS, ti consiglierei di dare un’occhiata al Tutorial su Spring MVC dove ho spiegato come usarlo.
Esempio di Spring AOP
Crea un nuovo progetto Spring Maven semplice in modo che tutte le librerie di Spring Core siano incluse nei file pom.xml e non sia necessario includerle esplicitamente. Il nostro progetto finale avrà un aspetto simile all’immagine sottostante. Esamineremo dettagliatamente i componenti principali di Spring e le implementazioni degli aspetti.
Spring AOP AspectJ Dependencies
Il framework Spring fornisce il supporto per AOP di default, ma poiché utilizziamo le annotazioni AspectJ per configurare aspetti e consigli, è necessario includerle nel file pom.xml.
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>SpringAOPExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>4.0.2.RELEASE</spring-framework.version>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
<!-- Test -->
<junit.version>4.11</junit.version>
<!-- AspectJ -->
<aspectj.version>1.7.4</aspectj.version>
</properties>
<dependencies>
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<!-- AspectJ dependencies -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</project>
Nota che ho aggiunto le dipendenze aspectjrt
e aspectjtools
(versione 1.7.4) nel progetto. Inoltre, ho aggiornato la versione del framework Spring all’ultima disponibile, ovvero 4.0.2.RELEASE.
Classe Modello
Creiamo una semplice classe Java Bean che utilizzeremo per il nostro esempio con alcuni metodi aggiuntivi. Codice di Employee.java:
package com.journaldev.spring.model;
import com.journaldev.spring.aspect.Loggable;
public class Employee {
private String name;
public String getName() {
return name;
}
@Loggable
public void setName(String nm) {
this.name=nm;
}
public void throwException(){
throw new RuntimeException("Dummy Exception");
}
}
Hai notato che il metodo setName() è annotato con l’annotazione Loggable
. È un annotazione Java personalizzata definita da noi nel progetto. Ne esamineremo l’uso in seguito.
Classe di servizio
Creiamo una classe di servizio per lavorare con l’oggetto Employee. Codice EmployeeService.java:
package com.journaldev.spring.service;
import com.journaldev.spring.model.Employee;
public class EmployeeService {
private Employee employee;
public Employee getEmployee(){
return this.employee;
}
public void setEmployee(Employee e){
this.employee=e;
}
}
I could have used Spring annotations to configure it as a Spring Component, but we will use XML based configuration in this project. EmployeeService class is very standard and just provides us an access point for Employee beans.
Configurazione del bean Spring con AOP
Se stai usando STS, hai l’opzione di creare un “File di configurazione del bean Spring” e scegliere lo schema del namespace AOP, ma se stai usando un altro IDE, puoi semplicemente aggiungerlo nel file di configurazione del bean Spring. Il mio file di configurazione del bean del progetto è simile al seguente. spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="https://www.springframework.org/schema/aop"
xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.0.xsd
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<!-- Enable AspectJ style of Spring AOP -->
<aop:aspectj-autoproxy />
<!-- Configure Employee Bean and initialize it -->
<bean name="employee" class="com.journaldev.spring.model.Employee">
<property name="name" value="Dummy Name"></property>
</bean>
<!-- Configure EmployeeService bean -->
<bean name="employeeService" class="com.journaldev.spring.service.EmployeeService">
<property name="employee" ref="employee"></property>
</bean>
<!-- Configure Aspect Beans, without this Aspects advices wont execute -->
<bean name="employeeAspect" class="com.journaldev.spring.aspect.EmployeeAspect" />
<bean name="employeeAspectPointcut" class="com.journaldev.spring.aspect.EmployeeAspectPointcut" />
<bean name="employeeAspectJoinPoint" class="com.journaldev.spring.aspect.EmployeeAspectJoinPoint" />
<bean name="employeeAfterAspect" class="com.journaldev.spring.aspect.EmployeeAfterAspect" />
<bean name="employeeAroundAspect" class="com.journaldev.spring.aspect.EmployeeAroundAspect" />
<bean name="employeeAnnotationAspect" class="com.journaldev.spring.aspect.EmployeeAnnotationAspect" />
</beans>
Per utilizzare Spring AOP nei bean Spring, è necessario fare quanto segue:
- Dichiarare il namespace AOP come xmlns:aop=“https://www.springframework.org/schema/aop”
- Aggiungere l’elemento aop:aspectj-autoproxy per abilitare il supporto di Spring AspectJ con proxy automatici durante l’esecuzione
- Configurare le classi Aspect come altri bean Spring
Puoi vedere che ho molti aspetti definiti nel file di configurazione del bean di primavera, è ora di analizzarli uno per uno.
Esempio di Aspetto Prima di Spring AOP
Il codice EmployeeAspect.java:
package com.journaldev.spring.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class EmployeeAspect {
@Before("execution(public String getName())")
public void getNameAdvice(){
System.out.println("Executing Advice on getName()");
}
@Before("execution(* com.journaldev.spring.service.*.get*())")
public void getAllAdvice(){
System.out.println("Service method getter called");
}
}
Punti importanti nella classe di aspetto sopra sono:
- Le classi di Aspetto devono avere l’annotazione
@Aspect
. - L’annotazione @Before viene utilizzata per creare un consiglio Prima
- Il parametro stringa passato nell’annotazione
@Before
è l’espressione Pointcut - Il consiglio getNameAdvice() verrà eseguito per qualsiasi metodo Spring Bean con firma
public String getName()
. Questo è un punto molto importante da ricordare, se creeremo un bean Employee usando l’operatore new i consigli non verranno applicati. Solo quando useremo ApplicationContext per ottenere il bean, i consigli verranno applicati. - Possiamo utilizzare l’asterisco (*) come wild card nelle espressioni Pointcut, getAllAdvice() verrà applicato a tutte le classi nel pacchetto
com.journaldev.spring.service
il cui nome inizia conget
e non prende argomenti.
Esamineremo il consiglio in azione in una classe di test dopo aver esaminato tutti i diversi tipi di consigli.
Metodi di Punto di Taglio e Riutilizzo di Spring AOP
A volte dobbiamo utilizzare la stessa espressione di punto di taglio in più punti, possiamo creare un metodo vuoto con l’annotazione @Pointcut
e poi usarlo come espressione nei consigli. Codice EmployeeAspectPointcut.java:
package com.journaldev.spring.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class EmployeeAspectPointcut {
@Before("getNamePointcut()")
public void loggingAdvice(){
System.out.println("Executing loggingAdvice on getName()");
}
@Before("getNamePointcut()")
public void secondAdvice(){
System.out.println("Executing secondAdvice on getName()");
}
@Pointcut("execution(public String getName())")
public void getNamePointcut(){}
@Before("allMethodsPointcut()")
public void allServiceMethodsAdvice(){
System.out.println("Before executing service method");
}
//Punto di taglio da eseguire su tutti i metodi delle classi in un pacchetto
@Pointcut("within(com.journaldev.spring.service.*)")
public void allMethodsPointcut(){}
}
L’esempio sopra è molto chiaro, anziché espressione stiamo usando il nome del metodo nell’argomento dell’annotazione del consiglio.
Spring AOP JoinPoint e Argomenti del Consiglio
Possiamo utilizzare JoinPoint come parametro nei metodi di consiglio e utilizzarlo per ottenere la firma del metodo o l’oggetto di destinazione. Possiamo utilizzare l’espressione args()
nel punto di taglio da applicare a qualsiasi metodo che corrisponda al modello di argomento. Se usiamo questo, allora dobbiamo usare lo stesso nome nel metodo di consiglio da dove viene determinato il tipo di argomento. Possiamo utilizzare anche oggetti generici negli argomenti del consiglio. Codice EmployeeAspectJoinPoint.java:
package com.journaldev.spring.aspect;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class EmployeeAspectJoinPoint {
@Before("execution(public void com.journaldev.spring.model..set*(*))")
public void loggingAdvice(JoinPoint joinPoint){
System.out.println("Before running loggingAdvice on method="+joinPoint.toString());
System.out.println("Agruments Passed=" + Arrays.toString(joinPoint.getArgs()));
}
//Argomenti del consiglio, saranno applicati ai metodi bean con un singolo argomento di tipo String
@Before("args(name)")
public void logStringArguments(String name){
System.out.println("String argument passed="+name);
}
}
Esempio di Consiglio After di AOP di Primavera
Esaminiamo una semplice classe di aspetto con un esempio di consiglio After, After Throwing e After Returning. Codice EmployeeAfterAspect.java:
package com.journaldev.spring.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class EmployeeAfterAspect {
@After("args(name)")
public void logStringArguments(String name){
System.out.println("Running After Advice. String argument passed="+name);
}
@AfterThrowing("within(com.journaldev.spring.model.Employee)")
public void logExceptions(JoinPoint joinPoint){
System.out.println("Exception thrown in Employee Method="+joinPoint.toString());
}
@AfterReturning(pointcut="execution(* getName())", returning="returnString")
public void getNameReturningAdvice(String returnString){
System.out.println("getNameReturningAdvice executed. Returned String="+returnString);
}
}
Possiamo usare within
nell’espressione del punto di taglio per applicare il consiglio a tutti i metodi della classe. Possiamo usare il consiglio @AfterReturning per ottenere l’oggetto restituito dal metodo consigliato. Abbiamo il metodo throwException() nell’oggetto Employee per mostrare l’uso del consiglio After Throwing.
Esempio di Aspetto Around di AOP di Primavera
Come spiegato in precedenza, possiamo utilizzare l’aspetto Around per interrompere l’esecuzione del metodo prima e dopo. Possiamo usarlo per controllare se il metodo consigliato verrà eseguito o meno. Possiamo anche ispezionare il valore restituito e cambiarlo. Questo è il consiglio più potente e deve essere applicato correttamente. Codice EmployeeAroundAspect.java:
package com.journaldev.spring.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class EmployeeAroundAspect {
@Around("execution(* com.journaldev.spring.model.Employee.getName())")
public Object employeeAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("Before invoking getName() method");
Object value = null;
try {
value = proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("After invoking getName() method. Return value="+value);
return value;
}
}
Intorno al consiglio è sempre necessario avere ProceedingJoinPoint come argomento e dovremmo utilizzare il suo metodo proceed () per invocare il metodo dell’oggetto target consigliato. Se il metodo consigliato restituisce qualcosa, è responsabilità del consiglio restituirlo al programma chiamante. Per i metodi void, il metodo di consiglio può restituire null. Poiché il consiglio intorno taglia intorno al metodo consigliato, possiamo controllare l’input e l’output del metodo così come il suo comportamento di esecuzione.
Consiglio di primavera con punto di taglio di annotazione personalizzata
Se si considerano tutte le espressioni pointcut di consigli precedenti, c’è la possibilità che vengano applicate ad altri bean dove non è inteso. Ad esempio, qualcuno può definire un nuovo bean Spring con il metodo getName() e il consiglio inizierà ad essere applicato anche a quello, anche se non era inteso. Ecco perché dovremmo mantenere il campo di applicazione dell’espressione pointcut il più ristretto possibile. Un approccio alternativo è quello di creare una annotazione personalizzata e annotare i metodi in cui vogliamo che il consiglio venga applicato. Questo è lo scopo di avere il metodo Employee setName() annotato con l’annotazione @Loggable. L’annotazione @Transactional del framework Spring è un ottimo esempio di questo approccio per la Gestione delle transazioni di Spring. Codice Loggable.java:
package com.journaldev.spring.aspect;
public @interface Loggable {
}
Codice EmployeeAnnotationAspect.java:
package com.journaldev.spring.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class EmployeeAnnotationAspect {
@Before("@annotation(com.journaldev.spring.aspect.Loggable)")
public void myAdvice(){
System.out.println("Executing myAdvice!!");
}
}
Il metodo myAdvice() consiglierà solo il metodo setName(). Questo è un approccio molto sicuro e ogni volta che vogliamo applicare il consiglio su un metodo, tutto ciò di cui abbiamo bisogno è di annotarlo con l’annotazione Loggable.
Configurazione XML di Spring AOP
I always prefer annotation but we also have the option to configure aspects in the spring configuration file. For example, let’s say we have a class as below. EmployeeXMLConfigAspect.java code:
package com.journaldev.spring.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class EmployeeXMLConfigAspect {
public Object employeeAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("EmployeeXMLConfigAspect:: Before invoking getName() method");
Object value = null;
try {
value = proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("EmployeeXMLConfigAspect:: After invoking getName() method. Return value="+value);
return value;
}
}
Possiamo configurarlo includendo la seguente configurazione nel file di configurazione dei bean di Spring.
<bean name="employeeXMLConfigAspect" class="com.journaldev.spring.aspect.EmployeeXMLConfigAspect" />
<!-- Spring AOP XML Configuration -->
<aop:config>
<aop:aspect ref="employeeXMLConfigAspect" id="employeeXMLConfigAspectID" order="1">
<aop:pointcut expression="execution(* com.journaldev.spring.model.Employee.getName())" id="getNamePointcut"/>
<aop:around method="employeeAroundAdvice" pointcut-ref="getNamePointcut" arg-names="proceedingJoinPoint"/>
</aop:aspect>
</aop:config>
Il scopo degli elementi di configurazione AOP xml è chiaro dal loro nome, quindi non entrerò nei dettagli.
Esempio di Spring AOP
Facciamo un semplice programma Spring e vediamo come tutti questi aspetti incidano sui metodi del bean. Codice di SpringMain.java:
package com.journaldev.spring.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.journaldev.spring.service.EmployeeService;
public class SpringMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
EmployeeService employeeService = ctx.getBean("employeeService", EmployeeService.class);
System.out.println(employeeService.getEmployee().getName());
employeeService.getEmployee().setName("Pankaj");
employeeService.getEmployee().throwException();
ctx.close();
}
}
Ora, quando eseguiamo il programma sopra, otteniamo l’output seguente.
Mar 20, 2014 8:50:09 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4b9af9a9: startup date [Thu Mar 20 20:50:09 PDT 2014]; root of context hierarchy
Mar 20, 2014 8:50:09 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
Service method getter called
Before executing service method
EmployeeXMLConfigAspect:: Before invoking getName() method
Executing Advice on getName()
Executing loggingAdvice on getName()
Executing secondAdvice on getName()
Before invoking getName() method
After invoking getName() method. Return value=Dummy Name
getNameReturningAdvice executed. Returned String=Dummy Name
EmployeeXMLConfigAspect:: After invoking getName() method. Return value=Dummy Name
Dummy Name
Service method getter called
Before executing service method
String argument passed=Pankaj
Before running loggingAdvice on method=execution(void com.journaldev.spring.model.Employee.setName(String))
Agruments Passed=[Pankaj]
Executing myAdvice!!
Running After Advice. String argument passed=Pankaj
Service method getter called
Before executing service method
Exception thrown in Employee Method=execution(void com.journaldev.spring.model.Employee.throwException())
Exception in thread "main" java.lang.RuntimeException: Dummy Exception
at com.journaldev.spring.model.Employee.throwException(Employee.java:19)
at com.journaldev.spring.model.Employee$$FastClassBySpringCGLIB$$da2dc051.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:711)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at com.journaldev.spring.model.Employee$$EnhancerBySpringCGLIB$$3f881964.throwException(<generated>)
at com.journaldev.spring.main.SpringMain.main(SpringMain.java:17)
Puoi notare che gli advices vengono eseguiti uno per uno in base alle loro configurazioni pointcut. Dovresti configurarli uno per uno per evitare confusione. Questo è tutto per il Tutorial di Esempio di Spring AOP, spero tu abbia imparato i concetti di base di AOP con Spring e possa approfondire con gli esempi. Scarica il progetto di esempio dal link sottostante e sperimentaci.