(Sin terminar) [Tema de primavera] Análisis de los principios subyacentes de SringAOP - Fase 3 (AOP)

prefacio

Conocimiento previo

paradigma de agencia

¿Qué es el modo proxy? Explicación del modo proxy: proporcione un proxy para que otros objetos controlen el acceso a este objeto, mejoren un método en una clase y extiendan el programa.
¿Alguna vez has oído hablar del [Agente Paradigm]? Su pseudocódigo es generalmente el siguiente: (El esquema adoptado por el proxy dinámico Cglib

class 被代理类 {
    
    
	function 方法A();
}

class 代理类 <<继承>> 被代理类 {
    
    
	被代理类 targetObject;
	
	@Override
	function 方法A() {
    
    
		// 这里写被加强的逻辑
		targetObject.方法A();
		// 也可以在这里写
	}
}

O expresado en código java de la siguiente manera:

// 被代理对象
public class ProxyTarget {
    
    
    public void run() {
    
    
        System.out.println("这是普通对象的run");
    }
}


// 代理对象
public class ProxyModel extends ProxyTarget {
    
    
    private ProxyTarget proxyTarget;

    public void setProxyTarget(ProxyTarget proxyTarget) {
    
    
        this.proxyTarget = proxyTarget;
    }

    @Override
    public void run() {
    
    
        System.out.println("我代理对象可以在这里做加强---1");
        super.run();
        System.out.println("我代理对象也可以在这里做加强---2");
    }
}

Sin embargo, en realidad existe otra forma de implementar el modo proxy, pero la premisa es que la clase proxy tiene una interfaz.. Su pseudocódigo de paradigma proxy es el siguiente: (El esquema adoptado por el proxy dinámico JDK.

class 被代理类 <<实现>> 接口A {
    
    
	function 实现自接口A的方法();
}

class 代理类 <<实现>> 接口A {
    
    
	被代理类 targetObject;
	
	@Override
	function 实现自接口A的方法() {
    
    
		// 这里写被加强的逻辑
		targetObject.方法A();
		// 也可以在这里写
	}
}

Los dos métodos de proxy descritos anteriormente son un pequeño detalle. Cierto parámetro mencionado más adelante afectará la elección del método de proxy.

Comprensión de Spring AOP

OOP significa programación orientada a objetos, que es un tipo de idea de programación, y AOP significa programación orientada a aspectos, que también es un tipo de idea de programación. Para que los programadores sean más convenientes para lograr el soporte técnico proporcionado por la programación orientada a aspectos. Spring proporciona un conjunto de mecanismos que pueden facilitarnos la realización de AOP, por lo que también podemos llamar a este mecanismo Spring AOP.

Implementación del proxy dinámico Spring

Lo puse en [Contenido del curso] porque tengo miedo de que la gente no le preste atención.

Contenido del curso

1. Realización de proxy dinámico

Creo que los amigos experimentados deberían saber que existen dos métodos de proxy comúnmente utilizados en Java, a saber: proxy dinámico JDK y proxy dinámico Cglib. Permítanme ofrecerles una breve demostración de los ejemplos de uso sencillos de estos dos agentes dinámicos.
Antes de que el lenguaje pueda ser un proxy para ambos, se requiere una clase base. como sigue:

@Component
public class UserService {
    
    

    public void test() {
    
    
        System.out.println("这是UserService的一个普通方法");
    }
}

Antes de iniciar el proxy, ¿por qué necesita un proxy nuevamente?
Explicación del modo proxy: proporcione un proxy para que otros objetos controlen el acceso a este objeto, mejoren un método en una clase y extiendan el programa.
Es decir, cuando necesitamos mejorar un determinado método, pero no queremos modificar el código original (seguir los principios de diseño: el principio de apertura y cierre), generalmente consideramos usar proxies. En Spring, se utilizan las dos soluciones siguientes para implementar este modo proxy.

1.1 Proxy dinámico Cglib

En el UserService anterior, si creamos un nuevo objeto UserService y luego ejecutamos el método test(), el resultado es obvio. Si ahora queremos agregar lógica adicional a test() sin modificar el código fuente de la clase UserService, entonces podemos usar el mecanismo de proxy dinámico Cglib para crear el objeto UserService, por ejemplo:

 public static void main(String[] args) throws IOException {
    
    
        UserService target = new UserService();
        target.test();


        System.out.println("下面开始是cglib之后的逻辑了");

        // cglib
        {
    
    
            // 使用cglib增强类
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(UserService.class);

            // 定义额外的增强逻辑,增强对象
            enhancer.setCallbacks(new Callback[]{
    
    new MethodInterceptor() {
    
    
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
                    System.out.println("before...");
                    Object result = methodProxy.invoke(target, objects);
                    System.out.println("after...");
                    return result;
                }
            }});

            // 动态代理所创建出来的UserService对象
            UserService userService = (UserService) enhancer.create();

            // 执行这个userService的test方法时,就会额外会执行一些其他逻辑
            userService.test();
        }
    }

Todos los obtenidos son objetos UserService, pero el efecto de ejecutar el método test () es diferente, que es el efecto que trae el proxy.
Lo anterior es la creación del objeto proxy realizada por cglib, que se basa en las clases principal e secundaria: la clase proxy (UserService) es la clase principal, la clase proxy es la subclase y el objeto proxy es el objeto de instancia de la clase de proxy La clase de proxy es creada por cglib, no se preocupa por los programadores.

1.2 Proxy dinámico JDK

Además de la tecnología cglib, el propio jdk también proporciona un mecanismo de proxy dinámico para crear objetos proxy.Pero solo puede ser una interfaz proxy, es decir, UserService primero debe tener una interfaz para utilizar el mecanismo de proxy dinámico jdk para generar un objeto proxy.,Por ejemplo:

public interface UserInterface {
    
    
    void test();
}

public class UserService implements UserInterface{
    
    

    @Override
    public void test() {
    
    
        System.out.println("这是UserService的一个普通方法");
    }
}

Un ejemplo del uso del proxy dinámico JDK para generar un objeto proxy es el siguiente:

 public static void main(String[] args) throws IOException {
    
    
        UserService target = new UserService();
        target.test();

        System.out.println("下面开始是cglib之后的逻辑了");

        // jdk代理
        {
    
    
            // UserInterface接口的代理对象
            Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{
    
    UserInterface.class}, new InvocationHandler() {
    
    

                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
                    System.out.println("before...");
                    Object result = method.invoke(target, args);
                    System.out.println("after...");
                    return result;
                }
            });

            UserInterface userService = (UserInterface) proxy;
            userService.test();
        }
    }

Si reemplaza la nueva Clase [] {UserInterface.class} con la nueva Clase [] {UserService.class}, el código informará directamente un error: (esto también prueba que JDK usa el segundo paradigma de proxy)

java.lang.IllegalArgumentException: UserService is not an interface

Debido a esta limitación, el tipo de objeto proxy generado es UserInterface, no UserService, lo que requiere atención.

1.3 ProxyFactory: encapsulación de Spring de dos proxies

Arriba, presentamos dos tecnologías de proxy dinámico, luego las encapsulamos en Spring y la clase encapsulada se llama ProxyFactory, lo que significa que es una fábrica para crear objetos proxy, que es más conveniente de usar que lo anterior, por ejemplo:

    public static void main(String[] args) throws IOException {
    
    
        UserService target = new UserService();

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvice(new MethodInterceptor() {
    
    
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });

        UserInterface userService = (UserInterface) proxyFactory.getProxy();
        userService.test();
    }

A través de ProxyFactory, ya no podemos preocuparnos por usar el proxy dinámico cglib o jdk. ProxyFactory nos ayudará a juzgar. Si UserService implementa la interfaz, entonces la capa inferior de ProxyFactory usará el proxy dinámico jdk; si la interfaz no está implementada, utilizará la tecnología cglib, el código anterior se debe a que UserService implementa la interfaz UserInterface, por lo que el objeto proxy final generado es del tipo UserInterface.

2. Conocimientos básicos de AOP

Revisión de los conceptos básicos de AOP

