Análisis del código fuente del proceso AOP: análisis de la información de configuración y creación de objetos proxy

Este artículo incluso comienza a analizar el código fuente del proceso de aop. A diferencia de IOC, aop es relativamente simple. Nuestro contenido principal de seguimiento es el análisis de la información de configuración relacionada con aop, la creación de agentes y la invocación de procesos de agentes. Estas tres partes hablarán brevemente sobre el análisis del código fuente de aop .

Describa brevemente el pasado y el presente de AOP

En primer lugar, el comienzo de la serie de artículos sigue siendo una vieja rutina. Permítanme hablar sobre algunos conocimientos conceptuales de aop. La principal fuente de información es Internet y el oficial. Omita esta sección si tiene cierta comprensión de aop.

  1. AOP (Aspect Orient Programming): programación orientada a aspectos;
  2. Propósito: se utiliza para cuestiones transversales en el sistema, como la gestión de registros y la gestión de transacciones;
  3. Implementación: use el modo proxy para agregar funciones al objeto proxy a través del objeto proxy. Por lo tanto, la clave es que el marco AOP crea automáticamente objetos proxy AOP, y el modo proxy se divide en proxy estático y proxy dinámico;
  4. Framework:
    AspectJ usa proxies estáticos, mejorados en tiempo de compilación y genera objetos proxy en tiempo de compilación;
    SpringAOP usa proxies dinámicos, mejorados en tiempo de ejecución y genera dinámicamente objetos proxy en tiempo de ejecución;

En la actualidad, hay tres métodos de configuración para Spring AOP. Spring es compatible con versiones anteriores, por lo que puede usarlo con confianza.

  • Configuración basada en la interfaz de Spring 1.2: el primer Spring AOP se basó completamente en varias interfaces
  • Configuración basada en el esquema de Spring 2.0: después de Spring 2.0, use XML para configurar, use el espacio de nombres
  • Configuración Spring 2.0 @AspectJ : use anotaciones para configurar, este método parece el más conveniente y, aunque aquí se llama @AspectJ, no tiene nada que ver con AspectJ.

Cabe señalar que el Spring AOP presentado aquí es código Spring puro y no tiene nada que ver con AspectJ, pero Spring amplía los conceptos en AspectJ, incluido el uso de anotaciones en el paquete jar proporcionado por AspectJ, pero no depende de su implementación. funciones Las anotaciones como @Aspect, @Pointcut, @Before, @After son todas de AspectJ, pero la implementación de la función todavía la implementa Spring AOP.

Actualmente hay dos mecanismos de implementación subyacentes de Spring AOP: proxy dinámico JDK y generación de código de bytes dinámico CGLIB. Tener una comprensión del uso de estos dos mecanismos antes de leer el código fuente conduce a una mejor comprensión del código fuente.

Análisis de código fuente

Para el código fuente, use el código fuente que usó al analizar el IOC antes y luego cree una clase de prueba.

public static void main(String[] args) {
    
    

  ClassPathXmlApplicationContext applicationContext =
    new ClassPathXmlApplicationContext("classpath:applicationContext-aop.xml");

  UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
  userService.findAll();
}

Nuestro objetivo principal del análisis del código fuente de hoy es probar la creación de applicationContext en la clase, que es el contenido cuando se inicia el contenedor, y hablaremos sobre la invocación de métodos específicos más adelante.

Debido a que IOC ya analizó todos los métodos de actualización de métodos básicos una vez antes, los amigos que no conocen IOC pueden comenzar a leer desde el segundo artículo de IOC: IOC Process Analysis-BeanFactory Creation . Ahora que lo hemos visto, vayamos directamente al método específico.

Análisis de información de configuración de AOP

En primer lugar, la configuración de la etiqueta de aop es un poco diferente de la etiqueta del bean, por lo que si queremos verla, comenzamos con el análisis del contenido de la etiqueta, es decir, la construcción de BeanDefinition.

<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>
		
	<context:component-scan base-package="com.itheima"/>
	
	<!--@EnableAspectJAutoProxy-->
	<aop:aspectj-autoproxy />
</beans>

El código se encuentra directamente aquí, el método parseBeanDefinitions (la búsqueda global es suficiente aquí, cómo encontrarlo o ver el segundo artículo de IOC), lo que puede ver aquí es que habrá dos ramas del método de análisis, que tenemos también se explicó antes del mecanismo de esquema de Spring, por lo que la etiqueta aop debe ser el segundo método parseCustomElement.

