Como han dicho las otras respuestas, Spring solo se encarga de ello, crea los frijoles e inyecta según sea necesario.
Una de las consecuencias es que la configuración de la propiedad / inyección de bean puede ocurrir en un orden diferente al que parecen implicar los archivos de cableado XML. Por lo tanto, debe tener cuidado de que los establecedores de su propiedad no realicen una inicialización que dependa de que otros establecedores ya hayan sido llamados. La forma de lidiar con esto es declarar que los beans implementan la InitializingBeaninterfaz. Esto requiere que implemente el afterPropertiesSet()método, y aquí es donde realiza la inicialización crítica. (También incluyo código para verificar que realmente se hayan establecido propiedades importantes).
El manual de referencia de Spring explica cómo se resuelven las dependencias circulares. Los granos se instancian primero y luego se inyectan entre sí.
Considere esta clase:
package mypackage;publicclass A {public A(){System.out.println("Creating instance of A");}private B b;publicvoid setB(B b){System.out.println("Setting property b of A instance");this.b = b;}}
Y una clase similar B:
package mypackage;publicclass B {public B(){System.out.println("Creating instance of B");}private A a;publicvoid setA(A a){System.out.println("Setting property a of B instance");this.a = a;}}
Es por eso que Spring requiere un constructor sin argumentos ;-)
Chris Thompson
15
¡No si usa argumentos de constructor en sus definiciones de frijol! (Pero en ese caso no puede tener una dependencia circular.)
Richard Fearn
1
@Richard Fearn ¿Tu publicación acerca de la explicación del problema en lugar de proporcionar una solución?
gstackoverflow
4
Si intenta utilizar la inyección del constructor, el mensaje de error esorg.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
X. Wo Satuk
19
En el código base con el que estoy trabajando (más de 1 millón de líneas de código) tuvimos un problema con tiempos de inicio largos, alrededor de 60 segundos. Obtuvimos más de 12000 FactoryBeanNotInitializedException .
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);returnfalse;
Aparentemente, esto sucede cuando los FactoryBean s están involucrados en un gráfico de dependencia cíclica. Lo solucionamos implementando ApplicationContextAware e InitializingBean e inyectando manualmente los beans.
Interesante recomendación. Mi contra recomendación sería solo hacer eso si sospecha que las referencias circulares están causando un problema de rendimiento. (Sería una lástima romper algo que no necesitaba romperse al tratar de solucionar un problema que no necesitaba ser arreglado.)
Stephen C
2
Es una pendiente resbaladiza hacia el infierno del mantenimiento para permitir dependencias circulares, rediseñar su arquitectura a partir de dependencias circulares puede ser realmente complicado, por así decirlo en nuestro caso. Lo que significó más o menos para nosotros fue que obtuvimos el doble de conexiones de base de datos durante el inicio que las de sessionfactory involucradas en la dependencia circular. En otros escenarios, podrían haber ocurrido cosas mucho más desastrosas debido a que el bean se instanciara más de 12000 veces. Seguro que deberías escribir tus beans para que soporten su destrucción, pero ¿por qué permitir este comportamiento en primer lugar?
jontejj
@jontejj, te mereces una galleta
serprime
14
Problema ->
Class A {privatefinal B b;// must initialize in ctor/instance blockpublic A(B b){this.b = b };}Class B {privatefinal A a;// must initialize in ctor/instance blockpublic B(A a){this.a = a };}
// Causado por: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error al crear el bean con el nombre 'A': El bean solicitado se está creando actualmente: ¿Hay una referencia circular irresoluble?
Solución 1 ->
Class A {private B b;public A(){};//getter-setter for B b}Class B {private A a;public B(){};//getter-setter for A a}
Solución 2 ->
Class A {privatefinal B b;// must initialize in ctor/instance blockpublic A(@Lazy B b){this.b = b };}Class B {privatefinal A a;// must initialize in ctor/instance blockpublic B(A a){this.a = a };}
En general, puede confiar en que Spring hará lo correcto. Detecta problemas de configuración, como referencias a beans inexistentes y dependencias circulares, en el momento de la carga del contenedor. Spring establece las propiedades y resuelve las dependencias lo más tarde posible, cuando el bean se crea realmente.
El contenedor Spring es capaz de resolver dependencias circulares basadas en Setter pero da 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 manera 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 de Bean B y Bean B de Bean C, el contenedor inicializa completamente C antes de inyectarlo a B y una vez que B se inicializa completamente, se inyecta a A. Pero en caso de dependencia circular, uno de los beans se inyecta al otro antes de que se inicialice por completo.
Digamos que A depende de B, luego Spring primero instanciará A, luego B, luego establecerá propiedades para B, luego establecerá B en A.
Pero, ¿y si B también depende de A?
Mi comprensión es: Spring acaba de descubrir que A se ha construido (constructor ejecutado), pero no se ha inicializado completamente (no se han realizado todas las inyecciones), bueno, pensó, está bien, es tolerable que A no esté completamente inicializado, simplemente establezca esto no- instancias A completamente inicializadas en B por ahora. Una vez que B se inicializó por completo, se estableció en A y, finalmente, A se inició completamente ahora.
En otras palabras, simplemente expone A a B de antemano.
Para las dependencias a través del constructor, Sprint simplemente lanza BeanCurrentlyInCreationException, para resolver esta excepción, establezca lazy-init en verdadero para el bean que depende de otros a través del constructor-arg.
Si generalmente usa constructor-injection y no desea cambiar a property-injection, entonces el método de búsqueda- inyección de Spring permitirá que un bean busque perezosamente al otro y, por lo tanto, solucione la dependencia cíclica. Vea aquí: http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161
La inyección del constructor falla cuando hay una dependencia circular entre los granos de primavera. Entonces, en este caso, la inyección de Setter ayuda a resolver el problema.
Básicamente, Constructor Injection es útil para dependencias obligatorias, para dependencias opcionales es mejor usar la inyección Setter porque podemos hacer reinyección.
Si dos beans son dependientes entre sí, entonces no deberíamos usar la inyección Constructor en ambas definiciones de bean. En su lugar, tenemos que usar la inyección de setter en cualquiera de los beans. (por supuesto, podemos usar la inyección de setter en ambas definiciones de bean, pero las inyecciones de constructor en ambas lanzan 'BeanCurrentlyInCreationException'
Respuestas:
Como han dicho las otras respuestas, Spring solo se encarga de ello, crea los frijoles e inyecta según sea necesario.
Una de las consecuencias es que la configuración de la propiedad / inyección de bean puede ocurrir en un orden diferente al que parecen implicar los archivos de cableado XML. Por lo tanto, debe tener cuidado de que los establecedores de su propiedad no realicen una inicialización que dependa de que otros establecedores ya hayan sido llamados. La forma de lidiar con esto es declarar que los beans implementan la
InitializingBean
interfaz. Esto requiere que implemente elafterPropertiesSet()
método, y aquí es donde realiza la inicialización crítica. (También incluyo código para verificar que realmente se hayan establecido propiedades importantes).fuente
El manual de referencia de Spring explica cómo se resuelven las dependencias circulares. Los granos se instancian primero y luego se inyectan entre sí.
Considere esta clase:
Y una clase similar
B
:Si tenías este archivo de configuración:
Vería el siguiente resultado al crear un contexto usando esta configuración:
Tenga en cuenta que cuando
a
se inyectab
,a
aún no se ha inicializado por completo.fuente
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
En el código base con el que estoy trabajando (más de 1 millón de líneas de código) tuvimos un problema con tiempos de inicio largos, alrededor de 60 segundos. Obtuvimos más de 12000 FactoryBeanNotInitializedException .
Lo que hice fue establecer un punto de interrupción condicional en AbstractBeanFactory # doGetBean
donde lo hace
destroySingleton(beanName)
imprimí la excepción con el código de punto de interrupción condicional:Aparentemente, esto sucede cuando los FactoryBean s están involucrados en un gráfico de dependencia cíclica. Lo solucionamos implementando ApplicationContextAware e InitializingBean e inyectando manualmente los beans.
Esto redujo el tiempo de inicio a unos 15 segundos.
Por lo tanto, no asuma siempre que Spring puede resolver estas referencias por usted.
Por esta razón, recomendaría deshabilitar la resolución de dependencia cíclica con AbstractRefreshableApplicationContext # setAllowCircularReferences (false) para evitar muchos problemas futuros.
fuente
Problema ->
// Causado por: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error al crear el bean con el nombre 'A': El bean solicitado se está creando actualmente: ¿Hay una referencia circular irresoluble?
Solución 1 ->
Solución 2 ->
fuente
Simplemente lo hace. Instancia
a
yb
, e inyecta cada uno en el otro (usando sus métodos de establecimiento).¿Cuál es el problema?
fuente
De la referencia de primavera :
fuente
El contenedor Spring es capaz de resolver dependencias circulares basadas en Setter pero da 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 manera 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 de Bean B y Bean B de Bean C, el contenedor inicializa completamente C antes de inyectarlo a B y una vez que B se inicializa completamente, se inyecta a A. Pero en caso de dependencia circular, uno de los beans se inyecta al otro antes de que se inicialice por completo.
fuente
Digamos que A depende de B, luego Spring primero instanciará A, luego B, luego establecerá propiedades para B, luego establecerá B en A.
Pero, ¿y si B también depende de A?
Mi comprensión es: Spring acaba de descubrir que A se ha construido (constructor ejecutado), pero no se ha inicializado completamente (no se han realizado todas las inyecciones), bueno, pensó, está bien, es tolerable que A no esté completamente inicializado, simplemente establezca esto no- instancias A completamente inicializadas en B por ahora. Una vez que B se inicializó por completo, se estableció en A y, finalmente, A se inició completamente ahora.
En otras palabras, simplemente expone A a B de antemano.
Para las dependencias a través del constructor, Sprint simplemente lanza BeanCurrentlyInCreationException, para resolver esta excepción, establezca lazy-init en verdadero para el bean que depende de otros a través del constructor-arg.
fuente
Aquí se explica claramente . Gracias a Eugen Paraschiv.
La dependencia circular es un olor de diseño, ya sea arréglelo o use @Lazy para la dependencia que causa el problema para solucionarlo.
fuente
Si generalmente usa constructor-injection y no desea cambiar a property-injection, entonces el método de búsqueda- inyección de Spring permitirá que un bean busque perezosamente al otro y, por lo tanto, solucione la dependencia cíclica. Vea aquí: http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161
fuente
La inyección del constructor falla cuando hay una dependencia circular entre los granos de primavera. Entonces, en este caso, la inyección de Setter ayuda a resolver el problema.
Básicamente, Constructor Injection es útil para dependencias obligatorias, para dependencias opcionales es mejor usar la inyección Setter porque podemos hacer reinyección.
fuente
Si dos beans son dependientes entre sí, entonces no deberíamos usar la inyección Constructor en ambas definiciones de bean. En su lugar, tenemos que usar la inyección de setter en cualquiera de los beans. (por supuesto, podemos usar la inyección de setter en ambas definiciones de bean, pero las inyecciones de constructor en ambas lanzan 'BeanCurrentlyInCreationException'
Consulte el documento de Spring en " https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#resources-resource "
fuente