Las notificaciones de Spring AOP se dividen en cinco categorías:
Antes de los consejos: ejecute frente al punto de conexión. La vista previa no afectará la ejecución del punto de conexión a menos que se lance una excepción aquí.
Notificación de devolución normal [Después de devolver el consejo]: Ejecutar después de que se complete la ejecución normal del punto de conexión. Si el punto de conexión lanza una excepción, no se ejecutará.
Notificación de devolución de excepción [después de lanzar consejos]: ejecute después de que el punto de conexión lanza una excepción.
Notificación de retorno [después del consejo (finalmente)]: después de completar la ejecución, el contenido de la notificación de devolución se ejecutará si se completa normalmente o se lanza una excepción.
En torno a los consejos: en torno a los consejos rodea el punto de conexión, como antes y después de una llamada de método. Este es el tipo de notificación más potente, que puede personalizar algunas operaciones antes y después de las llamadas del método.
La notificación circundante también debe decidir si continuar procesando el punto de unión (llamando al método de proceso del punto de proceso de procedimiento) o interrumpir la ejecución.
A continuación, probaremos cinco tipos de notificaciones escribiendo un programa de muestra:
Definir interfaz
paquete com.chenqa.springaop.example.service; interfaz pública bankservice { / *** transferencia bancaria simulada* @param desde la cuenta* @param a la cuenta* @param La cantidad de transferencia de cuenta* @return* / transferencia pública booleana (formulario de cadena, cadena a, doble cuenta);};}Escribir clases de implementación
paquete com.chenqa.springaop.example.service.impl; import com.chenqa.springaop.example.service.bankservice; public class bcmbankserviceImpl implementa bankservice {transferencia pública bobina (forma de cadena, cadena a, cuenta doble) {if <100) {Dangil yuan "); } System.out.println (formulario+"transferir a"+a+"cuenta bancaria"+cuenta+"yuan"); devolver falso; }}Modifique el archivo de configuración de Spring y agregue lo siguiente:
<!-bankservice bean-> <bean id = "bankservice"/> <!-section-> <bean id = "myAspect"/> <!-AOP Configuration-> <aop: config> <aop: aspecto ref = "myAspect"> <aop: pointCut Expression = "Execution (*com.chenqa.springaop.example.service.impl.* id = "PointCut"/> <aop: antes del método = "antes" PointCut-REF = "PointCut"/> <aop: After Method = "After" PointCut-REF = "PointCut"/> <aop: After-Returning Method = "AfterRurning" PointCut-Ref = "Pointcut"/> <AOP: After-throwing Method = "Afterthrowing PointCutCut" PointCutCut "PointCut" PointCut " <AOP: Around Method = "Around" PointCut-Ref = "PointCut"/> </aop: aspecto> </aop: config>
Escribir un programa de prueba
ApplicationContext context = new ClassPathXMLApplicationContext ("Spring-AOP.XML"); BankService BankService = context.getBean ("BankService", bankService.class); BankService.Transfer ("Zhang San", "Li Si", 200); Salida después de la ejecución:
Cambiar 200 en el programa de prueba a 50, y luego salga después de la ejecución:
A partir de los resultados de la prueba, se puede ver que la orden de ejecución de las cinco notificaciones es:
PRE-Notificación → Notificación envolvente → Notificación de retorno normal/Notificación de retorno de excepción → Notificación de retorno, puede realizar varias veces para ver.
Caso 1: Un método solo es interceptado por una clase de aspecto
Cuando un método es interceptado por un solo aspecto, ¿en qué orden se ejecutan los diferentes consejos en este aspecto? Consulte:
Agregar clase de PointCut
Este punto de venta se utiliza para interceptar todos los métodos en todas las clases en el paquete de prueba.
prueba de paquete; import org.spectj.lang.annotation.pointcut; public class PointCuts {@PointCut (value = "dentro (Test.*)") public void aopDemo () {}}Agregar clase de aspecto
El consejo en esta clase utilizará el PointCut anterior. Consulte el atributo de valor de cada consejo cuando lo use.
Prueba de paquete; importar org.spectj.lang.joinpoint; import org.aspectj.lang.procedingjoinpoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.component;@component@aspecto de aspecto público {System.out.println ("[Aspect1] antes del consejo"); } @Around (value = "test.pointcuts.aopDemo ()") public void alrededor de (procedimientoJoinPoint PJP) lanza {system.out.println ("[aspecto1] alrededor del consejo 1"); pjp.proceed (); System.out.println ("[Aspect1] en torno a Advicion2"); } @Afterreturning (valor = "test.pointcuts.aopdemo ()") public void después de lareta (unión unión unión) {System.out.println ("[Aspect1] después de consejos de retorno"); } @Afterthrowing (value = "test.pointcuts.aopDemo ()") public void Afterthrowing (unión unión de unión) {System.out.println ("[Aspect1] AfterThrowing Assesity"); } @After (valor = "test.pointcuts.aopDemo ()") public void después (unión unión de unión) {System.out.println ("[Aspect1] Aviso posterior"); } @After (valor = "test.pointcuts.aopDemo ()") public void después (unión unión de unión) {System.out.println ("[Aspecto1] después del asesoramiento"); }}Agregar un controlador de prueba
Agregue un controlador para la prueba. Solo hay un método en este controlador, pero se manejará de manera diferente de acuerdo con los valores de los parámetros: uno es devolver un objeto normalmente, y el otro es lanzar una excepción (porque queremos probar el consejo @Afterthrowing)
Test de paquete; importación de importación = "/test", método = requestMethod.get) prueba de resultado público (@RequestParam Boolean ThrowException) {// Case 1 if (ThrowException) {System.out.println ("lanzar una excepción"); tirar nueva testException ("simular una excepción del servidor"); } // case 2 System.out.println ("Test OK"); devolver nuevo resultado () {{this.setId (111); this.setName ("burlarse de un resultado"); }}; } Resultado de clase estática pública {private int id; nombre de cadena privada; public int getId () {return id; } public void setid (int id) {this.id = id; } public String getName () {nombre de retorno; } public void setName (nombre de cadena) {this.name = name; }}}Probar situación normal
Ingrese la siguiente URL directamente en el navegador e ingrese: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false 1
Veremos el resultado de salida:
[Aspecto1] alrededor del consejo 1 [aspecto1] Antes del asesoramiento OK [aspecto1] en torno al consejo2 [aspecto1] Después del consejo [aspecto1] después de retirar el consejo
Excepciones de prueba
Ingrese directamente la siguiente URL en el navegador y presione Entrar: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true 1
Veremos el resultado de salida:
[Aspecto1] alrededor del consejo 1 [aspecto1] Antes de advicethrow una excepción [aspecto1] después del consejo [aspecto1] posterior consejos para después
en conclusión
Cuando un método es interceptado por una sola clase de aspecto, el consejo dentro de la clase de aspecto se ejecutará en el siguiente orden:
Situación normal:
Excepción:
Caso 2: El mismo método es interceptado por múltiples clases de aspecto
Aquí hay un ejemplo que es interceptado por dos clases de aspecto.
En algunos casos, para dos clases de aspectos diferentes, independientemente de si su consejo usa el mismo punto de punto o puntos de puntos diferentes, puede hacer que el mismo método sea interceptado por múltiples clases de aspecto. Entonces, en este caso, ¿en qué orden se ejecutan los consejos en estas múltiples clases de aspecto? Consulte:
La clase de Pointcut permanece sin cambios
Agregar una nueva clase de aspecto
Prueba de paquete; importar org.spectj.lang.joinpoint; import org.aspectj.lang.procedingjoinpoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.component;@component@aspecto de aspecto público {System.out.println ("[aspecto2] antes del consejo"); } @Around (value = "test.pointcuts.aopDemo ()") public void alrededor de (procedimientojoinpoint pjp) lanza {system.out.println ("[aspecto2] alrededor del consejo 1"); pjp.proceed (); System.out.println ("[aspecto2] en torno a consejo2"); } @AfterReturning (value = "test.pointcuts.aopDemo ()") public void después de la toma (unión de unión unión) {System.out.println ("[Aspect2] After ReTurning Advice"); } @Afterthrowing (value = "test.pointcuts.aopDemo ()") public void Afterthrowing (unión de unión unión) {System.out.println ("[Aspecto2] AfterThrowing Advacion"); } @After (value = "test.pointcuts.aopDemo ()") public void después (unión unión unión) {System.out.println ("[Aspect2] Aviso posterior"); } @After (value = "test.pointcuts.aopDemo ()") public void después (unión unión unión) {system.out.println ("[aspecto2] después del asesoramiento"); }}El controlador de prueba tampoco está cambiado
Todavía usa el controlador anterior. Pero ahora tanto Suppe1 como Suppe2 interceptan los métodos en el controlador.
¡Continúe probando a continuación!
Probar situación normal
Ingrese la siguiente URL directamente en el navegador e ingrese: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false 1
Veremos el resultado de salida:
[Aspect2] alrededor del consejo 1 [aspecto2] Antes del consejo [aspecto1] en torno al consejo 1 [aspecto1] Antes del asesoramiento OK [aspecto1] en torno al consejo2 [aspecto1] después del consejo [aspecto1] después de retomar el consejo [aspecto2] en torno a los consejos2 [aspecto2] después del consejo de retorno
Pero en este momento, no puedo concluir que Aspect2 definitivamente se ejecute antes del aspecto1.
¿No lo crees? Reinicie el servidor y vuelve a intentarlo, tal vez vea los siguientes resultados de ejecución:
[Aspecto1] en torno al consejo 1 [aspecto1] Antes del consejo [aspecto2] en torno al consejo 1 [aspecto2] Antes del asesoramiento OK [aspecto2] en torno al consejo2 [aspecto2] después del consejo [aspecto2] después de retomar el consejo [aspecto1] en torno al consejo2 [aspecto1] después de retirar el consejo
Es decir, en este caso, se desconoce la orden de ejecución de aspecto1 y el aspecto2. Entonces, ¿cómo resolverlo? Sin prisa, la solución se dará a continuación.
Excepciones de prueba
Ingrese directamente la siguiente URL en el navegador y presione Entrar: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true 1
Veremos el resultado de salida:
[Aspecto2] Alrededor del consejo 1 [Aspect2] Antes del consejo [aspecto1] en torno al consejo 1 [aspecto1] antes de abogar una excepción [aspecto1] después de lanzar consejos [aspecto2] después de lanzar consejos
Del mismo modo, si reinicia el servidor y luego lo prueba nuevamente, puede ver los siguientes resultados:
[Aspect1] Alrededor del consejo 1 [Aspect1] Antes del consejo [Aspect2] en torno al consejo 1 [Aspect2] Antes de abogar una excepción de una excepción [Aspect2] Aviso de retraso [Aspecto1] Aviso de retraso
Es decir, de la misma manera, la orden de ejecución de aspecto1 y el aspecto2 también no se determina en circunstancias excepcionales.
Entonces, en el caso 2, ¿cómo especifica el orden de ejecución de cada aspecto?
Hay dos métodos:
No importa qué método se use, cuanto más pequeño sea el aspecto, más se ejecuta primero.
Por ejemplo, agregamos anotaciones de @order para APSECT1 y Suppect2 respectivamente, como sigue:
@Order (5)@componente@aspecto de clase Public Suppe1 {// ...}@Order (6)@componente@aspecto de clase Public Suppe2 {// ...} Después de esta modificación, se puede garantizar que en cualquier caso, el consejo en el aspecto1 siempre se ejecuta antes del consejo en el aspecto2. Como se muestra en la figura a continuación:
Nota
Si se definen dos consejos idénticos para el mismo punto de punto (por ejemplo, dos @bebore) se definen, entonces la orden de ejecución de estos dos consejos no se puede determinar, incluso si agrega la anotación @order a estos dos consejos, no funcionará. Recuerda esto.
Para el consejo de @Arcion, independientemente de si tiene un valor de retorno o no, debe llamar a PJP.ProCED () dentro del método; De lo contrario, la interfaz en el controlador no se ejecutará, lo que también hará que el consejo @before no se active. Por ejemplo, suponemos que en circunstancias normales, la orden de ejecución es "Aspect2 -> APSect1 -> Controlador". Si eliminamos pjp.procede (); En @around in Suppect1, entonces la salida que vemos será:
[Aspect2] Alrededor del consejo 1 [Aspect2] Antes del consejo [Aspect1] en torno al consejo 1 [Aspect1] en torno al consejo2 [aspecto1] después del consejo [aspecto1] después de retirar el consejo [aspecto2] en torno a los consejos2 [aspecto2] después de retirar el consejo
A partir de los resultados, podemos encontrar que la interfaz en el controlador no se ha ejecutado, y @beForeAdVice en Suppe1 tampoco se ha ejecutado.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.