Todo el mundo está familiarizado con Spring AOP, pero antes de hablar de AOP, creo que será de gran ayuda para nosotros estudiar más a fondo clasificando los conceptos. Además, creo que incluso si tiene experiencia real en producción en SpringAOP, es posible que no comprenda algunos de los siguientes conceptos. Además, hay algunos conceptos que aparecerán en nuestro [Historial de Desarrollo] más adelante, parece que hay una diferencia de una palabra, pero en realidad son dos cosas diferentes.

  • 切面(AspectJ): En Aop, aspecto se refiere a 【Fideos】. El código de comportamiento público mejorado [es decir, notificación] y el método de corte [es decir, punto de corte] se administran en la clase de aspecto
  • 通知(Advice):[Acción] realizada en un punto de conexión específico de un aspecto. Hay muchos tipos de notificaciones, incluidas [alrededor de], [antes] y [después], etc. Muchos marcos de AOP, incluido Spring, utilizan [interceptor] como modelo de notificación y mantienen una [cadena de interceptores] centrada en el punto de conexión.
  • 切点(PointCut): una afirmación que coincide con un punto de unión. [Notificación de aviso] está asociada con la expresión [punto de corte] y opera en el [punto de conexión] que satisface este [punto de corte] (por ejemplo, al ejecutar un método con un nombre específico). El núcleo de AOP es la coincidencia de expresiones de corte de puntos y puntos de unión. Spring usa la semántica de corte de puntos de AspectJ de forma predeterminada
  • 连接点(JoinPoint): En Spring AOP, un punto de unión siempre representa la ejecución de un método,De hecho, representa el [método] mejorado
  • 目标对象(Target): El objeto de destino se refiere alObjeto mejorado. Es decir, el objeto de la clase que contiene la lógica empresarial principal.
  • 顾问(Advisor): Adviser es una encarnación empaquetada de Advice.Advisor es una combinación de Pointcut y Advice, que se utiliza para administrar Advice y Pointcut., la aplicación no necesita preocuparse (pero el código fuente de la investigación sí debe saberlo)
  • 织入(Weaving): El proceso de cortar consejos en un punto de unión se llama tejido
  • 引入(Introductions): Se pueden introducir dinámicamente otras interfaces e implementaciones en targetClass

(PD: Permítanme hacer una declaración especial. Según mi experiencia, muchas personas confundirán [Consejo] con [Asesor]. Después de todo, el inglés de los dos es demasiado similar)
(PD: Permítanme hacer una declaración especial. Según mi experiencia, muchas personas confundirán [Consejo] con [Asesor]. Después de todo, el inglés de los dos es demasiado similar)
(PD: Permítanme hacer una declaración especial. Según mi experiencia, muchas personas confundirán [Consejo] y [Asesor]. Compruébelo. Para que todos tengan una comprensión clara de estos dos conceptos, aquí hay dos cosas para hablar. aproximadamente por separado.)

Notificar la clasificación de Consejos

Creo que después de leer los conceptos anteriores, te sentirás familiarizado, así es, son las anotaciones que usamos habitualmente. Normalmente, incluye las siguientes categorías:

  1. Antes del consejo: ejecutado antes del método. Corresponde a las anotaciones de Spring AOP @Before. Además, también existe una interfaz API correspondiente: MethodBeforeAdvicehereda la interfazBeforeAdvice
  2. Después de devolver el consejo: se ejecuta después de que regresa el método. Corresponde a las anotaciones de Spring AOP @AfterReturning. Además, existen interfaces API correspondientes:AfterReturningAdvice
  3. Después de lanzar un consejo: se ejecuta después de que el método arroja una excepción. Corresponde a las anotaciones de Spring AOP @AfterThrowing. Además, existen interfaces API correspondientes:ThrowsAdvice
  4. Después (finalmente) del consejo: se ejecuta después de que el método finalmente se ejecuta, este es el último, más tarde que el retorno. Corresponde a las anotaciones de Spring AOP @After. Además, existen interfaces API correspondientes:AfterAdvice
  5. Alrededor del consejo: este es el consejo más poderoso y el orden de ejecución se puede personalizar. Corresponde a las anotaciones de Spring AOP @Around. Además, existen interfaces API correspondientes:MethodInterceptor

Spring analizará las cinco anotaciones en las clases de Consejos correspondientes:

  1. @Before: AspectJMethodBeforeAdvice es en realidad un MethodBeforeAdvice
  2. @AfterReturning: AspectJAfterReturningAdvice, que en realidad es un AfterReturningAdvice
  3. @AfterThrowing: AspectJAfterThrowingAdvice, que en realidad es un MethodInterceptor
  4. @After: AspectJAfterAdvice es en realidad un MethodInterceptor
  5. @Around: AspectJAroundAdvice es en realidad un MethodInterceptor

Comprensión del asesor

