Jak powiedziały inne odpowiedzi, Spring po prostu się tym zajmuje, tworząc ziarna i wstrzykując je w razie potrzeby.
Jedną z konsekwencji jest to, że wstrzykiwanie / ustawianie właściwości fasoli może zachodzić w innej kolejności, niż sugerowałyby to pliki łączników XML. Musisz więc uważać, aby ustawienia ustawiające właściwości nie przeprowadzały inicjalizacji, która polega na wywołaniu innych metod ustawiających. Sposobem na rozwiązanie tego problemu jest zadeklarowanie fasoli jako implementującej InitializingBeaninterfejs. Wymaga to zaimplementowania afterPropertiesSet()metody i tutaj wykonujesz krytyczną inicjalizację. (Dołączam również kod, aby sprawdzić, czy ważne właściwości zostały faktycznie ustawione).
Reference Manual Wiosna wyjaśnia, w jaki sposób wzajemnie od siebie zależnych są rozwiązane. Ziarna są najpierw tworzone, a następnie wstrzykiwane do siebie nawzajem.
Rozważ tę klasę:
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;}}
I podobna klasa 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;}}
Dlatego Spring wymaga konstruktora bez argumentów ;-)
Chris Thompson,
15
Nie, jeśli używasz argumentów konstruktora w definicjach komponentów bean! (Ale w takim przypadku nie możesz mieć zależności cyklicznej.)
Richard Fearn,
1
@Richard Fearn Czy Twój post dotyczy wyjaśnienia problemu, a nie podania rozwiązania?
gstackoverflow
4
Jeśli spróbujesz użyć iniekcji konstruktora, komunikat o błędzie toorg.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
W bazie kodu, z którą pracuję (1 milion + wierszy kodu) mieliśmy problem z długimi czasami uruchamiania, około 60 sekund. Byliśmy coraz 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;}
gdzie to jest destroySingleton(beanName), wydrukowałem wyjątek z kodem warunkowego punktu przerwania:
Ciekawa rekomendacja. Moją przeciwną rekomendacją byłoby zrobienie tego tylko wtedy, gdy podejrzewasz, że odwołania cykliczne powodują problem z wydajnością. (Szkoda byłoby zepsuć coś, czego nie trzeba było zepsuć, próbując naprawić problem, który nie wymagał naprawy.)
Stephen C
2
Jest to śliskie zejście do piekła konserwacji, aby umożliwić zależności cykliczne, przeprojektowanie architektury z zależności cyklicznych może być naprawdę trudne, tak jak to było w naszym przypadku. Z grubsza oznaczało to dla nas to, że podczas uruchamiania otrzymaliśmy dwa razy więcej połączeń z bazą danych, niż fabryka sesji była zaangażowana w zależność cykliczną. W innych scenariuszach mogło dojść do znacznie bardziej katastrofalnych rzeczy z powodu tworzenia instancji fasoli ponad 12000 razy. Jasne, powinieneś napisać swoje ziarna tak, aby wspierały ich niszczenie, ale po co w ogóle pozwalać na takie zachowanie?
jontejj
@jontejj, zasługujesz na ciastko
serprime
14
Problem ->
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 };}
// Spowodowane przez: org.springframework.beans.factory.BeanCurrentlyInCreationException: Błąd podczas tworzenia komponentu bean o nazwie „A”: Żądany komponent bean jest obecnie tworzony: czy istnieje nierozwiązywalne cykliczne odwołanie?
Rozwiązanie 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}
Rozwiązanie 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 };}
Generalnie możesz ufać Springowi, że postąpi właściwie. Wykrywa problemy z konfiguracją, takie jak odwołania do nieistniejących komponentów bean i zależności cyklicznych, w czasie ładowania kontenera. Spring ustawia właściwości i rozwiązuje zależności tak późno, jak to możliwe, kiedy fasola jest faktycznie tworzona.
Kontener Spring jest w stanie rozwiązać zależności cykliczne oparte na narzędziu Setter, ale daje wyjątek czasu wykonywania BeanCurrentlyInCreationException w przypadku zależności cyklicznych opartych na konstruktorze. W przypadku zależności cyklicznej opartej na programie Setter, kontener IOC obsługuje go inaczej niż w typowym scenariuszu, w którym w pełni skonfigurowałby współpracujący komponent bean przed wstrzyknięciem. Na przykład, jeśli Bean A ma zależność od Bean B i Bean B od Bean C, kontener w pełni inicjuje C przed wstrzyknięciem go do B i po pełnym zainicjowaniu B jest wstrzykiwany do A. Ale w przypadku zależności cyklicznej, jeden ziaren jest wstrzykiwana do drugiej, zanim zostanie w pełni zainicjowana.
Powiedzmy, że A zależy od B, a następnie Spring najpierw utworzy wystąpienie A, potem B, a następnie ustawi właściwości dla B, a następnie ustawi B na A.
Ale co, jeśli B również zależy od A?
Rozumiem: Spring właśnie odkrył, że A został skonstruowany (wykonano konstruktor), ale nie został w pełni zainicjowany (nie wykonano wszystkich wstrzyknięć), cóż, pomyślał, jest OK, to tolerowane, że A nie jest w pełni zainicjowany, po prostu ustaw to nie- na razie w pełni zainicjalizowane instancje A w B. Po pełnym zainicjowaniu B został ustawiony na A, a ostatecznie A został teraz w pełni zainicjowany.
Innymi słowy, po prostu wystawia z wyprzedzeniem A na B.
W przypadku zależności za pośrednictwem konstruktora Sprint po prostu wyrzuć BeanCurrentlyInCreationException, aby rozwiązać ten wyjątek, ustaw lazy-init na true dla komponentu bean, który zależy od innych, poprzez sposób konstruktora-arg.
Jeśli generalnie używasz iniekcji konstruktora i nie chcesz przełączać się na wstrzykiwanie właściwości, metoda wyszukiwania Springa pozwoli jednej fasoli leniwie wyszukać drugą, a tym samym obejść cykliczną zależność. Zobacz tutaj: http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161
Wstrzyknięcie konstruktora kończy się niepowodzeniem, gdy między fasolkami wiosennymi występuje zależność kołowa. Więc w tym przypadku my Setter wtrysk pomaga rozwiązać problem.
Zasadniczo iniekcja konstruktora jest przydatna w przypadku zależności obowiązkowych, w przypadku zależności opcjonalnych lepiej jest używać iniekcji settera, ponieważ możemy wykonać ponowne wstrzyknięcie.
Jeśli dwie fasole są od siebie zależne, nie powinniśmy używać wtrysku konstruktora w obu definicjach fasoli. Zamiast tego musimy użyć zastrzyku ustawiającego w dowolnej fasoli. (oczywiście możemy użyć iniekcji setter w obu definicjach bean, ale iniekcje konstruktora w obu rzutach 'BeanCurrentlyInCreationException'
Odpowiedzi:
Jak powiedziały inne odpowiedzi, Spring po prostu się tym zajmuje, tworząc ziarna i wstrzykując je w razie potrzeby.
Jedną z konsekwencji jest to, że wstrzykiwanie / ustawianie właściwości fasoli może zachodzić w innej kolejności, niż sugerowałyby to pliki łączników XML. Musisz więc uważać, aby ustawienia ustawiające właściwości nie przeprowadzały inicjalizacji, która polega na wywołaniu innych metod ustawiających. Sposobem na rozwiązanie tego problemu jest zadeklarowanie fasoli jako implementującej
InitializingBean
interfejs. Wymaga to zaimplementowaniaafterPropertiesSet()
metody i tutaj wykonujesz krytyczną inicjalizację. (Dołączam również kod, aby sprawdzić, czy ważne właściwości zostały faktycznie ustawione).źródło
Reference Manual Wiosna wyjaśnia, w jaki sposób wzajemnie od siebie zależnych są rozwiązane. Ziarna są najpierw tworzone, a następnie wstrzykiwane do siebie nawzajem.
Rozważ tę klasę:
I podobna klasa
B
:Jeśli wtedy miałeś ten plik konfiguracyjny:
Podczas tworzenia kontekstu przy użyciu tej konfiguracji zobaczysz następujące dane wyjściowe:
Zauważ, że kiedy
a
jest wstrzykiwanyb
,a
nie jest jeszcze w pełni zainicjowany.źródło
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
W bazie kodu, z którą pracuję (1 milion + wierszy kodu) mieliśmy problem z długimi czasami uruchamiania, około 60 sekund. Byliśmy coraz 12000+ FactoryBeanNotInitializedException .
To, co zrobiłem, to ustawienie warunkowego punktu przerwania w AbstractBeanFactory # doGetBean
gdzie to jest
destroySingleton(beanName)
, wydrukowałem wyjątek z kodem warunkowego punktu przerwania:Najwyraźniej dzieje się tak, gdy FactoryBean są zaangażowane w cykliczny wykres zależności. Rozwiązaliśmy to, wdrażając ApplicationContextAware i InitializingBean oraz ręcznie wprowadzając ziarna.
Skróciło to czas uruchamiania do około 15 sekund.
Dlatego nie zawsze zakładaj, że wiosna może być dobra w rozwiązywaniu tych odniesień.
Z tego powodu polecam wyłączenie cyklicznego rozwiązywania zależności za pomocą AbstractRefreshableApplicationContext # setAllowCircularReferences (false), aby zapobiec wielu przyszłym problemom.
źródło
Problem ->
// Spowodowane przez: org.springframework.beans.factory.BeanCurrentlyInCreationException: Błąd podczas tworzenia komponentu bean o nazwie „A”: Żądany komponent bean jest obecnie tworzony: czy istnieje nierozwiązywalne cykliczne odwołanie?
Rozwiązanie 1 ->
Rozwiązanie 2 ->
źródło
Po prostu to robi. Tworzy instancje
a
ib
i wstrzykuje je do siebie (używając ich metod ustawiających).Jaki jest problem?
źródło
Ze źródła wiosennego :
źródło
Kontener Spring jest w stanie rozwiązać zależności cykliczne oparte na narzędziu Setter, ale daje wyjątek czasu wykonywania BeanCurrentlyInCreationException w przypadku zależności cyklicznych opartych na konstruktorze. W przypadku zależności cyklicznej opartej na programie Setter, kontener IOC obsługuje go inaczej niż w typowym scenariuszu, w którym w pełni skonfigurowałby współpracujący komponent bean przed wstrzyknięciem. Na przykład, jeśli Bean A ma zależność od Bean B i Bean B od Bean C, kontener w pełni inicjuje C przed wstrzyknięciem go do B i po pełnym zainicjowaniu B jest wstrzykiwany do A. Ale w przypadku zależności cyklicznej, jeden ziaren jest wstrzykiwana do drugiej, zanim zostanie w pełni zainicjowana.
źródło
Powiedzmy, że A zależy od B, a następnie Spring najpierw utworzy wystąpienie A, potem B, a następnie ustawi właściwości dla B, a następnie ustawi B na A.
Ale co, jeśli B również zależy od A?
Rozumiem: Spring właśnie odkrył, że A został skonstruowany (wykonano konstruktor), ale nie został w pełni zainicjowany (nie wykonano wszystkich wstrzyknięć), cóż, pomyślał, jest OK, to tolerowane, że A nie jest w pełni zainicjowany, po prostu ustaw to nie- na razie w pełni zainicjalizowane instancje A w B. Po pełnym zainicjowaniu B został ustawiony na A, a ostatecznie A został teraz w pełni zainicjowany.
Innymi słowy, po prostu wystawia z wyprzedzeniem A na B.
W przypadku zależności za pośrednictwem konstruktora Sprint po prostu wyrzuć BeanCurrentlyInCreationException, aby rozwiązać ten wyjątek, ustaw lazy-init na true dla komponentu bean, który zależy od innych, poprzez sposób konstruktora-arg.
źródło
Jest to jasno wyjaśnione tutaj . Podziękowania dla Eugena Paraschiva.
Zależność cykliczna jest zapachem projektu, napraw ją lub użyj @Lazy dla zależności, która powoduje problem w jej obejściu.
źródło
Jeśli generalnie używasz iniekcji konstruktora i nie chcesz przełączać się na wstrzykiwanie właściwości, metoda wyszukiwania Springa pozwoli jednej fasoli leniwie wyszukać drugą, a tym samym obejść cykliczną zależność. Zobacz tutaj: http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161
źródło
Wstrzyknięcie konstruktora kończy się niepowodzeniem, gdy między fasolkami wiosennymi występuje zależność kołowa. Więc w tym przypadku my Setter wtrysk pomaga rozwiązać problem.
Zasadniczo iniekcja konstruktora jest przydatna w przypadku zależności obowiązkowych, w przypadku zależności opcjonalnych lepiej jest używać iniekcji settera, ponieważ możemy wykonać ponowne wstrzyknięcie.
źródło
Jeśli dwie fasole są od siebie zależne, nie powinniśmy używać wtrysku konstruktora w obu definicjach fasoli. Zamiast tego musimy użyć zastrzyku ustawiającego w dowolnej fasoli. (oczywiście możemy użyć iniekcji setter w obu definicjach bean, ale iniekcje konstruktora w obu rzutach 'BeanCurrentlyInCreationException'
Zapoznaj się z dokumentem Spring pod adresem „ https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#resources-resource ”
źródło