if (node instanceof Element) {
    
    
  Element ele = (Element) node;
  //下面有两个分支
  if (delegate.isDefaultNamespace(ele)) {
    
    
    // 1.1 默认命名空间节点的处理,例如: <bean id="test" class="" />
    //分支1:代表解析标准元素 <import />、<alias />、<bean />、<beans /> 这几个
    //标准节点
    parseDefaultElement(ele, delegate);
  }
  else {
    
    
    // 1.2 自定义命名空间节点的处理,例如:<context:component-scan/>、<aop:aspectj-autoproxy/>
    //分支2:代表解析 <mvc />、<task />、<context />、<aop /> 、<component-scan />等
    //特殊节点
    delegate.parseCustomElement(ele);
  }
}

Método de seguimiento.

El primer enfoque aquí es obtener un procesador de espacio de nombres, y cuando presentamos el mecanismo de esquema antes, ya dijimos que este analizador lo proporciona la configuración de etiqueta correspondiente, por lo que debemos encontrar el "http:/ /www.springframework" correspondiente. .org/schema/aop” y luego busque el archivo spring.handlers correspondiente según el logotipo.

//解析命名空间,得到一个命名空间处理器
//重点
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
//开始解析
//主线 重点
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

Si la búsqueda global es difícil de encontrar, porque puede haber muchos archivos de configuración que han introducido aop, puede hacer clic directamente en el logotipo en el xml, saltar al paquete jar correspondiente y luego buscar el archivo spring.handlers correspondiente en la carpeta inf

imagen-20220428154603852

El analizador de esta etiqueta aop se almacena en este archivo.

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

Luego siga directamente con la clase AopNamespaceHandler.

Puede ver la generación de diferentes analizadores para cada etiqueta. Lo que configuramos arriba es la etiqueta aspectj-autoproxy, la etiqueta básica de aop, así que busque directamente la clase AspectJAutoProxyBeanDefinitionParser correspondiente. En cuanto a cuándo se llama a este método init, sigamos mirando hacia abajo.

public class AopNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.5+ XSDs
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace in 2.5+
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}
}

Volviendo al método parseCustomElement, siga con su método de resolución.

Podemos ver que el método init se llama en este punto, lo que significa que aquí se crean diferentes objetos del analizador y luego se devuelven.

NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;

Vuelva al método parseCustomElement nuevamente.

Ahora que sabemos que el analizador actual es el objeto AspectJAutoProxyBeanDefinitionParser, podemos continuar con el seguimiento de su método de análisis.

Método de seguimiento. En lo que debemos centrarnos es en el primer método AspectJAnnotationAutoProxyCreator registrado.

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
    
    
  // 1.注册AspectJAnnotationAutoProxyCreator
  AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
  // 2.对于注解中子节点的处理
  extendBeanDefinition(element, parserContext);
  return null;
}

Hacer un seguimiento.

El propósito aquí es registrar el objeto AnnotationAwareAspectJAutoProxyCreator en BeanFactory. Tenga en cuenta que esto no está registrado en el grupo de singleton, específicamente por qué, vea a continuación.

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
  ParserContext parserContext, Element sourceElement) {
    
    

  // 1.注册AnnotationAwareAspectJAutoProxyCreator
  BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
    parserContext.getRegistry(), parserContext.extractSource(sourceElement));
  // 2.对于proxy-target-class以及expose-proxy属性的处理
  useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
  // 3.注册组件并通知,便于监听器做进一步处理
  registerComponentIfNecessary(beanDefinition, parserContext);
}

Podemos ver la estructura del objeto AnnotationAwareAspectJAutoProxyCreator.

imagen-20220428160623332

La interfaz de nivel superior de este objeto es la interfaz BeanPostProcessor, lo que significa que este objeto es un objeto de posprocesador Bean. Entonces, si se registra en BeanFactory, no se registra en el grupo de fuerza único, sino en la colección de BeanPostProcessor.

resumen

El análisis de la etiqueta aop aquí es así, el propósito es registrar el posprocesador del primer Bean en la colección BeanPostProcessor.

Ejecución de BeanPostProcessor correspondiente a AOP

En lo anterior, vemos que se ha creado BeanPostProcessor relacionado con AOP, por lo que el siguiente paso es ver la ejecución de estos posprocesadores de Bean, por lo que ubicamos directamente el método doCreateBean del contenido de inicialización de Bean.

Después de localizar el método, busque directamente la llamada del método initializeBean del BeanPostProcessor correspondiente para ejecutar el contenido relacionado.