Similar al Consejo, existe un concepto de Asesor. Un Asesor se compone de un Pointcut y un Consejo. El Pointcut puede especificar la lógica que se va a representar. Su diagrama de modelo es aproximadamente el siguiente:
inserte la descripción de la imagen aquí
Por ejemplo, hay dos métodos en una clase UserService. Según el ejemplo anterior, estos dos métodos serán proxy y mejorados. Ahora podemos usar Advisor para controlar qué método proxy. Por ejemplo:

	public static void main(String[] args) {
    
    
        PointcutAdvisor pointcutAdvisor = new PointcutAdvisor() {
    
    

            @Override
            public Pointcut getPointcut() {
    
    
                return new StaticMethodMatcherPointcut() {
    
    
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
    
    
                        return method.getName().equals("test");
                    }
                };
            }

            @Override
            public Advice getAdvice() {
    
    
                return new MethodInterceptor() {
    
    
                    @Override
                    public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
                        System.out.println("before...");
                        Object result = invocation.proceed();
                        System.out.println("after...");
                        return result;
                    }
                };
            }

            @Override
            public boolean isPerInstance() {
    
    
                return false;
            }
        };

        // 注入advisor
        UserService target = new UserService();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvisor(pointcutAdvisor);
        UserInterface userService = (UserInterface) proxyFactory.getProxy();
        userService.test();
    }

    // 系统输出如下:
    // before...
    // 这是UserService的一个普通方法
    // after...

El código anterior indica que el objeto proxy generado testsolo se mejorará cuando se ejecute este método, y se ejecutará lógica adicional, pero no se mejorará cuando se ejecuten otros métodos.

3. Cómo crear objetos proxy

Lo anterior introdujo tecnologías como ProxyFactory, Advisor, Advice y PointCut proporcionadas en Spring para realizar la creación de objetos proxy, pero cuando usamos Spring, no usaremos ProxyFactory directamente de esta manera. Por ejemplo, esperamos que el objeto proxy generado por ProxyFactory pueda ser un bean directamente, y el objeto proxy de UserSerivce se pueda obtener directamente del contenedor Spring, y Spring los admite, pero, como desarrolladores, debemos decirle a Spring, Esas clases necesita ser proxy y cuál es la lógica del proxy.

3.1 ProxyFactoryBean: versión de implementación temprana de Spring AOP

En los primeros días de Spring, si desea implementar AOP, como crear un bean proxy UserService, debe hacer lo siguiente:

    @Bean
    public ProxyFactoryBean userServiceProxy() {
    
    
        UserService userService = new UserService();

        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.addAdvice(new MethodInterceptor() {
    
    

            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
                System.out.println("before...1111");
                Object result = invocation.proceed();
                System.out.println("after...1111");
                return result;
            }
        });
        return proxyFactoryBean;
    }

Como se puede ver en el código anterior, para implementar AOP en la etapa inicial, debe hacer lo siguiente:

  1. Vincula fuertemente un objeto proxy, como se muestra arriba:userService
  2. Añade una notificación. Lo anterior es una clase de implementación anónima new MethodInterceptor. MethodInterceptores Adviceuna subinterfaz de la interfaz
  3. Utilice FactoryBean para obtener el objeto proxy

Este método se utiliza para definir un UserService Bean y ha pasado AOP. Pero obviamente,Este método solo puede apuntar a un determinado Bean y solo se puede controlar hasta el nivel de clase, todos los métodos de la clase son interceptados., lo que significa que si queremos cortar más frijoles, debemos crear un FactoryBean correspondiente para cada frijol. Esto es inaceptable para nosotros.
ProxyFactoryBean también tiene funciones adicionales, como definir un Advise o Advisor como un bean y luego configurarlo en ProxyFactoryBean:

	@Bean
    public MethodInterceptor zhouyuAroundAdvice() {
    
    
        return new MethodInterceptor() {
    
    
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }

    @Bean
    public ProxyFactoryBean userService() {
    
    
        UserService userService = new UserService();

        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.setInterceptorNames("zhouyuAroundAdvise");
        return proxyFactoryBean;
    }

3.2 NameMatchMethodPointcutAdvisor: introduce el concepto de Asesor para mejorar el problema de interceptar todos los métodos

¿Recuerdas lo que dije antes sobre Advisor? El asesor es una combinación de [Pointcut+Advice]. En general, es relativamente simple: al inicializar, debe especificar uno internamente Advicey luego Advisordecidir Pointcutqué métodos interceptar, y el trabajo que debe completarse después de la interceptación aún se Advicerealiza internamente.

PD: Los estudiantes con experiencia en AOP deben saber Pointcutque la granularidad está en realidad en el nivel del método...

NameMatchMethodPointcutAdvisorEs Advisoruna subclase de y no es difícil ver por el nombre de la clase que coincide con el punto de entrada según el nombre del método. Por supuesto, hay varias subclases diferentes, aquí se muestra solo un uso simple de esto para demostrarlo.

@Bean
public MethodInterceptor zhouyuAroundAdvice() {
    
    
    return new MethodInterceptor() {
    
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
            System.out.println("before...");
            Object result = invocation.proceed();
            System.out.println("after...");
            return result;
        }
    };
}
	
