11

Surfen im Frühling JavaConfig Referenzdokumentation http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html ich einige verwirrende Teile gefunden ...Frühling JavaConfig inter-Bohne Abhängigkeiten

Unter Abschnitt "5.12.4 Verwendung der @Configuration Anmerkung" heißt es:

„Wenn @Beans Abhängigkeiten voneinander, wird diese Abhängigkeit exprimieren einen anderen so einfach wie mit einem bean Methode aufrufen:

@Configuration 
public class AppConfig { 
    @Bean 
    public Foo foo() { 
     return new Foo(bar()); 
    } 
    @Bean 
    public Bar bar() { 
     return new Bar(); 
    } 
} 

Im obigen Beispiel erhält die Foo-Bean einen Verweis auf Balken über die Konstruktorinjektion. "

Nun, wenn alles staatenlos ist, könnte es nicht viel, aber wenn man die Config oben haben, und dann in der Anwendung tun:

@Autowired 
private Foo foo; 

@Autowired 
private Bar bar; 

die Hashcodes der Bohnen Überprüfung stellt sich heraus, , dass Ihr private Variable bar zu einer anderen Instanz von Bar als die von foo verwendet beziehen, was wahrscheinlich ist, nicht, was Sie erwarten, nicht wahr?

Ich würde sagen, das normale Muster eher sein sollte:

@Configuration 
public class AppConfig { 
    @Bean 
    public Bar bar() { 
     return new Bar(); 
    } 
    @Autowired Bar bar; 
    @Bean 
    public Foo foo() { 
     return new Foo(bar); 
    } 
} 

Wenn Sie nun beide Bohnen in Ihrer App autowire, werden Sie nur eine einzelne Instanz Bar erstellen.

Fehle ich etwas, oder bin ich richtig, dass die Dokumentation hier flockig ist?

Dann weiter unten, unter Abschnitt „Weitere Informationen darüber, wie Java-basierte Konfiguration arbeiten intern“ es, wie sie dieses Problem versuchen zu „klären“ aussieht:

@Configuration 
public class AppConfig { 
    @Bean 
    public ClientService clientService1() { 
     ClientServiceImpl clientService = new ClientServiceImpl(); 
     clientService.setClientDao(clientDao()); 
     return clientService; 
    } 
    @Bean 
    public ClientService clientService2() { 
     ClientServiceImpl clientService = new ClientServiceImpl(); 
     clientService.setClientDao(clientDao()); 
     return clientService; 
    } 
    @Bean 
    public ClientDao clientDao() { 
     return new ClientDaoImpl(); 
    } 
} 

Jetzt, Leider wird diese Konfiguration nicht einmal zur Laufzeit geladen, weil es zwei Beans vom selben Typ, ClientService, gibt, die keine unterscheidbaren Eigenschaften haben, also erhalten Sie die Ausnahme

org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
No qualifying bean of type [.....] is defined: 
expected single matching bean but found 2 

Aber selbst wenn wir das Beispiel etwas zu ändern, und den ersten 2 Bohnen verschiedene Arten geben,

@Bean 
public ClientService1 clientService1() {...clientDao()...} 
@Bean 
public ClientService2 clientService2() {...clientDao()...} 
@Bean 
public ClientDao clientDao() { 
    return new ClientDaoImpl(); 
} 

dies immer noch nicht korrekt ist, da - im Gegensatz zu dem, was dem Text Ansprüche - wir würden noch 3 schaffen unterschiedliche Instanzen von ClientDaoImpl, beim Autowiren aller 3 Beans.

Noch einmal, ich vermisse etwas völlig, oder ist die Dokumentation wirklich so schlecht, wie es mir scheint?

EDIT: Added eine Demo, die das Problem zeigen, werde ich sehen:

https://github.com/rop49/demo

bohnen ServiceA, und zwei Bohnen ServiceB1, ServiceB2 dass Konstruktordeklaration einspritzt ServiceA.

Dann zwei Testklassen Config01Test und Config02Test, die mit Ausnahme der Konfigurationen identisch sind. Der erste Test PASSIERT, der zweite versagt wegen Eindeutigkeit.

+3

Warum denken Sie haben Sie verschiedene 'Bar' Objekte zu bekommen? – chrylis

+0

Ich habe einen kleinen Test gemacht und die hashCodes in den Beans überprüft. Sie sind anders. Ich habe das in der obigen Frage geklärt, danke. – Rop

+0

Kannst du ein einfaches laufendes Beispiel auf GitHub veröffentlichen, möglicherweise mit Spring Boot? Ich habe dieses Verhalten noch nie gesehen, und es ist ein Fehler, wenn es wirklich passiert. – chrylis

Antwort

8

Überprüfen Sie, ob in Ihrer Konfigurationsklasse @Configuration Anmerkungen vorhanden sind. Mit Ihrer Demo fehlen zumindest die Klassen Config01 und Config02. Wenn ich sie diesen Klassen hinzufüge, werden die Tests bestanden.

+0

Aah, toll das habe ich aussortiert :) Danke Phil! – Rop

+0

Als eine Nebenbemerkung ... wäre es sinnvoll, Spring @SpringApplicationConfiguration von Klassen, die nicht die Annotation \ @Configuration haben, abzulehnen? Oder wäre es jemals ein gültiger Anwendungsfall, um dies zuzulassen? – Rop

+1

Leider würde es die Rückwärtskompatibilität brechen. Siehe den Abschnitt lite-beans hier: http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/htmlsingle/#beans-java-basic-concepts –

0

ich nicht das Beispiel selbst testen haben, Dies sollte sicherstellen, dass Sie nur eine Instanz der Bar in der gesamten Anwendungskontext

@Configuration 
public class AppConfig { 
    @Bean 
    public Foo foo(Bar bar) { 
     return new Foo(bar); 
    } 
    @Bean 
    public Bar bar() { 
     return new Bar(); 
    } 
} 
Verwandte Themen