El método previo analiza todos los métodos advisor-postProcessBeforeInitialization

Seguimiento del método. La llamada del primer método previo sigue al método applyBeanPostProcessorsBeforeInitialization. Sin embargo, hemos visto este método muchas veces antes, no tiene nada que ver con él, simplemente recorre todos los BeanPostProcessors y ejecuta el método postProcessBeforeInitialization correspondiente.

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
    
    
  // 2.在初始化前应用BeanPostProcessor的postProcessBeforeInitialization方法,允许对bean实例进行包装
  wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

Hacemos un seguimiento directo del método Before del objeto AnnotationAwareAspectJAutoProxyCreator creado anteriormente. Tenga en cuenta que el seguimiento aquí es la implementación del objeto AbstractAutoProxyCreator de la clase principal, porque este objeto no implementa el método Before.

Código de seguimiento. Encuentre su punto clave y llame al método shouldSkip Preste atención a si el método Before crea un objeto proxy, pero cargará todos los asesores.

if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
    
    
  this.advisedBeans.put(cacheKey, Boolean.FALSE);
  return null;
}

Hacer un seguimiento. Tenga en cuenta que es necesario hacer un seguimiento y encontrar la reescritura de la subclase correspondiente. Luego busque el método clave llamada al método findCandidateAdvisors

List<Advisor> candidateAdvisors = findCandidateAdvisors();

Todavía seguimiento. O encuentre su subclase correspondiente para reescribir.

Aquí, todos los asesores encontrados según las reglas de la clase padre se encontrarán primero, pero aquí no hay ninguno, es decir, nulo, por lo que depende de la llamada del método buildAspectJAdvisors.

@Override
protected List<Advisor> findCandidateAdvisors() {
    
    
  // Add all the Spring advisors found according to superclass rules.
  // 1.添加根据父类规则找到的所有advisor
  List<Advisor> advisors = super.findCandidateAdvisors();
  // Build Advisors for all AspectJ aspects in the bean factory.
  // 2.为bean工厂中的所有AspectJ方面构建advisor
  if (this.aspectJAdvisorsBuilder != null) {
    
    
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  }
  return advisors;
}

Método de seguimiento.

Primero, todos los cachés de objetos de los asesores se obtendrán una vez. Si hay un valor, se devolverá directamente. Si no hay ningún valor, se analizará. El propósito es analizar solo una vez, porque todas las inicializaciones de beans usarán este BeanPostProcessor, por lo que es necesario evitar el análisis repetido.

List<String> aspectNames = this.aspectBeanNames;

// 1.如果aspectNames为空,则进行解析
if (aspectNames == null) {
    
    

Luego obtenga todo el beanName, recorra.

// 1.1 获取所有的beanName
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
  this.beanFactory, Object.class, true, false);