@Bean
public NameMatchMethodPointcutAdvisor nameMethodAdvisor() {
    
    
    NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();

    // 通知(Advice)  :是我们的通知类
    // 通知者(Advisor):是经过包装后的细粒度控制方式。
    advisor.setAdvice(zhouyuAroundAdvice());
    advisor.setMappedNames("test");
    return  advisor;
}

/**
 * FactoryBean方式单个: ProxyFactoryBean
 *  控制粒度到方法
 * @return
 */
@Bean
public ProxyFactoryBean calculateProxy(){
    
    
	
	UserService userService = new UserService();
    ProxyFactoryBean userService=new ProxyFactoryBean();
    userService.setInterceptorNames("nameMethodAdvisor");   
    userService.setTarget(userService);
    return userService;
}

Podemos ver que tulingLogAspecteste bean está configurado con un asesor y hay un consejo dentro del asesor. El asesor es responsable de hacer coincidir los métodos y el asesoramiento interno es responsable de implementar el empaquetado de métodos.
Tenga en cuenta que la configuración de mappedNames aquí puede especificar múltiples, separados por comas, que pueden ser métodos en diferentes clases. En comparación con la especificación directa de consejos, el asesor logra un control más detallado, porque si configura los consejos aquí, todos los métodos serán interceptados.

3.3 BeanNameAutoProxyCreator: mejora el problema de que solo se puede cortar un Bean

Para mejorar el problema mencionado anteriormente de que el AOP [granularidad de clase] es demasiado pequeño, se creó un AutoProxyesquema de interfaz llamado . Como puede ver por el nombre, es una solución de proxy automática. Usamos una de sus clases de implementación aquí BeanNameAutoProxyCreatorpara brindarle una demostración simple.
ProxyFactoryBean tiene que especificar el objeto proxy por sí mismo, luego podemos usar BeanNameAutoProxyCreator para representar el bean especificando el nombre de un bean.

    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
    
    
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setBeanNames("userSe*");
        beanNameAutoProxyCreator.setInterceptorNames("zhouyuAroundAdvice");
        beanNameAutoProxyCreator.setProxyTargetClass(true);
        return beanNameAutoProxyCreator;
    }

Como se puede ver en el código anterior, para AutoProxyimplementar AOP, debe hacer lo siguiente:

  1. Especifica las reglas para cortar objetos. Aquí está el nombre del frijol usando coincidencia difusauserSe*
  2. Igual que arriba, agregue una notificación. aquí lo tieneszhouyuAroundAdvice
  3. A diferencia de la necesidad de usar FactoryBean para obtener el objeto proxy anterior, ya que se dice que es un proxy automático, cuando obtenemos el bean según el beanName, si se detecta que necesita ser proxy, se generará un objeto proxy. generado automáticamente para ello

Obviamente, a través de BeanNameAutoProxyCreator, se puede realizar AOP en lotes de beans, y se especifica la lógica del proxy y se especifica un InterceptorName, que es un Consejo. El requisito previo es que el Consejo también debe ser un Bean, para que Spring pueda encontrar pero BeanNameAutoProxyCreator no es suficiente. ¿Es perfecto? Solo puede beanNameespecificar el Bean que desea proxy de acuerdo con

3.4 DefaultAdvisorAutoProxyCreator: una solución AutoProxy más potente

En este punto, es una solución relativamente madura.

   @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
    
    
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.addMethodName("test");

        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(pointcut);
        defaultPointcutAdvisor.setAdvice(new ZhouyuAfterReturningAdvice());

        return defaultPointcutAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    
    
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        return defaultAdvisorAutoProxyCreator;
    }

