dependencia spring-ioc-cíclica

La dependencia circular de spring-ioc, el entorno es el siguiente, probamos 3 dependencias circulares de objetos

<?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"
	   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"
		default-autowire="byType">
		<context:component-scan base-package="org.springframework.work2"></context:component-scan>
		<bean id="eService" class="org.springframework.work2.service.EService">

		</bean>
		<bean id="tService" class="org.springframework.work2.service.TService">

		</bean>
		<bean id="uService" class="org.springframework.work2.service.UService">

		</bean>
</beans>


package org.springframework.work2.service;

import org.springframework.stereotype.Component;

public class EService {

	TService tService;

	public EService(){
		System.out.println(" eService object init");
	}


	public void settService(TService tService) {
		this.tService = tService;
	}

}


package org.springframework.work2.service;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

public class TService{

	UService uService;

	public TService(){
		System.out.println(" tService object init");
	}


	public void setuService(UService uService) {
		this.uService = uService;
	}
}

package org.springframework.work2.service;

import org.springframework.stereotype.Component;


public class UService {

	EService eService;

	public UService(){
		System.out.println(" uService object init");
	}


	public void seteService(EService eService) {
		this.eService = eService;
	}

}

package org.springframework.work2;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.work2.app.AppConfig;
import org.springframework.work2.service.EService;
import org.springframework.work2.service.TService;
import org.springframework.work2.service.UService;

public class Main {

	public static void main(String[] args) {
		//AnnotationConfigApplicationContext cxc = new AnnotationConfigApplicationContext(AppConfig.class);
		ClassPathXmlApplicationContext cxc = new ClassPathXmlApplicationContext("classpath:spring2.xml");
		System.out.println(cxc.getBean("eService"));

	}
}

El resultado de la impresión es el siguiente

Se debe esperar el resultado impreso.

Entonces podemos pensar en el proceso general de creación de un bean en primavera como clase - objeto de inicialización - atributo de llenado (es decir, dependencia) - el resto del ciclo de vida

Comencemos a discutir juntos cómo Spring resuelve el problema de las dependencias circulares.
Primero echemos un vistazo a la cadena de llamadas, que se puede depurar junto con mis puntos de interrupción. Tenga en cuenta que después de la primera ronda de puntos de interrupción, recuerde cancelar la configuración o restablecer las condiciones de los puntos de interrupción; de lo contrario, no podrá levantarse.

El primero if (isFactoryBean (beanName)) no entrará, porque este objeto no es un FactoryBean, por lo que entrará en el método getBean del else
. La diferencia entre BeanFactory y FactoryBean

Centrémonos primero en el método getSingleton. Establezca el punto de interrupción de eService para ingresar, esto es cierto para admitir dependencias circulares de forma predeterminada

Aquí hay 3 mapas, echemos un vistazo

Hay 10 objetos en el primer mapa, que están arraigados dentro de Spring. En este momento, no hay ningún objeto escrito por nosotros en él.

Entonces, la primera vez que getSingleton regresa vacío, los otros dos mapas también están vacíos. Si este objeto no se recupera, entonces no hay duda de que Spring creará este objeto.

Punto de interrupción en la línea 321 primero

Luego puede hacer clic directamente en el método para ingresar el método en la línea 225 para regresar al punto de interrupción en la línea 323 (no sé por qué la lógica debajo de esta línea de código en las primeras tres rondas de prueba no se ejecutará, y volverá directamente)

Continuar, comenzar a crear el objeto (creado por el constructor juzgado)

Empiece a envolver frijoles e inyectar propiedades.

Entramos directamente y localizamos la última línea de código

El método de construcción inferido por resorte para inicializar el objeto.

Comience a inyectar propiedades, antes de inyectar propiedades, primero determinará si se necesita una dependencia circular

Estas tres condiciones son para determinar si el objeto es un singleton, la segunda por defecto es verdadera y la tercera, como sugiere el nombre, se refiere a si el objeto se está creando (durante el ciclo de vida del bean)

Si este objeto se está creando se puede ver en este método getSingleton

Entonces mira el siguiente método

Puede ver que EService se coloca en el segundo mapa

 

La entrada para completar las propiedades comienza con el método populateBean, hacemos clic y miramos dentro

Hemos configurado inyección automática en xml, el modelo de inyección es por tipo, por lo que ingresaremos el siguiente método para ensamblar atributos automáticamente, seguimos haciendo clic en

El nombre de propiedad obtenido es tService, que es exactamente el objeto del que depende eService

Creo que todos entienden el seguimiento del código aquí. Cuando se confía en TService durante la creación de EService, primero se creará el objeto TService, y continuaremos haciendo clic para ver, y luego miraremos la cadena de llamadas del depurador. Así es, volvemos al método que acabamos de comenzar. .

 