// 1.2 循环遍历所有的beanName,找出对应的增强方法
for (String beanName : beanNames) {
    
    

El primer punto importante es que la interfaz que debe ser modificada por la anotación de Aspecto se integrará en un objeto de asesor.

// 1.4 如果beanType存在Aspect注解则进行处理
if (this.advisorFactory.isAspect(beanType)) {
    
    

El segundo punto clave es llamar al método getAdvisors para obtener la colección de objetos Advisor encapsulada por todos los métodos del objeto actual.

// 使用BeanFactory和beanName创建一个BeanFactoryAspectInstanceFactory,主要用来创建切面对象实例
MetadataAwareAspectInstanceFactory factory =
  new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 1.5 解析标记AspectJ注解中的增强方法===》》》》
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

Siga el método getAdvisors para ver el contenido específico del paquete.

Aquí se encapsula en diferentes objetos Advisor de acuerdo con diferentes anotaciones modificadas en el método.

// 2.获取Aspect()标注的类名
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();

// 5.获取切面类中的方法(也就是我们用来进行逻辑增强的方法,被@Around、@After等注解修饰的方法,使用@Pointcut的方法不处理)==>
for (Method method : getAdvisorMethods(aspectClass)) {
    
    
  // 6.处理method,获取增强器==>
  Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
  if (advisor != null) {
    
    
    // 7.如果增强器不为空,则添加到advisors
    advisors.add(advisor);
  }
}

No hay necesidad de continuar con el seguimiento, echemos un vistazo a la redacción general.

La primera es la clase de modificación de la anotación @Aspect, que indica que esta clase es una clase de aspecto y se puede encontrar mediante aop

Luego, la anotación @Pointcut modifica el primer método, todos los objetos específicos que necesitan ser interceptados

Finalmente, la anotación @Before modifica el método previo, la anotación @After modifica el método posterior y la anotación @Around modifica el método circundante.

@Component
@Aspect // 切面
public class AopAspect {
    
    
  
	@Pointcut("execution(* com.itheima.service..*.*(..))")
	public void pointcut() {
    
    
	}

	@Before("pointcut()")
	public void before() {
    
    
		System.out.println("before");
	}

	@After("pointcut()")
	public void after() {
    
    
		System.out.println("after");
	}

	@Around("pointcut()")
	public Object around(ProceedingJoinPoint proceedingJoinPoint) throws InterruptedException {
    
    
		System.out.println("around advice start");
		try {
    
    
			Object result = proceedingJoinPoint.proceed();
			System.out.println("around advice end");
			return result;
		} catch (Throwable throwable) {
    
    
			throwable.printStackTrace();
			return null;
		}
	}
}

El método de publicación genera un objeto proxy - método postProcessAfterInitialization

O regrese al objeto AbstractAutoProxyCreator y busque el método postProcessAfterInitialization directamente.

Código de seguimiento.

El primero es generar la clave para el almacenamiento en caché y luego llamar al método wrapIfNecessary.

//2.如果beanName为空,使用Class对象作为缓存的key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 1.判断当前bean是否需要被代理,如果需要则进行封装
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
    
    
  return wrapIfNecessary(bean, beanName, cacheKey);
}

Hacer un seguimiento.

Aquí primero obtenemos todos los asesores en el caché de análisis anterior, primero podemos ver el método getAdvicesAndAdvisorsForBean.

// 4.获取当前bean的Advices和Advisors===》
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

Después del seguimiento, el punto clave es llamar directamente al método findCandidateAdvisors. No lo veremos aquí, solo seguiremos de nuevo.

Como puede ver en esta parte, el primer paso es obtener todos los objetos Advisor y luego filtrar los Advisors que interceptan este objeto. Tenga en cuenta que todavía estamos en el proceso de inicialización del objeto Bean, por lo que el objeto al que se hace referencia aquí es el objeto que se está inicializando. Finalmente, simplemente ordene los objetos Advisor calificados en orden.La ordenación aquí es para ordenar los métodos circundantes, previos y posteriores, para facilitar el orden de llamada de los objetos proxy subsiguientes cuando se ejecutan.

En cuanto al método findCandidateAdvisors, es exactamente igual que la llamada anterior, la única diferencia es que esta vez no necesita analizarse nuevamente, sino que devuelve directamente la colección de caché anterior.

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    
    
  // 1.查找所有的候选Advisor
  //将所有拥有@Aspect注解的类转换为advisors(aspectJAdvisorsBuilder.buildAspectJAdvisors)
  // 2.从所有候选的Advisor中找出符合条件的
  List<Advisor> candidateAdvisors = findCandidateAdvisors();
  List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  // 3.扩展方法,留个子类实现
  extendAdvisors(eligibleAdvisors);
  if (!eligibleAdvisors.isEmpty()) {
    
    
    // 4.对符合条件的Advisor进行排序
    eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  }
  return eligibleAdvisors;
}

Volvamos al método wrapIfNecessary.

La continuación es la parte de la creación del proxy. Finalmente, el proxy creado se almacenará en el caché y se devolverá el resultado. No volveremos a este método más adelante, así que sea optimista.