A través de DefaultAdvisorAutoProxyCreator, todos los beans de tipo Advisor se encontrarán directamente, y el Bean que se va a representar y la lógica del proxy se determinarán de acuerdo con la información de PointCut y Advice en el Advisor. No sé si lo sientes, pero este método es muy parecido al método de anotación que estamos usando actualmente. Así es, lo que puedo decirles de antemano es que en el esquema de implementación de AOP basado en anotaciones, no es más que descubrir todas las clases de aspectos, luego analizar [Pointcut] y [Advice], y empaquetarlos en [Advisor]. , Después de una serie de procesos de proxy, se crea un objeto de proxy.

Finalmente, pegue un ejemplo de AOP que usamos a menudo en el proyecto:

@Aspect
@Component
public class MyAspect {
    
    

    @Pointcut("execution(* org.tuling.spring.aop..*(..))")
    public void pointCut() {
    
    

    }

    @Before("pointCut()")
    public void before() {
    
    
        System.out.println("方法执行之前,记录一下入口时间。" + System.currentTimeMillis());
    }

    @AfterReturning("pointCut()")
    public void afrer() {
    
    
        System.out.println("方法执行之后,记录一下出口时间。" + System.currentTimeMillis());
    }
}

A través de la clase anterior, definimos directamente el método que será proxy (a través de una expresión) y la lógica del proxy (método modificado por @Before), que es simple y clara, por lo que para Spring, todo lo que tiene que hacer es analizar estos Anotaciones, después del análisis, obtenga los objetos Pointcut correspondientes y los objetos de asesoramiento, genere objetos Advisor, tírelos a ProxyFactory y luego genere los objetos proxy correspondientes. Cómo analizar estas anotaciones es lo que las anotaciones deben hacer, que se analizará en detalle más adelante @EnableAspectJAutoProxy.

4. Análisis del código fuente subyacente del esquema de anotación AOP

@AspectSabemos que Spring agrega anotaciones a su clase a través de una clase de aspecto , define un Pointcutmétodo y finalmente define una serie de métodos de mejora Advice. Esto completa la operación de aspecto de un objeto. Entonces, si eres el autor de Spring, piénsalo. Según lo anterior, ¿qué pasos crees que son necesarios? Mi resumen es el siguiente:

  1. Encuentre todos los beans de aspecto, es decir, @Aspectbeans con anotaciones en la clase.
  2. Analice todos los consejos, a saber: @Before, @After, @AfterReturning, @AfterThrowing, @Aroundestas 5 anotaciones, Pointcutencapsúlelas con sus funciones, empaquetelas una por una Advisory guárdelas
  3. Crear una clase de proxy dinámica
  4. Al llamar al método de la clase proxy, busque todos sus potenciadores y mejore el método actual.

Luego, intentemos estudiar el código fuente para ver si coincide con nuestro razonamiento.

4.1 Comenzando desde @EnableAspectJAutoProxy

Ahora que hemos entrado en la era Springboot, es posible que muchos estudiantes no sepan u olviden que cuando queramos presentar Spring AOP, usaremos esta anotación. ¿Para qué sirve esta anotación? Hagamos clic para abrir el código fuente, de la siguiente manera:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    
    

	/**
	 * 指示是否要创建基于子类(CGLIB)的代理,而不是基于标准Java接口的代理。默认为false。
	 */
	boolean proxyTargetClass() default false;

	/**
	 * 表明代理应该由AOP框架作为ThreadLocal公开,
	 * 以便通过org.springframework.aop.framework.AopContext类进行检索。
	 * 默认为关闭,即不保证AopContext访问将工作。
	 */
	boolean exposeProxy() default false;
}

Del código fuente anterior podemos encontrar que se usa en la clase de anotación.¿Qué @Import(AspectJAutoProxyRegistrar.class)significa esto? como sigue:

PD: Acerca de @Importlas anotaciones, como sigue:
inserte la descripción de la imagen aquí

Como se mencionó anteriormente, en realidad es solo registrar una definición de bean en nuestra fábrica de frijoles. Hagamos clic para ver qué hace esta clase. El código fuente es el siguiente:

