AOP (Programación Orientada a Aspectos) divide el programa completo en diferentes unidades más pequeñas. En numerosas situaciones, necesitamos registrar y auditar los detalles, así como también debemos prestar atención a las transacciones declarativas, la seguridad, el almacenamiento en caché, etc. Veamos las terminologías clave de AOP
- Aspecto: Cuenta con un conjunto de APIs para requerimientos transversales. El módulo de registro es un ejemplo del aspecto AOP del registro.
- Punto de unión: enchufe de aspecto AOP en su lugar
- Consejo: a través de esto, se cuida la implementación real del código para el enfoque AOP. Puede ser antes/después/después de la devolución/después del lanzamiento. En este artículo, veamos los ejemplos relacionados con esto.
- Pointcut: Conjunto de uno o más puntos de unión donde se necesita ejecutar un consejo.
- Introducción: Este es el lugar donde podemos agregar nuevos métodos o atributos a las clases existentes.
- Objeto de destino: uno o más aspectos estarán allí para brindar asesoramiento para el objeto de destino.
- Tejer: vincular aspectos con otros tipos de aplicaciones u objetos. Se puede hacer en tiempo de compilación/tiempo de ejecución/tiempo de carga.
En este artículo, veremos brevemente los diferentes tipos de consejos disponibles.
@Alrededor
Este es el consejo más efectivo y deseable entre todos los demás consejos. El primer parámetro es de tipo ProceedingJoinPoint. El código debe tener proceder() en ProceedingJoinPoint. Cuando se proporciona esto, el código debe ejecutarse antes y después de que el método coincida con el punto de corte.
Fragmento de código de muestra:
En cuanto a la prioridad, siempre se invocará @Around incluso si hay anotaciones @Before,
Java
// Displays all the available methods i.e. the advice will // be called for all the methods The method declaration is // called the pointcut signature. It provides a name that can // be used by advice annotations to refer to that pointcut. @Pointcut( value = "execution(* com.gfg.examples.service.ServiceExample.*(..))") private void printLogs() { } // Declares the around advice that is applied before and // after the method matching with a pointcut expression Even // there are @Before annotations, @Around will be invoked // first with the before invokation and then only @Before // will be called @Around(value = "printLogs()") public void logsAroundAdvice(ProceedingJoinPoint proJoinPoint) throws Throwable { System.out.println( "The method aroundAdvice() before invokation of the method " + proJoinPoint.getSignature().getName() + " method"); try { proJoinPoint.proceed(); } finally { } System.out.println( "The method aroundAdvice() after invokation of the method " + proJoinPoint.getSignature().getName() + " method"); }
Como siempre, este es el punto de partida, la lógica empresarial debe procesarse aquí y es ideal.
Posibles casos de uso:
- Cuando se ha iniciado el cálculo de la nómina de empleados.
- Cuando un estudiante comenzó a escribir el examen.
- Cuando se inicia una aplicación externa como una impresora/escáner en el período de tiempo mencionado.
Dado que los consejos de @Around informarán sobre todas y cada una de las actividades antes y después del progreso, serán un punto de referencia y también los errores se pueden diagnosticar fácilmente a través de este enfoque.
@Antes
En cuanto a la prioridad, puede ser el primer paso si no hay un consejo @Around. Si @Around está ahí, siempre @Around tendrá la prioridad más alta y @Before se ejecutará después de la parte inicial de @Around.
Fragmento de código de muestra:
Java
// If there is no @Around advice, @Before will be called // first, otherwise @Around Before Invocation is called @Before( "execution(* com.gfg.examples.service.ServiceExample.*(..))") public void printLogStatementsBefore() { System.out.println( ".............Looking for @Around advice, if none is there, @Before will be called first. My role is to execute before each and every method............."); }
Escenario apto para tener @Antes:
Por lo general, en la relación maestro-detalle, el registro maestro debe existir y luego solo se pueden insertar los datos secundarios correspondientes de manera similar durante la eliminación, los datos secundarios deben eliminarse y luego solo se pueden eliminar los datos maestros. @Before ayudará a superar estos escenarios de dependencias desde el principio.
@Después
En cuanto a la prioridad, siempre se ejecutará @Around, si está disponible y, después de eso, solo se ejecutará @After. Este será un buen lugar para concluir el final de una actividad.
Fragmento de código de muestra:
Java
// If there is no @Around advice, @After will be called // after @Before(if available) first, otherwise @Around After // Invocation is called @After( "execution(* com.gfg.examples.service.ServiceExample.*(..))") public void printLogStatementsAfter() { System.out.println( ".............Looking for @Around advice, if none is there, @After will be called after @Before(if available). My role is to execute after each and every method............."); }
Escenario apto para tener @After:
Para informar a los usuarios sobre la finalización de una operación, como la finalización del proceso de descarga de un archivo o una imagen o el trabajo de impresión completado, etc.,
@Después de regresar
Aunque el consejo @After está ahí, el consejo @AfterReturning indicará el éxito de una operación. Por lo tanto, los pasos de éxito se indicarán aquí.
Fragmento de código de muestra:
Java
// implementing after returning advice // This is generally used to indicate the output after // successful return of the method, will be called at last // i.e. after @Around @AfterReturning( value = "execution(* com.gfg.examples.service.ServiceExample.*(..))", returning = "account") public void logsAfterReturningDisplay(JoinPoint joinPoint) { System.out.println("After Returing method:" + joinPoint.getSignature()); }
Escenario apto para tener @AfterReturning:
Cuando hay actividades como trabajos de impresión, necesitamos conocer el estado de finalización de los trabajos de impresión. Una vez finalizado con éxito, es necesario iniciar otras actividades posteriores. Por lo tanto, las operaciones relacionadas con el éxito se pueden proporcionar en @AfterReturning
@después de lanzar
Hay muchos escenarios de falla de una actividad, por ejemplo, cuando no hay energía, el trabajo de impresión no se puede completar. Durante esos tiempos, es necesario informar sobre la causa de la falla y las medidas de recuperación posteriores. @AfterThrowing es el lugar adecuado para ello.
Fragmento de código de muestra:
Java
// implementing after throwing advice // This is generally used to indicate the exception in case // of exception , will be called whenever exception occurs @AfterThrowing( value = "execution(* com.gfg.examples.service.ServiceExample.*(..))", throwing = "ex") public void logsAfterThrowingDisplay(JoinPoint jPoint, Exception ex) { System.out.println("After Throwing exception in method:" + jPoint.getSignature()); System.out.println("Exception is:" + ex.getMessage()); }
Escenario apto para @AfterThrowing:
Debido a un error de E/S, excepciones aritméticas, excepciones de SQL, etc., debemos proporcionar medidas correctivas.
Combinemos todo y verifiquemos como un proyecto maven de muestra.
Proyecto de ejemplo
Estructura del proyecto:
pom.xml
XML
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> </parent> <groupId>com.gfg.examples</groupId> <artifactId>aop-example</artifactId> <version>0.0.1-SNAPSHOT</version> <name>aop-example</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Archivos importantes clave
EjemploServicio.java
Java
import org.springframework.stereotype.Service; @Service public class ServiceExample { public void getAccountBalance(String employeeAccountNumber) { System.out.println("Inside getBalance() method"); // To mention about for a certain // employeeAccountNumber value if (employeeAccountNumber.equals("Emp1212")) { System.out.println("Total balance: ......"); } else { System.out.println( "Sorry! wrong account number. Please give correct account number to verify"); } } public String employeeStatus(String employeeNumber) { System.out.println( "Inside checkEmployeeExistence() method"); String status = null; if (employeeNumber.equals("emp12345")) { System.out.println(employeeNumber + " is currently active"); status = "active"; } else { System.out.println(employeeNumber + " is currently inactive"); status = "Inactive"; } return status; } public String eligibilityForPromotion(int promotionExamMarks) { System.out.println( "Inside eligibilityForPromotion() method"); String status = null; if (promotionExamMarks >= 650) { System.out.println("Eligible for promotion.."); status = "eligible"; } else { System.out.println( "Not eligible for promotion.."); status = "not eligible"; } return status; } }
ImplementaciónDeDiferentesAspectos.java
Java
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; // Enables the spring AOP functionality in an application @Aspect @Component public class ImplementationOfDifferentAspect { // Displays all the available methods i.e. the advice // will be called for all the methods The method // declaration is called the pointcut signature. It // provides a name that can be used by advice annotations // to refer to that pointcut. @Pointcut( value = "execution(* com.gfg.examples.service.ServiceExample.*(..))") private void printLogs() { } // If there is no @Around advice, @Before will be called // first, otherwise @Around Before Invocation is called @Before( "execution(* com.gfg.examples.service.ServiceExample.*(..))") public void printLogStatementsBefore() { System.out.println( ".............Looking for @Around advice, if none is there, @Before will be called first. My role is to execute before each and every method............."); } // If there is no @Around advice, @After will be called // after @Before(if available) first, otherwise @Around // After Invocation is called @After( "execution(* com.gfg.examples.service.ServiceExample.*(..))") public void printLogStatementsAfter() { System.out.println( ".............Looking for @Around advice, if none is there, @After will be called after @Before(if available). My role is to execute after each and every method............."); } // implementing after returning advice // This is generally used to indicate the output after // successful return of the method, will be called at // last i.e. after @Around // AOP aspect plug in place is JointPoint @AfterReturning( value = "execution(* com.gfg.examples.service.ServiceExample.*(..))", returning = "account") public void logsAfterReturningDisplay(JoinPoint joinPoint) { System.out.println("After Returing method:" + joinPoint.getSignature()); // System.out.println(account); } // implementing after throwing advice // This is generally used to indicate the exception in // case of exception , will be called whenever exception // occurs @AfterThrowing( value = "execution(* com.gfg.examples.service.ServiceExample.*(..))", throwing = "ex") public void logsAfterThrowingDisplay(JoinPoint jPoint, Exception ex) { System.out.println( "After Throwing exception in method:" + jPoint.getSignature()); System.out.println("Exception is:" + ex.getMessage()); } // Declares the around advice that is applied before and // after the method matching with a pointcut expression // Even there are @Before annotations, @Around will be // invoked first with the before invokation and then only // @Before will be called @Around(value = "printLogs()") public void logsAroundAdvice(ProceedingJoinPoint proJoinPoint) throws Throwable { System.out.println( "The method aroundAdvice() before invokation of the method " + proJoinPoint.getSignature().getName() + " method"); try { proJoinPoint.proceed(); } finally { } System.out.println( "The method aroundAdvice() after invokation of the method " + proJoinPoint.getSignature().getName() + " method"); } }
ImplementaciónDeDiferentesConsejos.java
Java
import com.gfg.examples.service.ServiceExample; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.EnableAspectJAutoProxy; @SpringBootApplication // @EnableAspectJAutoProxy annotation enables support for // handling the components marked with @Aspect annotation. @EnableAspectJAutoProxy public class ImplementationOfDifferentAdvice { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run( ImplementationOfDifferentAdvice.class, args); // Fetching the object from the application // context. ServiceExample service = context.getBean(ServiceExample.class); // checking for an employee available in the // organization String employeeNumber = "emp12345"; try { service.employeeStatus(employeeNumber); } catch (Exception ex) { System.out.println("Exception occurred.." + ex.getMessage()); } // Displaying balance in the account. String employeeAccountNumber = "Emp1212"; try { service.getAccountBalance( employeeAccountNumber); } catch (Exception ex) { System.out.println("Exception occurred.." + ex.getMessage()); } // Employee has undergone some exams for promotion. // Let us check that int promotionExamMarks = 650; try { service.eligibilityForPromotion( promotionExamMarks); } catch (Exception ex) { System.out.println("Exception occurred.." + ex.getMessage()); } // Closing the context object. context.close(); } }
Producción:
Explicación:
1. employeeStatus method // @around advice begins The method aroundAdvice() before invocation of the method employeeStatus method // @before advice .............Looking for @Around advice, if none is there, @Before will be called first. My role is to execute before each and every method............. // execution steps Inside ....() method emp12345 is currently active // @around advice ends The method aroundAdvice() after invocation of the method employeeStatus method // @after advvice .............Looking for @Around advice, if none is there, @After will be called after @Before(if available). My role is to execute after each and every method............. @afterreturning After Returing method:String com.gfg.examples.service.ServiceExample.employeeStatus(String) // Similarly it will be done for other methods
En caso de que hayamos ejecutado el método con entradas que causan excepciones, tal vez en el siguiente ejemplo podamos probar
Java
// Displaying balance in the account. String employeeAccountNumber = null; try { service.getAccountBalance(employeeAccountNumber); } catch (Exception ex) { System.out.println("Exception occurred.." + ex.getMessage()); }
Producción:
A lo largo de las muestras, si observamos, hemos utilizado una forma adecuada de proporcionar consejos @Around, @Before, @After, @AfterReturning y @AfterThrowing y, de esta manera, podemos implementar la funcionalidad AOP fácilmente.
Publicación traducida automáticamente
Artículo escrito por priyarajtt y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA