Pregunta Dependencia circular en primavera


¿Cómo resuelve la primavera esto? El frijol A depende del frijol b, y el frijol b del frijol a.


73
2017-08-14 22:20


origen


Respuestas:


Como han dicho las otras respuestas, Spring solo se encarga de crear las semillas e inyectarlas según sea necesario.

Una de las consecuencias es que la configuración de inyección / propiedad de frijol puede ocurrir en un orden diferente al que parecen implicar sus archivos de cableado XML. Por lo tanto, debe tener cuidado de que sus instaladores de propiedades no realicen la inicialización que depende de otros instaladores que ya hayan sido llamados. La forma de lidiar con esto es declarar que los beans implementan el InitializingBean interfaz. Esto requiere que implemente el afterPropertiesSet() método, y aquí es donde haces la inicialización crítica. (También incluyo el código para verificar que las propiedades importantes realmente se hayan establecido).


33
2017-08-15 00:07



los Manual de referencia de primavera explica cómo se resuelven las dependencias circulares. Primero se crean instancias de los beans, luego se inyectan entre sí.

Considera esta clase:

package mypackage;

public class A {

    public A() {
        System.out.println("Creating instance of A");
    }

    private B b;

    public void setB(B b) {
        System.out.println("Setting property b of A instance");
        this.b = b;
    }

}

Y una clase similar B:

package mypackage;

public class B {

    public B() {
        System.out.println("Creating instance of B");
    }

    private A a;

    public void setA(A a) {
        System.out.println("Setting property a of B instance");
        this.a = a;
    }

}

Si luego tuvieras este archivo de configuración:

<bean id="a" class="mypackage.A">
    <property name="b" ref="b" />
</bean>

<bean id="b" class="mypackage.B">
    <property name="a" ref="a" />
</bean>

Vería el siguiente resultado al crear un contexto usando esta configuración:

Creating instance of A
Creating instance of B
Setting property a of B instance
Setting property b of A instance

Tenga en cuenta que cuando a se inyecta en b, a aún no está completamente inicializado.


63
2017-08-14 22:44



En la base de código con la que estoy trabajando (1 millón de líneas de código), tuvimos un problema con los tiempos de inicio largos, de alrededor de 60 segundos. Estábamos recibiendo más de 12000 FactoryBeanNotInitializedException.

Lo que hice fue establecer un punto de corte condicional en AbstractBeanFactory # doGetBean

catch (BeansException ex) {
   // Explicitly remove instance from singleton cache: It might have been put there
   // eagerly by the creation process, to allow for circular reference resolution.
   // Also remove any beans that received a temporary reference to the bean.
   destroySingleton(beanName);
   throw ex;
}

donde lo hace destroySingleton(beanName) Imprimí la excepción con el código de punto de interrupción condicional:

   System.out.println(ex);
   return false;

Aparentemente esto sucede cuando FactoryBeans están involucrados en un gráfico de dependencia cíclica. Lo solucionamos implementando ApplicationContextAware y InitializingBean y manualmente inyectando los frijoles.

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class A implements ApplicationContextAware, InitializingBean{

    private B cyclicDepenency;
    private ApplicationContext ctx;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        ctx = applicationContext;
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        cyclicDepenency = ctx.getBean(B.class);
    }

    public void useCyclicDependency()
    {
        cyclicDepenency.doSomething();
    }
}

Esto redujo el tiempo de inicio a alrededor de 15 segundos.

Por lo tanto, no siempre asuma que la primavera puede ser buena para resolver estas referencias por usted.

Por esta razón, recomendaría desactivar la resolución de dependencia cíclica con AbstractRefreshableApplicationContext # setAllowCircularReferences (false) para prevenir muchos problemas futuros.


15
2018-06-14 15:08



Simplemente lo hace. Crea una instancia a y b, e inyecta cada uno en el otro (usando sus métodos setter).

¿Cuál es el problema?


12
2017-08-14 22:29



Desde el Referencia de primavera:

Generalmente puedes confiar en Spring para hacer   Lo correcto. Detecta   problemas de configuración, como   referencias a frijoles inexistentes y   dependencias circulares, en el contenedor   tiempo de carga. Spring establece propiedades y   resuelve las dependencias tan tarde como   posible, cuando el frijol es en realidad   creado.


6
2017-08-14 22:50



El contenedor Spring es capaz de resolver dependencias circulares basadas en Setter pero ofrece una excepción de tiempo de ejecución BeanCurrentlyInCreationException en caso de dependencias circulares basadas en Constructor. En caso de dependencia circular basada en Setter, el contenedor IOC lo maneja de forma diferente a un escenario típico en el que configuraría completamente el bean colaborador antes de inyectarlo. Por ejemplo, si Bean A tiene una dependencia en Bean B y Bean B en Bean C, el contenedor inicializa completamente C antes de inyectarlo a B y una vez que B está completamente inicializado se inyecta a A. Pero en caso de dependencia circular, uno de los granos se inyecta a la otra antes de que esté completamente inicializado.


5
2018-03-16 19:02



Está claramente explicado aquí. Gracias a Eugen Paraschiv.

La dependencia circular es un olor de diseño, ya sea solucionarlo o usar @Lazy para la dependencia que causa problemas para solucionarlo.


4
2018-06-20 14:01