Mit der Java-Konfiguration von Spring muss ich eine Bean mit Prototypbereich mit Konstruktorargumenten erwerben / instanziieren, die nur zur Laufzeit verfügbar sind. Betrachten Sie das folgende Codebeispiel (der Kürze halber vereinfacht):
@Autowired
private ApplicationContext appCtx;
public void onRequest(Request request) {
//request is already validated
String name = request.getParameter("name");
Thing thing = appCtx.getBean(Thing.class, name);
//System.out.println(thing.getName()); //prints name
}
wobei die Thing-Klasse wie folgt definiert ist:
public class Thing {
private final String name;
@Autowired
private SomeComponent someComponent;
@Autowired
private AnotherComponent anotherComponent;
public Thing(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
Hinweis name
ist final
: Es kann nur über einen Konstruktor geliefert werden und garantiert Unveränderlichkeit. Die anderen Abhängigkeiten sind implementierungsspezifische Abhängigkeiten der Thing
Klasse und sollten nicht bekannt (eng mit der Implementierung des Anforderungshandlers gekoppelt) sein.
Dieser Code funktioniert perfekt mit der Spring XML-Konfiguration, zum Beispiel:
<bean id="thing", class="com.whatever.Thing" scope="prototype">
<!-- other post-instantiation properties omitted -->
</bean>
Wie erreiche ich dasselbe mit der Java-Konfiguration? Folgendes funktioniert mit Spring 3.x nicht:
@Bean
@Scope("prototype")
public Thing thing(String name) {
return new Thing(name);
}
Jetzt könnte ich eine Fabrik erstellen, zB:
public interface ThingFactory {
public Thing createThing(String name);
}
Dies macht jedoch die Verwendung von Spring zum Ersetzen des ServiceLocator- und Factory-Entwurfsmusters zunichte , was für diesen Anwendungsfall ideal wäre.
Wenn Spring Java Config dies könnte, könnte ich Folgendes vermeiden:
- Definieren einer Factory-Schnittstelle
- Definieren einer Factory-Implementierung
- Schreiben von Tests für die Factory-Implementierung
Das ist eine Menge Arbeit (relativ gesehen) für etwas so Triviales, dass Spring es bereits über die XML-Konfiguration unterstützt.
Thing
Implementierung ist tatsächlich komplexer und hat Abhängigkeiten von anderen Beans (ich habe sie der Kürze halber einfach weggelassen). Daher möchte ich nicht, dass die Implementierung des Anforderungshandlers davon erfährt, da dies den Handler eng mit APIs / Beans koppeln würde, die er nicht benötigt. Ich werde die Frage aktualisieren, um Ihre (ausgezeichnete) Frage widerzuspiegeln.
@Qualifier
einem Setter mit @Autowired
dem Setter selbst Parameter zuweisen können.
@Bean
funktioniert Ihr Beispiel mit . Die @Bean
Methode wird mit den entsprechenden Argumenten aufgerufen, an die Sie übergeben haben getBean(..)
.