Cuando descubrimos que confiamos en UService cuando creamos TService, definitivamente seguiremos volviendo al mismo método getBean. Entonces, si descubre que depende de EService cuando crea UService, ¿tiene que continuar el ciclo sin fin? Spring siempre ha sido inteligente y capaz. Veamos cómo lo hace la primavera. ¿Recuerdas los tres mapas mencionados anteriormente? ¿Recuerdas este método? Cada vez que se agregan objetos dependientes al segundo mapa, veamos qué sucede la segunda vez

Al inicializar:

	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

singletonObjects 10 个 objeto raíz

singletonFactories 0

earlySingletonObjects 0 个

El resultado de nuestro primer eService es:

singletonObjects 10 个 objeto raíz

singletonFactories 1 个 --eService

earlySingletonObjects 0 个

El resultado del segundo tService es:

singletonObjects 10 个 objeto raíz

singletonFactories 2 个 --eService , tService

earlySingletonObjects 0 个

El resultado del tercer uService es:

singletonObjects 10 个 objeto raíz

singletonFactories 3 个 --eService , tService , uService

earlySingletonObjects 0 个

Cuando uService encuentra un eService dependiente por tercera vez, establecerá el eService de singletonFactories en earlySingletonObjects y luego regresará.

singletonObjects 10 个 objeto raíz

singletonFactories 2 个 , tService , uService

earlySingletonObjects 1 个 eService

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

Cuando se crea eService, los otros dos objetos se crearán de la misma manera.

En pocas palabras, Spring completa la dependencia circular del bean a través de dos mapas.

Pero si usa el método de construcción para resolver la dependencia circular, aunque la inyección del método de construcción se recomienda después de la primavera 4.0, pero la primavera arrojará una excepción al analizar la inyección del método de construcción. El bean solicitado está actualmente en creación: ¿Hay una referencia circular irresoluble? ?
Entonces, cómo resolverlo, puede usar el método set para inyectar el objeto dependiente.

¿Por qué Spring usa la inyección del constructor para tener tal problema?

Luego, volvamos al primer punto anterior: 3 mapas, y hay un conjunto Set <String> singletonsCurrentlyInCreation debajo de los 3 mapas.

¿Cuál es el propósito de esta colección de conjuntos? Por lo tanto, para el segundo punto, volvemos a lo que se mencionó anteriormente. Hay tres condiciones de juicio para juzgar si se necesitan referencias circulares, y la tercera condición es

Juzgará si este objeto se está creando, cómo sabe Spring si este objeto se está creando. Es esta colección de sets la que lo hace, pero ¿cómo lo hace la primavera?

No sé si ha notado que un objeto de eService init está impreso arriba. El objeto se inicializa primero y luego se inyectan las propiedades. Después de explicar la inyección de bucle del atributo, también deberíamos notar que los datos se colocarán en el segundo mapa solo cuando las tres condiciones de la aplicación de bucle sean verdaderas.

Y en el método getSingleton recién comenzamos

En este momento, el tercer nivel debe estar vacío. Es posible que deseemos revisar los datos almacenados en la caché de segundo nivel que es el segundo mapa cuando las tres condiciones anteriores son verdaderas, por lo que cuando regresemos, vale la pena tomar el segundo nivel. . Al encontrar el último nivel de dependencias circulares

Hay un valor de retorno en este lugar.

Sin embargo, no se almacenan datos en la caché secundaria de principio a fin en el proceso de dependencia circular del método de construcción combinado con la explicación anterior. Pero la dependencia circular del método de construcción vuelve a getSingleton en la figura anterior en esta línea. ¿Por qué no baja esta línea? No puede almacenar datos en el mapa sin bajar. Si está interesado, puede hacer clic y echar un vistazo.

Entonces no vi la dependencia circular del constructor y no puse datos en el caché de segundo nivel. Pero el objeto actual ya existe en la colección de conjuntos, que se está creando. Cuando este método encuentre dependencias y regrese vacío por última vez, irá al segundo método getSingleton y cambiará el método del objeto dependiente a este En la colección de conjuntos, pero la colección de conjuntos viene con efectos de deduplicación (compatibles con la sintaxis de Java), es normal informar un error.

Entonces, si es la dependencia circular del método de construcción, no se puede realizar, y el método set solo se puede usar para inyectar el objeto que depende de


Artículo siguiente¿Cómo filtra el resorte los métodos de construcción adecuados para crear objetos?

 

Supongo que te gusta

Origin blog.csdn.net/qq_38108719/article/details/103102188
Recomendado
Clasificación