2012-07-18 10 views
15

Mam wykres fasoli wiosennej, który się nawzajem się nawzajem. Mocno uproszczony rysunek:Wiosna tworząc wiele wystąpień singletona?

<context:annotation-config/> 
<bean class="Foo"/> 
<bean class="Bar"/> 
<bean class="Baz"/> 

... 

public class Foo { 
    @Autowired Bar bar; 
    @Autowired Baz baz; 
} 

public class Bar { 
    @Autowired Foo foo; 
} 

public class Baz { 
    @Autowired Foo foo; 
} 

wszystkich tych ziaren nie mają zakres określony które implikują one singletons (czyniąc je wyraźnymi singletons niczego nie zmienia, próbowałem).

Problemem jest to, że po chwili tworzenia kontekstu pojedynczej aplikacji instancje Bar i Baz zawierać różne wystąpienia Foo. Jak to mogło się stać?

Próbowałem utworzyć publiczny konstruktor bez args dla Foo, a debugowanie potwierdziło, że Foo jest tworzony więcej niż jeden raz. Ślad stosu dla wszystkich tych kreacji to here.

Próbowałem również włączyć rejestrowanie debugowania na wiosnę, a wśród wszystkich innych linii, mam następujące:

DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo' 
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo' 
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo' 

Rozumiem, że moje ziarna są odsyłaczy siebie, ale spodziewałbym Spring Framework aby uszanować zasięg singletonu i zainicjować pojedynczą fasolę raz, a następnie powierzyć ją każdemu, kto chce.

Ciekawostką jest fakt, że jeśli korzystam ze starego szkolnego konstruktora private z akcesorium public static Foo getInstance, działa to dobrze - żadne wyjątki nie są generowane podczas konfiguracji kontekstu.

FWIW, używam wersji Spring 3.0.5 (również wypróbowany z 3.1.2, te same wyniki) z konstruktorem o.s.c.s.ClassPathXmlApplicationContext(String ...configLocations).

Mogę łatwo przekonwertować mój kod, aby użyć statycznego inicjalizatora, ale chcę zrozumieć, dlaczego Spring zachowa się w ten sposób. Czy to błąd?

EDIT: Niektóre dodatkowe dochodzenie wykazało, że

  • Po kontekst aplikacji jest inicjowany, wszystkie kolejne wnioski do context.getBean(Foo.class)zawsze powrócić tą samą instancję Foo.
  • Zastąpienie @Autowired za pomocą setterów (około 20 zastosowań tego fasoli) wciąż powoduje powstanie wielu konstrukcji tego obiektu, ale wszystkie zależności są wstrzykiwane pod tym samym numerem .

Powyższe sugeruje, że jest to wiosenny błąd związany z implementacją @Autowired. Zamierzam publikować na wiosennych forach społecznościowych i zamieszczać je tutaj, jeśli uda mi się uzyskać cokolwiek pożytecznego.

+0

Może to być oczywiste, ale czy w grze jest tylko 1 JVM? Okrężne zależności? –

+0

Tak, jest to tylko jedna maszyna JVM. Okrężne zależności - tak, ale uważam, że wyjaśniłem to w moim poście. – mindas

+0

Widzę, ale co się dzieje, jeśli masz na przykład wstrzyknięcie konstruktora? Jak Spring ma rozwiązać ten problem? –

Odpowiedz

11

Konteksty dziecka mogą przywracać te same pojedyncze fasolki, jeśli nie jesteś ostrożny z kontekstem: adnotacje skanowania składników (tam są inne adnotacje w kontekście kontekstowym, takie jak MVC i inne). Jest to powszechny problem podczas używania serwletów Spring w aplikacjach internetowych, zobacz Why DispatcherServlet creates another application context?

Upewnij się, że nie skanujesz ponownie komponentów w kontekście podrzędnym lub skanujesz tylko określone pakiety/adnotacje i wykluczasz wspomniane pakiety/adnotacje z katalogu głównego skanowanie składnika kontekstowego.

+0

czy te singletony będą ładować ten sam program ładujący klasy? – gstackoverflow

+0

Czy możesz podać minimalny przykład gdzie wiosenny singleton zostanie załadowany? – gstackoverflow

0

Spróbuj użyć zastrzyku ustawiającego zamiast sposobu konstruktora i zobacz, czy działa. W xml fasoli sprężynowej określ pozycję Fasola A odn. Fasoli B i odwrotnie.

+0

Zaktualizowałem mój post. Wystarczy powtórzyć - wiem, jak rozwiązać problem, ale co ważniejsze, staram się zrozumieć ** dlaczego ** tak się dzieje. – mindas

0

Moja konfiguracja Wiosna była jak następuje:

<context:annotation-config/> 

<bean class="Bar" /> 
<bean class="Foo" /> 
<bean class="Baz" /> 

Klasy są identyczne Twoi

aplikacja testowa jak następuje:

import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 

public class SpringTest { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/spring/testctx.xml"); 

     Foo foo = ctx.getBean(Foo.class); 
     Baz baz = ctx.getBean(Baz.class); 
     Bar bar = ctx.getBean(Bar.class); 

     System.out.println(foo.equals(baz.foo)); 
     System.out.println(foo.equals(bar.foo)); 
     System.out.println(baz.equals(foo.baz)); 

     System.out.println(foo.baz.toString()); 
     System.out.println(baz.toString()); 
     System.out.println(foo.bar.toString()); 
     System.out.println(bar.toString()); 

    } 

} 

Wyjście z aplikacji testowej jak następuje:

true 
true 
true 
[email protected] 
[email protected] 
[email protected] 
[email protected] 

Korzystanie z wersji 3.0.6 działa idealnie dobrze (pojedyncza fasola jest w istocie singletonami). Może być coś, czego tutaj nie zilustrowałeś, psując konfigurację. Oczywiście, jak na marginesie, użycie domyślnego pakietu może spowodować pewną tajemniczą magię ;-)

+0

Dzięki za wkładanie w to wysiłku. W moim przypadku był to znacznie bardziej złożony wykres obiektów, ich setki. Z oczywistych powodów nie mogłem opublikować ich wszystkich, wystarczy wyciąć minimalny scenariusz, aby zilustrować ten punkt. – mindas

+0

@mindas Czy próbowałeś zmienić kolejność definicji fasoli w pliku? Spróbuj umieścić Foo na drugim lub ostatnim miejscu. – partlov

1

Z jakiegoś powodu otrzymujemy to pojawianie się losowo w testach integracyjnych i usługach (wersja wiosna 4.1.4, java 1.8).

Wygląda na to, że może być więcej niż jeden winowajca - Wydaje się, że Autowiring powodował to na początku.

Rozwiązaliśmy jednak najbardziej spójne błędy, upewniając się, że nadaliśmy każdemu wpływowemu komponentowi bean pole "id".

Powiązane problemy