Spring IoC Container: Bean Definitionen "überschreiben"?

DarthShader

Erfahrenes Mitglied
Hallo zusammen,

ich habe hier ein Projekt mir vielen Bean Definitionen in einer Spring XML Konfiguration. Nun bin ich in einer Situation, in der ich einige bestimmte Konfigurationen temporär austauschen muss. Im Prinzip geht es nur um einige Properties einiger Beans, die andere Werte bekommen müssen.

Was ich nun sehr gerne machen würde ist, eine Bean Defintion in einer anderen Spring XML Konfiguration zu "überschreiben", sodass ich z.B. nur eine der zuvor gesetzten Properties neu setze.

Also Beispiel mal diese Bean:

XML:
<bean id="ersteBean" class="de.test.Person">
   <property name="vorname" value="Nelson">
   <property name="nachname" value="Mandela">
   <property name="wichtig" value="false">
</bean>

Nun möchte ich durch nur eine neue Konfigurations-Datei das Property "wichtig" von "false" auf "true" setzen, etwa so:

XML:
<!-- "ersteBean" wird überschrieben, alle Properties ausser "wichtig" bleiben erhalten -->
<bean id="ersteBean">
   <property name="wichtig" value="true">
</bean>

Das ist natürlich ein sehr konstruiertes Beispiel. In einer meiner XML Dateien habe ich natürlich eine große Menge an Beans. Ich hoffe jedoch, mein Anliegen wird dadurch deutlich.


Vielen Dank für Eure Hilfe!
 
Zuletzt bearbeitet von einem Moderator:
Weiß nicht ob das noch aktuell ist aber ich antworte trotzdem mal.

Für solche Zwecke gibt es das abstract bzw. parent property. Dein Beispiel würde dann so aussehen:

Die abstrakte Bean die die Einstellungen und Klasse definiert.
Code:
<bean id="ersteBean" class="de.test.Person" abstract="true">
 <property name="vorname" value="Nelson">
 <property name="nachname" value="Mandela">
 <property name="wichtig" value="false">
</bean>

abstract=true bedeutet dass diese konkrete Bean ersteBean nicht von Spring erzeugt werden kann selbst wenn du sie explizit über die ID anforderst.


Eine deiner konkreten Beans die die Einstellungen übernimmt und wahlweise einige davon überschreiben kann
Code:
<bean id="zweiteBean" parent="ersteBean">
 <property name="wichtig" value="true">
</bean>
 
Zuletzt bearbeitet:
Hallo,

vielen Dank für Deine Antwort. Ja, das Thema ist noch aktuell (für mich).

Das Konzept der abstrakten Bean kenne ich. Und Du hast Recht, darüber kann ich das theoretisch machen. In der Praxis habe ich aber eine ziemlich große Context Konfiguration, verteilt über mehrere XML Dateien.

Wenn ich nun im Prinzip beliebige Bean Definitionen "überschreiben" will, so müsste ich _alle_ Bean Definitionen, die ich habe, als abstrakt markieren. Das kann's ja irgendwie nicht sein.

Der Zweck ist eben, dass die gesamte Konfiguration so OK ist - aber wenn ich mal beim Kunden bin bzw. an dem Ort, wo die Applikation deployed wurde, hätte ich eben gerne die Möglichkeit, mal kurz durch Verändern der XML Dateien einige BEans zu verändern, die Injektion kurz auszusetzen oder irgendeine Debugger Bean einzusetzen, anstatt der richtigen etc... aber ich kann noch nicht voraussagen, welche Beans und Properties das sein werden.

Gibts da vielleicht nen ähnlichen Mechanismus für? Falls nicht, sehr schade, dann muss ich mir irgendwas anderes einfallen lassen.
 
Also das mit dem Management von Konfigurationsdateien ist so eine Sache. Ich halte folgendes Vorgehen für recht sinnvoll:

1. Aufteilen der Konfiguration nach fachlichen und technischen Gesichtspunkten.
2. Extrahieren von Umgebungsspezifischen Konfigurationswerten (DB Urls usw.) in Propertiesfiles und Benutzung des PropertyPlaceholderConfigurer
3. In den Konfigurationsfiles in src/main/resources hinterlege ich dann auch die Produktivkonfiguration. Hiermit ist z.B. die Deklaration eines JNDI Lookups per <j2ee:jndi-lookup /> in eine fiktiven Datei foo-context.xml gemeint.
4. Pro Komponente (die sich meist über zwei Eclipseprojekte erstreckt) gibt es ein zentrales Konfigurationsfile component-context.xml, dass alle anderen relevanten der Komponente (z.B. foo-context.xml) inkludiert. So genügt es in einem Client der Komponente dieses File zu inkludieren

In Testcases ist es nun allerdings kein JNDI vorhanden, es kann sein, dass die Komponente andere Komponente required usw. Hier habe ich dann in src/test/resources für die jeweiligen Teilkonfigurationsfiles Dateien, die beispielsweise foo-context-dev.xml heißen. Hier wird dann die Bean die den JNDI lookup macht durch eine ersetzt, die evtl. eine lokale Datasource nutzt.

Für andere Requiredkomponenten kann man so auch prima mit EasyMock Mockinstanzen von kollaborierenden Komponenten deklarieren.

Mal eben so eine einzelne Bean umzukonfigurieren halte ich für kritisch, das Austauschen einer Bean ist hingegen einfacher. D.h. angenommen es gibt eine Deklaration

XML:
<bean id="foo">
  <property name="foo" ref="bar" />
</bean>

<bean id="bar" />
würde ich nicht hergehen und foo umkonfigurieren wollen und eine andere Bean referenzieren, sondern einfach in einem weiteren File die Bean bar überschreiben und das für den ApplicationContext deiner Wahl mit laden.

Gruß
Ollie
 
Zuletzt bearbeitet von einem Moderator:
Hallo Oliver,

vielen Dank für Deine ausführliche Antwort. Ich habe einen ähnliches Mechanismus, nur habe ich das Gefühl, dass ich noch nicht korrekt zwischen technischen und fachlichen Klassen trenne. Allerdings ist das natürlich ein anderes Thema...



Mal eben so eine einzelne Bean umzukonfigurieren halte ich für kritisch, das Austauschen einer Bean ist hingegen einfacher. D.h. angenommen es gibt eine Deklaration

XML:
<bean id="foo">
  <property name="foo" ref="bar" />
</bean>

<bean id="bar" />
würde ich nicht hergehen und foo umkonfigurieren wollen und eine andere Bean referenzieren, sondern einfach in einem weiteren File die Bean bar überschreiben und das für den ApplicationContext deiner Wahl mit laden.

Das ist der Punkt, Du sagst "sondern einfach in einem weiteren File die Bean bar überschreiben" - wie genau definierst Du hier "überschreiben"? Handelst Du das über includes, oder kann Spring tatsächlich eine zuvor schon gelesene Bean mit einer weiteren Bean Definition überschreiben? Denn das ist ja mein Problem, ich will eine Bean überschreiben, die aber schon von Spring "gelesen" wurde.
 
Zuletzt bearbeitet von einem Moderator:
Angenommen du hast das von dir zitierte KOnfigurationsfile in foo.xml. Dann gibt es z.B. in src/test/resources ein foo-test.xml in dem steht folgendes:

XML:
<!-- Andere implementierung, KOnfiguration, whatever - hauptsache, die ID ist gleich -->
<bean id="bar" />
Deine zentrale applicationContext.xml importiert dann z.B. einfach nur das foo.xml. Ein Testcase könnte hingegen so aussehen:

Java:
@RunWith(SpringJUnit4Runner.class)
@ContextConfiguration(locations = {"applicationContext.xml", "foo-test.xml"})
public class Whatevertest {

}

Damit lädst du die normale Anwendungskonfiguration PLUS beliebig viele weitere Files, die evtl. Beans überschreiben und die Konfiguration so "testgerecht" machen.

Gruß
Ollie
 
Zuletzt bearbeitet von einem Moderator:

Neue Beiträge

Zurück