Mi informacion de contacto
Correo[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Proxy se refiere a un modo en el que un objeto A puede tener el mismo comportamiento que B al sostener otro objeto B. Para abrir el protocolo al mundo exterior, B a menudo implementa una interfaz y A también implementará la interfaz. Pero B es la clase de implementación "real", mientras que A es más "virtual". Toma prestados los métodos de B para implementar los métodos de la interfaz. Aunque A es un "pseudo ejército", puede mejorar B y hacer otras cosas antes y después de llamar al método de B. Spring AOP utiliza proxies dinámicos para completar el "tejido" dinámico del código.
Los beneficios de usar un proxy van más allá de esto. Si un proyecto depende de la interfaz proporcionada por otro proyecto, pero la interfaz del otro proyecto es inestable y el protocolo cambia con frecuencia, puede usar un proxy cuando la interfaz cambia. Solo es necesario modificar el proxy, no uno por uno. Modificar el código comercial. En este sentido, podemos hacer esto para todas las interfaces que se ajustan al mundo exterior para evitar que código externo invada nuestro código. Esto se llama programación defensiva. Puede haber muchas otras aplicaciones para el proxy.
En el ejemplo anterior, la clase A está codificada para contener B, que es el proxy estático de B. Si el objeto de un proxy es incierto, es un proxy dinámico. Actualmente existen dos implementaciones comunes de proxy dinámico, proxy dinámico jdk y proxy dinámico cglib.
El proxy estático es un patrón de diseño y un tipo de patrón de proxy. En un proxy estático, la clase de proxy se define antes de ejecutar el programa y la relación entre la clase de proxy y la clase de proxy se determina en el momento de la compilación. Esto significa que tanto la clase proxy como la clase proxy implementan la misma interfaz o heredan la misma clase principal. La clase proxy contiene internamente una instancia de la clase proxy y llama a los métodos de la clase proxy en su propio método. , Puede agregar algunas de sus propias operaciones antes y después de la llamada, como registro, verificación de permisos, procesamiento de transacciones, etc.
El proxy estático tiene tres componentes: interfaz abstracta, clase de proxy y clase de proxy. Sus ejemplos de implementación son los siguientes:
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class TargetProxy implements TargetInteface {
-
- private Target target =new Target();
- @Override
- public void method1() {
- System.out.println("执行方法前...");
- target.method1();
- System.out.println("执行方法后...");
- }
-
- @Override
- public void method2() {
- System.out.println("执行方法前...");
- target.method2();
- System.out.println("执行方法后...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("执行方法前...");
- int method3 = target.method3(i);
- System.out.println("执行方法后...");
- return method3;
- }
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println(" Target method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("Target method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("Target method3 running ...");
- return i;
- }
- }
- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = new TargetProxy();
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Salida de resultados:
Antes de ejecutar el método...
Método de destino 1 en ejecución...
Después de ejecutar el método...
-----------------------------
Antes de ejecutar el método...
Método de destino2 ejecutándose...
Después de ejecutar el método...
-----------------------------
Antes de ejecutar el método...
Método de destino3 ejecutándose...
Después de ejecutar el método...
3
No es difícil ver en la implementación de agentes estáticos que las ventajas de los agentes estáticos son una implementación simple y fácil de entender. Pero sus deficiencias también son obvias, es decir, cada vez que necesita agregar funcionalidad de proxy a una nueva clase, debe crear manualmente una nueva clase de proxy, lo que provocará un fuerte aumento en el número de clases y un aumento en los costos de mantenimiento. . Al mismo tiempo, el grado de acoplamiento entre la clase de proxy y la clase de proxy es demasiado alto. Cuando se agregan, eliminan o modifican métodos en la clase de proxy, también se deben agregar, eliminar o modificar los métodos correspondientes en la clase de proxy. , lo que mejora el coste de mantenimiento del código. Otro problema es que cuando el objeto proxy representa las clases de implementación de múltiples interfaces de destino, debe haber diferentes métodos en las múltiples clases de implementación. Dado que el objeto proxy debe implementar la misma interfaz que el objeto de destino (en realidad, una relación de inclusión), debe implementar. Ser escrito Numerosos métodos pueden conducir fácilmente a un código inflado y difícil de mantener.
La idea central del proxy dinámico es acceder indirectamente al objeto original a través del objeto proxy sin modificar el código del objeto original y realizar operaciones adicionales antes y después del acceso.
El principio de implementación del proxy dinámico se basa principalmente en el mecanismo de reflexión de Java. Cuando se utilizan servidores proxy dinámicos, es necesario definir una interfaz o un conjunto de interfaces que definan el comportamiento de la clase proxy (objeto proxy).Entonces, necesitas escribir una implementación.InvocationHandler
Clase de interfaz, esta clase contiene lógica que se ejecuta antes y después de las llamadas al método en el objeto proxy.al llamarProxy.newProxyInstance()
método, pase el cargador de clases de la interfaz, la matriz de la interfaz yInvocationHandler
Objeto, Java generará dinámicamente una clase proxy que implementa la interfaz especificada en tiempo de ejecución y delegará llamadas a métodos aInvocationHandler
objetos a procesar.Cuando se llama a un método de un objeto proxy, en realidad llamaInvocationHandler
Interfazinvoke()
Método, en el que puede realizar cierta lógica de preprocesamiento basada en el nombre del método, los parámetros y otra información, y luego llamar al método correspondiente del objeto proxy mediante la reflexión.
A continuación, presentamos dos proxies dinámicos: JDK Proxy y CGLib.
JDK Proxy utiliza el mecanismo de reflexión de Java para generar dinámicamente clases de proxy. Específicamente,Proxy
la clase usaráProxyGenerator
class (aunque esta clase no es una API pública, es la clave para implementar proxy dinámico dentro del JDK) para generar el código de bytes de la clase de proxy y cargarlo en la JVM.La clase de proxy generada heredará dejava.lang.reflect.Proxy
clase e implementar la interfaz especificada.En el método de la clase proxy, se llamaráInvocationHandler
deinvoke
Método, reenvía la llamada al método al procesador para su procesamiento.
Además, para mejorar el rendimiento, JDK Proxy también proporciona un mecanismo de almacenamiento en caché para almacenar en caché el objeto Clase de la clase de proxy generada. De esta manera, cuando necesite crear un objeto proxy del mismo tipo, puede obtener directamente el objeto Clase de la clase proxy del caché sin regenerarlo.El almacenamiento en caché se realiza medianteWeakCache
Implementado por la clase, utiliza referencias débiles a objetos de caché para que los elementos de caché que ya no se utilizan se puedan limpiar automáticamente cuando la JVM realiza la recolección de basura.
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
InvocationHandler
interfaz y reescribirinvoke
método.existirinvoke
En el método, puede agregar lógica personalizada, como registro, verificación de permisos, etc., y llamar al método de clase original mediante reflexión.Proxy.newProxyInstance
método, pasando el cargador de clases, la matriz de interfaz yInvocationHandler
Instancia para generar dinámicamente objetos proxy. Este método devuelve una instancia de clase proxy que implementa la interfaz especificada.- public class TargetProxy {
- public static <T> Object getTarget(T t) {
- //新构建了一个 新的 代理类的对象
- return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
- //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
- System.out.println("执行方法前...");
- Object invoke = method.invoke(t, args);
- System.out.println("执行方法后...");
- return invoke;
- }
- });
- }
- }
InvocationHandler
deinvoke
Método, después de ejecutar la lógica personalizada en este método, llame al método de la clase original.- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Salida de resultados:
Antes de ejecutar el método...
método1 corriendo...
Después de ejecutar el método...
-----------------------------
Antes de ejecutar el método...
método2 ejecutándose...
Después de ejecutar el método...
-----------------------------
Antes de ejecutar el método...
método3 corriendo...
Después de ejecutar el método...
3
MethodInterceptor
Interfaz para definir un interceptor de métodos, que ejecutará lógica personalizada antes y después de la llamada al método del objeto proxy, como preprocesamiento, posprocesamiento, manejo de excepciones, etc.- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- import java.lang.reflect.Method;
- public class Target {
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
MethodInterceptor
clase de interfaz y anulaciónintercept
método. Escriba la lógica del proxy en este método.Enhancer
clase para crear objetos proxy.Debe configurar la clase de proxy (a través desetSuperclass
método) y devoluciones de llamada (a través desetCallback
El método establece la clase de implementación MethodInterceptor).- public class TargetProxy {
- public static <T> Object getProxy(T t) {
- Enhancer en = new Enhancer(); //帮我们生成代理对象
- en.setSuperclass(t.getClass());//设置要代理的目标类
- en.setCallback(new MethodInterceptor() {//代理要做什么
- @Override
- public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- System.out.println("执行方法前。。。");
- //调用原有方法
- Object invoke = methodProxy.invokeSuper(object, args);
- // Object invoke = method.invoke(t, args);// 作用等同与上面。
- System.out.println("执行方法后。。。");
- return invoke;
- }
- });
- return en.create();
- }
- }
intercept
Lógica proxy en métodos.- public class TargetUser {
-
- public static void main(String[] args) {
- Target target = (Target) TargetProxy.getProxy(new Target());
- System.out.println(target.getClass().getName());
- target.method1();
- }
-
- }
Salida de resultados:
com.heaboy.aopdemo.cglibproxy.ObjetivominorteorteyoanorteorteCmiaByCGRAMOyoIBf9f41fb8
antes de ejecutar el método. . .
método1 corriendo...
Después de ejecutar el método. . .
ventaja:
defecto:
Tipo de objeto proxy:JDK Proxy solo puede representar clases que implementan interfaces, mientras que CGLib puede representar directamente clases ordinarias.
actuación: CGLib genera subclases de clases de proxy en tiempo de ejecución y generalmente se considera que tiene un rendimiento ligeramente mejor que JDK Proxy. Pero en la mayoría de los escenarios, esta diferencia de rendimiento no es significativa.
escenas a utilizar: Si el objeto de destino ya implementa la interfaz, usar JDK Proxy es una opción simple y directa. Si necesita representar una clase que no implementa una interfaz, debe usar CGLib.
confiar:JDK Proxy no requiere dependencias adicionales porque es parte de la biblioteca principal de Java, mientras que CGLib requiere agregar la biblioteca CGLib como dependencia del proyecto.
JDK Proxy es una función que viene con el lenguaje Java y no necesita implementarse cargando clases de terceros;
Java proporciona soporte estable para JDK Proxy y continuará actualizándose y actualizándose. Por ejemplo, el rendimiento de JDK Proxy en la versión Java 8 ha mejorado enormemente en comparación con las versiones anteriores;
JDK Proxy se implementa mediante interceptores y reflexión;
JDK Proxy solo puede representar clases que hereden interfaces;
JDK Proxy es relativamente sencillo de implementar y llamar;
CGLib es una herramienta proporcionada por un tercero, implementada en base a ASM y tiene un rendimiento relativamente alto;
CGLib no necesita implementarse a través de una interfaz, se llama implementando una subclase.
Proxy estático: Los servidores proxy estáticos se determinan durante la compilación. Es necesario escribir una clase de proxy para cada clase de proxy. La clase de proxy y la clase de proxy implementan la misma interfaz o heredan la misma clase principal.
La clase de proxy de un proxy estático existe en el momento de la compilación, por lo que solo puede representar clases específicas cuando el programa se está ejecutando y no puede decidir dinámicamente qué clases representar.
El proxy estático envuelve la llamada al método del objeto original y puede agregar lógica adicional antes y después de la llamada, pero la clase de proxy debe escribirse con anticipación, lo que aumentará la cantidad de código.
El proxy estático especifica explícitamente el objeto proxy en el código y su uso es relativamente intuitivo, pero agregar nuevas clases de proxy requiere una recompilación.
Proxy dinámico: El proxy dinámico crea objetos proxy en tiempo de ejecución sin escribir clases de proxy por adelantado. Utilice el mecanismo de reflexión de Java para generar dinámicamente clases proxy y objetos proxy.
Los proxies dinámicos se basan en interfaces y se implementan a través de la clase java.lang.reflect.Proxy y la interfaz java.lang.reflect.InvocationHandler.
El proxy dinámico puede representar clases de múltiples interfaces y decidir dinámicamente qué clases representar. En tiempo de ejecución, se pueden generar servidores proxy para diferentes objetos según sea necesario, lo que proporciona una mayor flexibilidad.
El proxy dinámico no necesita escribir una clase de proxy específica para cada clase de proxy, lo que es más flexible y ahorra código.
Los agentes dinámicos pueden agregar lógica personalizada antes y después de las llamadas a métodos en el objeto proxy, como registros, gestión de transacciones, etc. La desventaja del proxy dinámico es que, en comparación con el proxy estático, generar objetos proxy en tiempo de ejecución requiere cierta sobrecarga de rendimiento.
Los proxies estáticos son adecuados para los siguientes escenarios:
Cuando la cantidad de objetos de destino (objetos proxy) es limitada y determinada, el proxy estático se puede implementar escribiendo clases de proxy manualmente. Los proxies estáticos crean clases de proxy en tiempo de compilación, por lo que tienen un mejor rendimiento en tiempo de ejecución.
Los proxies estáticos encapsulan el objeto de destino y agregan funciones adicionales sin modificar el código original. Esto hace que los servidores proxy estáticos se utilicen a menudo para cuestiones transversales, como el registro y la gestión de transacciones.
El proxy dinámico es adecuado para los siguientes escenarios:
Cuando el número de objetos de destino es incierto o no se puede determinar de antemano, los servidores proxy dinámicos pueden generar objetos proxy de manera más conveniente. Genera clases de proxy y objetos de proxy en tiempo de ejecución, evitando el tedioso trabajo de escribir manualmente varias clases de proxy.
Los proxies dinámicos brindan la flexibilidad de agregar, eliminar o cambiar el comportamiento del proxy para los objetos de destino en tiempo de ejecución. Esto hace que los servidores proxy dinámicos se utilicen a menudo en escenarios de aplicaciones como AOP (programación orientada a aspectos) y RPC (llamada a procedimiento remoto).
Cabe señalar que debido a que los servidores proxy dinámicos crean clases de proxy y objetos proxy a través del mecanismo de reflexión en tiempo de ejecución, su rendimiento puede ser ligeramente menor que el de los servidores proxy estáticos. Además, los proxies dinámicos solo pueden apuntar a objetos que implementan la interfaz, mientras que los proxies estáticos no tienen esta restricción.
En resumen, los servidores proxy estáticos son adecuados para escenarios donde el número de objetos de destino es limitado y seguro, y requieren encapsulación y funciones adicionales, mientras que los servidores proxy dinámicos son adecuados para escenarios donde el número de objetos de destino es incierto o no se puede determinar de antemano; y el comportamiento del proxy debe agregarse, eliminarse o cambiarse de manera flexible. Elija el método de agencia adecuado según las necesidades y circunstancias específicas.
Spring AOP es un módulo importante en el marco Spring y se utiliza para implementar programación orientada a aspectos.
Programación cara a cara , este es un modelo de programación que permite a los programadores modularizar a través de puntos transversales personalizados y encapsular comportamientos que afectan múltiples clases en módulos reutilizables. Ejemplo: por ejemplo, la salida del registro, si no usa AOP, debe colocar las declaraciones de salida del registro en todas las clases y métodos. Sin embargo, con AOP, puede encapsular las declaraciones de salida del registro en un módulo reutilizable y colocarlas en un. De manera declarativa. En una clase, la salida del registro se completa automáticamente cada vez que se utiliza la clase.
En la idea de programación orientada a aspectos, las funciones se dividen en dos tipos
Negocio principal: El inicio de sesión, el registro, la adición, la eliminación, la modificación y la consulta se denominan negocio principal
Funciones periféricas: Los registros y la gestión de transacciones son servicios periféricos secundarios.
En la programación orientada a aspectos, las funciones comerciales centrales y las funciones periféricas se desarrollan de forma independiente, y las dos no están acopladas. Luego, las funciones comerciales centrales y las funciones comerciales centrales se "tejen", lo que se denomina AOP.
AOP puede convertir aquellos que no estén relacionados con el negocio,Pero está encapsulado para la lógica o responsabilidades (como procesamiento de transacciones, gestión de registros, control de permisos, etc.) comúnmente llamadas por módulos comerciales.,facil deReducir el código duplicado en el sistema.,Reducir el acoplamiento entre módulos.,yPropicio para la futura escalabilidad y mantenibilidad。
Existen los siguientes conceptos en AOP:
Aspecto J: Aspecto es solo un concepto. No existe una interfaz o clase específica correspondiente. Es un nombre colectivo para Punto de unión, Consejo y Punto de corte.
Punto de unión : El punto de conexión se refiere a un punto durante la ejecución del programa, como la invocación de métodos, el manejo de excepciones, etc. En Spring AOP, solo se admiten puntos de unión a nivel de método.
Consejo : La notificación, es decir, la lógica transversal en un aspecto que definimos, tiene tres tipos: "alrededor", "antes" y "después". En muchos marcos de implementación de AOP, Advice generalmente actúa como un interceptor y también puede contener muchos interceptores como un enlace que se procesará alrededor del punto de unión.
Punto de corte: Pointcut, utilizado para unir puntos de unión. Los puntos de unión contenidos en un AspectJ deben filtrarse mediante Pointcut.
Introducción : Introducción, que permite que un aspecto declare que los objetos recomendados implementan cualquier interfaz adicional que en realidad no implementan. Por ejemplo, un objeto proxy se puede utilizar para representar dos clases de destino.
Costura : Weaving, ahora que tenemos puntos de conexión, puntos de corte, notificaciones y aspectos, ¿cómo aplicarlos al programa? Así es, está tejido. Bajo la guía de puntos de corte, la lógica de notificación se inserta en el método de destino, de modo que nuestra lógica de notificación se pueda ejecutar cuando se llama al método.
Proxy AOP : El proxy AOP se refiere al objeto que implementa el protocolo de aspecto en el marco de implementación de AOP. Hay dos tipos de proxies en Spring AOP, a saber, el proxy dinámico JDK y el proxy dinámico CGLIB.
Objeto objetivo: El objeto de destino es el objeto que se está representando.
Spring AOP se implementa en base al proxy dinámico JDK y la promoción Cglib. Ambos métodos de proxy son métodos de tiempo de ejecución, por lo que no tienen procesamiento en tiempo de compilación, por lo que Spring se implementa mediante código Java.
Algunos comportamientos comunes dispersos entre múltiples clases u objetos (como registro, administración de transacciones, control de permisos, limitación de corriente de la interfaz, potencia de la interfaz, etc.), estos comportamientos generalmente se denominan preocupaciones transversales . Si implementamos estos comportamientos repetidamente en cada clase u objeto, generaremos un código redundante, complejo y difícil de mantener.
AOP puede transformar preocupaciones transversales (como registro, gestión de transacciones, control de permisos, limitación de corriente de interfaz, potencia de interfaz, etc.) de Lógica empresarial central (preocupaciones centrales, preocupaciones centrales) Separarse del foco para lograr la separación de preocupaciones.
Registro: personalice las anotaciones de registro y utilice AOP para lograr el registro con una línea de código.
Estadísticas de rendimiento: utilice AOP para contar el tiempo de ejecución del método antes y después de la ejecución del método de destino para facilitar la optimización y el análisis.
Gestión de transacciones:@Transactional
Las anotaciones permiten que Spring realice la gestión de transacciones por nosotros, como revertir operaciones de excepción y eliminar la lógica de gestión de transacciones repetidas.@Transactional
Las anotaciones se implementan en función de AOP.
Control de permisos: utilice AOP para determinar si el usuario tiene los permisos necesarios antes de ejecutar el método de destino. Si es así, ejecute el método de destino; de lo contrario, no se ejecutará.Por ejemplo, SpringSecurity utiliza@PreAuthorize
Puede personalizar la verificación de permisos comentando una línea de código.
Limitación de corriente de la interfaz: utilice AOP para limitar la solicitud a través de implementaciones y algoritmos de limitación de corriente específicos antes de que se ejecute el método de destino.
Gestión de caché: utilice AOP para leer y actualizar el caché antes y después de que se ejecute el método de destino.
Los métodos de implementación comunes de AOP incluyen proxy dinámico, operación de código de bytes, etc.
Spring AOP se basa en un proxy dinámico. Si el objeto a ser proxy implementa una determinada interfaz, entonces Spring AOP utilizará. Proxy JDKPara crear un objeto proxy, para objetos que no implementan la interfaz, no puede usar JDK Proxy como proxy. En este momento, Spring AOP usará. Cglib Genere una subclase del objeto proxy para que sirva como proxy
existirspring-aop.xml
Configurar beans y aspectos relacionados en el archivo de configuración
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
-
- <bean id="target" class="com.xxhh.aopdemo.aop.Target"/>
-
- <bean id="targetAdvice" class="com.xxhh.aopdemo.aop.TargetAdvice"/>
-
- <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target" ref="target"/> <!--被代理的类-->
- <property name="interceptorNames" value="targetAdvice"/> <!--如果用多种增强方式,value的值使用逗号(,)分割-->
- <property name="proxyTargetClass" value="false"/> <!--如果设置为true,则创建基于类的代理(使用CGLIB);如果设置为false,则创建基于接口的代理(使用JDK动态代理)。-->
- <property name="interfaces" value="com.xxhh.aopdemo.aop.TargetInteface"/> <!--target实现的接口-->
- </bean>
- </beans>
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface{
-
- /*
- * 需要增强的方法,连接点JoinPoint
- **/
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
- public class TargetAdvice implements MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice {
-
- /*
- * 通知/增强
- **/
- @Override
- public Object invoke(MethodInvocation methodInvocation) throws Throwable {
- System.out.println("前置环绕通知");
- Object proceed = methodInvocation.proceed();
- System.out.println("后置环绕通知");
- return proceed;
- }
-
- @Override
- public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
- System.out.println("后置返回通知");
- }
-
- @Override
- public void before(Method method, Object[] args, Object target) throws Throwable {
- System.out.println("前置通知");
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-aop.xml");
- TargetInteface targetProxy = (TargetInteface) appCtx.getBean("targetProxy");
- targetProxy.method1();
- }
- }
Resultado de salida:
Notificación frontal envolvente
Notificación previa
método1 corriendo...
notificación de devolución posterior
Notificación envolvente trasera
existirspring-confaop.xml
Configurar beans y aspectos relacionados en el archivo de configuración
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- /*
- * 目标类
- **/
- public class Target {
-
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- /*
- * 连接点JoinPoint
- **/
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- // int i1 = 1 / i;
- return i;
- }
- }
- import org.aspectj.lang.ProceedingJoinPoint;
- /*
- * 切面类
- **/
- public class TargetAspect {
-
- /*
- * 前置通知
- **/
- public void before() {
- System.out.println("conf前置通知");
- }
-
- public void after() {
- System.out.println("conf后置通知");
- }
-
- public void afterReturning() {
- System.out.println("conf后置返回通知");
- }
-
- public void afterThrowing(Exception ex) throws Exception {
- // System.out.println("conf异常通知");
- // System.out.println(ex.getMessage());
- }
-
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("conf环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("conf环绕后置");
- }
- return proceed;
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-confaop.xml");
- Target targetProxy = (Target) appCtx.getBean("target");
- System.out.println(targetProxy.method3(0));
- }
- }
Resultado de salida:
notificación previa de configuración
prefijo envolvente conf
método3 corriendo...
conf notificación posterior a la devolución
publicación envolvente de configuración
notificación de publicación de configuración
0
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface TestAnnotation{
- }
- /*
- * 切面类
- **/
- @Aspect
- @Component
- public class AnnotationAspect {
-
- // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
- @Pointcut("@annotation(TestAnnotation)")
- private void advicePointcut() {}
-
- /*
- * 前置通知
- **/
- @Before("advicePointcut()")
- public void before() {
- System.out.println("annotation前置通知");
- }
-
- @After("advicePointcut()")
- public void after() {
- System.out.println("annotation后置通知");
- }
-
- @AfterReturning(pointcut = "advicePointcut()")
- public void afterReturning() {
- System.out.println("annotation后置返回通知");
- }
-
- @AfterThrowing(pointcut = "advicePointcut()", throwing = "ex")
- public void afterThrowing(Exception ex) throws Exception {
- System.out.println("annotation异常通知");
- System.out.println(ex.getMessage());
- }
-
- @Around("advicePointcut()")
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("annotation环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("annotation环绕后置");
- }
- return proceed;
- }
- }
- @Controller
- public class TestController {
-
- @RequestMapping("/test.do")
- @ResponseBody
- public String testController() {
- TestController o = (TestController) AopContext.currentProxy();
- o.test();
- // System.out.println("tewt");
- return "ok";
- }
-
- @TestAnnotation
- public void test() {
- System.out.println("test running");
- }
-
- }