Ruta de clase completa: org.springframework.context.annotation.AspectJAutoProxyRegistrar
Anotación de clase: según la anotación @EnableAspectJAutoProxy proporcionada, registre un AnnotationAwareAspectJAutoProxyCreator en el BeanDefinitionRegistry actual.

/**
* 根据给定的@EnableAspectJAutoProxy注释
* 在当前BeanDefinitionRegistry中注册一个AnnotationAwareAspectJAutoProxyCreator。
*/
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    
    

	/**
	 * 根据导入的@Configuration类上的@EnableAspectJAutoProxy.proxyTargetClass()
	 * 属性的值注册、升级和配置AspectJ自动代理创建器。
	 */
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
    

		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
    
    
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
    
    
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
    
    
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}
}

Para ser honesto, en este punto, básicamente podemos descubrir que una de las clases principales de Spring AOP es AnnotationAwareAspectJAutoProxyCreatorla clase mencionada en el comentario anterior. En cuanto al método, proxyTargetClassno exposeProxyte contaré mucho, ya sabes lo que significa cuando lo usas. Él no es nuestro principal objeto de investigación.

Solo una nota rápida:
proxyTargetClasses un atributo de la anotación @EnableAspectJAutoProxy. Indica si se deben crear servidores proxy basados ​​en subclases (CGLIB) en lugar de servidores proxy JDK basados ​​en interfaces Java estándar. El valor predeterminado es falso. (Como mencionamos anteriormente, el proceso general de Spring crea el modo de proxy de selección de proxy. Y este parámetro significa que si se establece en verdadero, el proxy CGLIB se creará de forma predeterminada y el proxy JDK ya no se considerará). anotado por
exposeProxylos atributos @EnableAspectJAutoProxy. Indica que el marco AOP debe exponer el proxy como ThreadLocal para su recuperación a través de la clase org.springframework.aop.framework.AopContext. El valor predeterminado está desactivado, es decir, no hay garantía de que el acceso a AopContext funcione.

4.2 AnnotationAwareAspectJAutoProxyCreator: una breve introducción

Aquí simplemente miramos el diagrama de herencia de esta clase, es decir, la anotación de clase, para que podamos tener una comprensión básica de ella. Primero mire la anotación de la clase:

/**
 * AspectJAwareAdvisorAutoProxyCreator子类,它处理当前应用程序上下文中的所有AspectJ注释方面,以及Spring Advisors。
 * 任何AspectJ注释的类都会被自动识别,如果Spring AOP的基于代理的模型能够应用它们,那么它们的建议就会被应用。这涵盖了方法执行连接点。
 * 如果使用了<aop:include>元素,那么只有名称与include模式匹配的@AspectJ bean才会被认为是定义了用于Spring自动代理的方面。
 * Spring advisor的处理遵循org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator中建立的规则。
 */
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
    
    
}

En los comentarios de la interfaz anteriores, podemos ver varias palabras clave:Maneja todos los aspectos anotados de AspectJ en el contexto de la aplicación actual, así como Spring Advisors. Cualquier clase anotada de AspectJ se reconoce automáticamente. Oh, estos no son los dos primeros pasos de los [pasos aproximados] que mencioné al principio. Echemos un vistazo al diagrama de herencia nuevamente:
inserte la descripción de la imagen aquí
veamos si hay muchas interfaces familiares, como: BeanPostProcessor y sus 2 subinterfaces.
Además, también dijimos antes que la implementación de AOP se encuentra en la etapa [después de la inicialización]. A continuación, comenzamos a analizar realmente el código fuente de la implementación de AOP.

4.3 Revisión de conceptos

BeanPostProcessor: Dado que se completa después de la [inicialización], la implementación de Spring AOP debe ser inseparable de esta interfaz. Sin embargo, cuando lo implementamos, utilizamos una de sus clases de implementación, AnnotationAwareAspectJAutoProxyCreator. Entonces, la mayor parte de la implementación de esta clase está en AbstractAutoProxyCreator.

4.4 Explicación detallada del método.

La entrada del análisis del código fuente es la siguiente:

Ruta completa: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization
explicación del método: ejecutar BeanPostProcessor después del método de inicialización

	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {
    
    

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
    
    
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
    
    
				return result;
			}
			result = current;
		}
		return result;
	}

resumir

Supongo que te gusta

Origin blog.csdn.net/qq_32681589/article/details/132459769
Recomendado
Clasificación