// 5.如果存在增强器则创建代理
if (specificInterceptors != DO_NOT_PROXY) {
    
    
  this.advisedBeans.put(cacheKey, Boolean.TRUE);
  // 5.1 创建代理对象:这边SingletonTargetSource的target属性存放的就是我们原来的bean实例(也就是被代理对象),
  // 用于最后增加逻辑执行完毕后,通过反射执行我们真正的方法时使用(method.invoke(bean, args))
  Object proxy = createProxy(
    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  // 5.2 创建完代理后,将cacheKey -> 代理类的class放到缓存
  this.proxyTypes.put(cacheKey, proxy.getClass());
  // 返回代理对象
  return proxy;
}

Continúe siguiendo el método createProxy.

Hay muchos códigos aquí, por lo que no necesita preocuparse por ellos, solo lea la última oración a continuación.

proxyFactory.getProxy(getProxyClassLoader());

Código de seguimiento.

No se apresure a mirar getProxy, primero mire el método createAopProxy.

public Object getProxy(@Nullable ClassLoader classLoader) {
    
    
  // 1.createAopProxy:创建AopProxy
  // 2.getProxy(classLoader):获取代理对象实例
  return createAopProxy().getProxy(classLoader);
}

La llamada aquí es relativamente simple, por lo que no la seguiré paso a paso, solo mire el resultado.

Aquí se juzgará si se utiliza el agente Cglib o el agente JDK. La conclusión directa es que el proxy JDK se usa de forma predeterminada y el proxy Cglib está configurado. Objeto correspondiente al proxy JDK: JdkDynamicAopProxy, objeto correspondiente al proxy Cglib: ObjenesisCglibAopProxy. Aquí debemos recordar los objetos correspondientes a los dos proxies. Cuando pasemos por el proceso más adelante, miraremos los proxies y miraremos directamente el método de invocación de los objetos correspondientes.

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    
    
  // 1.判断使用JDK动态代理还是Cglib代理
  // optimize:用于控制通过cglib创建的代理是否使用激进的优化策略。除非完全了解AOP如何处理代理优化,否则不推荐使用这个配置,目前这个属性仅用于cglib代理,对jdk动态代理无效
  // proxyTargetClass:默认为false,设置为true时,强制使用cglib代理,设置方式:<aop:aspectj-autoproxy proxy-target-class="true" />
  // hasNoUserSuppliedProxyInterfaces:config是否存在代理接口或者只有SpringProxy一个接口
  if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    
    
    // 拿到要被代理的对象的类型
    Class<?> targetClass = config.getTargetClass();
    if (targetClass == null) {
    
    
      // TargetSource无法确定目标类:代理创建需要接口或目标。
      throw new AopConfigException("TargetSource cannot determine target class: " +
                                   "Either an interface or a target is required for proxy creation.");
    }
    // 要被代理的对象是接口 || targetClass是Proxy class
    // 当且仅当使用getProxyClass方法或newProxyInstance方法动态生成指定的类作为代理类时,才返回true。
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    
    
      // JDK动态代理,这边的入参config(AdvisedSupport)实际上是ProxyFactory对象
      // 具体为:AbstractAutoProxyCreator中的proxyFactory.getProxy发起的调用,在ProxyCreatorSupport使用了this作为参数,
      // 调用了的本方法,这边的this就是发起调用的proxyFactory对象,而proxyFactory对象中包含了要执行的的拦截器
      return new JdkDynamicAopProxy(config);
    }
    // Cglib代理
    return new ObjenesisCglibAopProxy(config);
  }
  else {
    
    
    // JDK动态代理
    return new JdkDynamicAopProxy(config);
  }
}

Es fácil mirar hacia atrás en el método getProxy, porque no tenemos configuración, así que aquí está el uso del proxy jdk.

Es para obtener el objeto proxy a través de la clase de implementación classLoader, interfaz e InvocationHandler.

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    
    
  if (logger.isTraceEnabled()) {
    
    
    logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
  }
  // 1.拿到要被代理对象的所有接口
  Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
  findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
  // 2.通过classLoader、接口、InvocationHandler实现类,来获取到代理对象
  return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

resumen

De esta forma se acaba el contenido de generar el proxy, lo principal es ver si usar cglib o jdk como proxy, y el análisis de los asesores.

Resumir

esta vez es para entender algunos conceptos de aop claro que debo encontrar mas informacion en internet de lo que hago porque yo tambien la estoy buscando ese no es el punto lo principal es la descripcion de la creacion y ejecucion timing de los agentes aop Posteriormente analizaremos el proceso completo de la solicitud.

Apéndice Artículos de la serie de análisis de código fuente de Spring

COI

tiempo artículo
2022-03-09 Una breve descripción de los conceptos básicos de Spring y el proceso IOC
2022-03-11 Análisis de procesos IOC - creación de BeanFactory
2022-03-14 Análisis de procesos IOC - BeanFactoyPostProcessor y BeanPostProcessor
2022-03-15 Análisis de procesos IOC: creación de instancias e inicialización
2022-03-17 Análisis de procesos IOC - dependencia circular

POA

tiempo artículo
2022-03-19 Una breve descripción de los conceptos básicos de Spring y el proceso IOC
2022-03-20 Análisis del código fuente del proceso AOP: solicite llamar a todo el proceso

Supongo que te gusta

Origin blog.csdn.net/qq_39339965/article/details/124489133
Recomendado
Clasificación