BeanFactory und den ApplicationContext, in einem Webumfeld
übernimmt dies ein von Spring zur Verfügung gestelltes DispatcherServlet. Die BeanFactory ist
dabei die schmalere Implementierung und stellt nur den Container zur Verfügung, während im ApplicationContext
weitere Features wie Aspektorientierte Programmierung möglich werden. Der Dispatcher für das Webumfeld ähnelt dabei dem
ApplicationContext. Allgemein sollte solange wie möglich die BeanFactory genutzt werden und erst
wenn diese nicht mehr ausreicht auf den ApplicationContext zurückgegriffen werden. In der Spring-Terminolgie
heißen die von einem Spring-Container verwalteten Objekte Beans.
<:?xml version="1.0" encoding="UFT-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> ... </beans>Die Konfiguration der einzelnen Beans erfolgt in dem
beans-Tag.<bean id="dataSource" class="...ClientDataSource"> <property name="serverName" value="localhost"> <property name="portNumber" value="1527"> </bean>Hierdurch wird eine Bean von der Klasse
ClientDataSource per Defaultkonstruktor erzeugt und danach die Methoden
setServerName und SetPortNumber ausgeführt. Den Datentyp in den der value-Wert
gewandelt werden muss erkennt Spring dabei am Typ der Felder.<bean id="kundeDAO" class="KundeDAO"> <property name="dataSource" ref="dataSource"> </bean>In diesem Fall würde die
dataSource wie oben beschrieben erzeugt werden und der Bean kundeDAO per
setDataSource zugewiesen. Die Typ-Überprüfung passiert hierbei erst bei der Erzeugung des Containers, also zur
Lauf- und nicht zur Kompilierzeit.
<bean id="kundeDAO" class="KundeDAO">
<property name="dataSource">
<bean class="...ClientDataSource">
<property name="serverName" value="localhost">
<property name="portNumber" value="1527">
</bean>
</property>
</bean>
Da die innere Bean dabei keinen Namen bekommt, kann sie von keiner anderen Bean referenziert werden und ihr Lebenszyklus
entspricht dem der äußeren Bean.<bean id="dataSource" class="...ClientDataSource"> <constructor-arg value="localhost"> <constructor-arg value="1527"> </bean> <bean id="kundeDAO" class="KundeDAO"> <constructor-arg ref="dataSource"> </bean>Spring untersucht in diesem Fall die Parameter des Konstruktors und probiert die gegebenen Werte umzusetzen. In diesem Fall würde
"localhost" als String, "1527" als int und dataSource
als ClientDataSource an die Konstruktoren übergegeben werden. Dies passiert ebenfalls zur Laufzeit. Auch bei
Konstruktoren ist es möglich Beans die vom Konstruktor referenziert werden inline anzugeben.value aber in beiden Fällen Zahlen angegeben werden. Spring ist dadurch nicht mehr in der Lage zu
erkennen welcher Wert an welche Stelle des Konstruktors gehört. Um dies beheben zu können gibt es zwei Möglichkeiten.<bean id="dataSource" class="...ClientDataSource"> <constructor-arg type="String" value="localhost"> <constructor-arg type="int" value="1527"> </bean>Hier werden die Typen der Werte mit angegeben und Spring weiss so in welchen Typ er die Argumente umwandeln soll. Diese Lösung funktioniert allerdings nur, wenn ein Konstruktor jeden Typ nur einmal erwartet. Erwartet der Konstruktor zwei
Strings bietet Spring als zweite Möglichkeit folgende Lösung:
<bean id="dataSource" class="...ClientDataSource"> <constructor-arg index="0" value="localhost"> <constructor-arg index="1" value="1527"> </bean>Hier werden Spring die Positionen angegeben, an denen es die Werte dem Konstruktor übergeben soll. Hier ist darauf zu achten, dass das erste Argument den Index 0 hat. Spring versucht dann bei der Erzeugung der Bean zur Laufzeit den ersten Wert auf den vom Konstruktor als erstes Argument erwarteten Typ zu wandeln.
<bean id="exampleBean" class="ExampleBean2" factory-method="createInstance"/>In diesem Fall wird Spring in der Klasse
ExampleBean2 die Methode createInstance aufrufen und das
zurückgegebene Objekt als Bean exampleBean behandeln.<bean id="myFactoryBean" class="MyFactory"/> <bean id="exampleBean" factory-bean="myFactoryBean" factory-method="createInstance"/>Spring erstellt hier zuerst die Bean
myFactoryBean von der Klasse MyFactory und wird danach auf der
Bean myFactoryBean die Methode createInstance aufrufen. Das zurückgegebene Objekt dieses Aufrufes
wird dann als Bean exampleBean gespeichert.<constructor-arg ...>
gesetzt werden.
Collections als Parameter für setter-Methoden, Konstruktoren oder Factories zu übergeben.
Möglich sind dabei Lists, Sets, Maps und Propertys:
<bean id="myList" class="MyList">
<property name="list">
<list>
<value>Erster Listeneintrag</value>
<value>Zweiter Listeneintrag</value>
</list>
</property>
</bean>
<bean id="myMap" class="MyMap">
<constructor-arg>
<map>
<entry key="1" value="Hallo"/>
<entry key="2" value="Welt"/>
</map>
</constructor-arg>
</bean>
Für Sets und Propertys sind die Tags entsprechend <set> und <props>
<bean id="kundeDAO" class="KundeDAO" autowire="byName"/>
Das Attribut autowire kann dabei fünf verschiedene Werte annehmen:
| no | kein Autowiring (Default) |
|---|---|
| byName | Bean mit dem gleichen Namen wie das Feld im Objekt wird gesucht. Gibt es keine Bean mit diesem Namen bleibt dass Feld unbelegt. |
| byType | Bean mit dem gleichem Typ wie das Feld im Objekt wird gesucht und entsprechende Setter-Methode ausgeführt. Ist keine Bean dieses Typs vorhanden wird das Feld nicht gesetzt, sind mehrere Beans dieses Typs vorhanden wird zur Laufzeit ein Fehler ausgegeben. |
| constructor | Wie byType, allerdings wird hier in den Parametern des Konstuktor gesucht. Wenn kein passender Typ gefunden wird probiert Spring einen anderen Konstruktor auszuführen, wenn dieser nicht vorhanden ist oder mehrere Beans des gesuchten Typs vorhanden sind erfolgt zur Laufzeit eine Fehlerausgabe. |
| autodetect | Mischung aus byType und constructor. Spring versucht zuerst den Default-Konstruktor aufzurufen und die Felder mit Setter-Methoden zu füllen. Ist dies nicht möglich, da kein Default-Konstruktor zur Verfügung steht, wird versucht die Argumente des Konstruktors mit den wenigsten Argumenten zu finden und eventuell übrige Felder per Setter zu setzen. |
init- und destroy-Methoden festzulegen.
<bean id="kundeDAO" class="KundeDAO" init-method="init" destroy-method="cleanup"/>
Die zugehörige Klasse würde wie folgt aussehen:
public class KundeDAO {
public void init() {..}
public void destroy() {..}
}
Beide Attribute sind optional und auch einzeln einsetzbar. Die init- und destroy-Methoden werden
dann von Spring an den Stellen 6 (init) bzw. 9 (destroy) der folgenden Grafik ausgeführt.
Lebenszyklus einer Bean
InitializingBean implementiert wird die Methode afterPropertiesSet
ausgeführt. Dies war bis Version 2.0 die Vorgehensweise um Beans zu initialisieren. Allerdings sind die Beans dadurch von dem
Interfacce abhängig. Um die Beans unabhängig von Spring zu halten, sollte daher das init-method-Attribut verwendet werden.init-method-Attribut definierte Methode wird aufgerufen.DisposableBean implementiert wird die Methode destroy aufgerufen.
Dies ist wie bei 5. für die Versionen von 2.0 vorgesehen und sollte aus den gleichen Gründen mit Version 2.0 nicht mehr
benutzt werden.destroy-method-Attribut definierte Methode wird aufgerufen. Danach gilt die Bean als Destroyed.singleton. Das Vorgehen bei singleton-Beans ist in der folgenden Grafik gut zu
erkennen:

singelton-Bean
prototype und lässt sich in der folgenden Grafik erkennen:
Prototype-Bean
singleton oder prototype behandelt werden soll gibt das Attribut scope
des bean-Tags an. Hier gibt es folgende Werte:
singleton |
Bean wird nur einmal erzeugt und bei jeder Referenz die gleiche Bean verwendet. (Default) |
|---|---|
prototype |
Bei jeder Referenz wird eine neue Instanz der Bean erzeugt und verwendet. |
request |
Wird nur im Web-Kontext benötigt. Für jeden Request wird eine neue Instanz erzeugt. |
session |
Wird nur im Web-Kontext benötigt. Für jede Session wird eine neue Instanz erzeugt. |
globalSession |
Wird nur für portlet-based Webanwendungen benötigt. Für jede Global Portlet Session wird eine Bean erzeugt. |
scope-Attribut noch nicht. Bei der Verwendung von früheren Versionen muss das
Attribut singleton verwendet werden dass entweder true für eine singleton-Bean
(Default) oder false für eine prototype-Bean sein kann.
BeanFactory oder einen
ApplicationContext erzeugen:
public void main(Object[] args) {
Ressource resource = new FileSystemRessource("beans.xml");
BeanFactory factory = new XmlBeanFactory(ressource);
Object o = factory.getBean("myBean");
}
bzw.
public void main(Object[] args) {
ApplicationContext context = new FileSystemXmlApplicationContexxt("beans.xml");
Object o = context.getBean("myBean");
}
Der Zugriff auf den Container sollte dabei nur einmal erfolgen, da die Bean myBean einen Einstiegspunkt
darstellen und alle weiteren Beans als Abhängigkeiten dieser Bean erreichbar sein sollten. Der Container stellt nur wenige
Methoden zur Verfügung. Das Ergebnis eines getBean ist immer ein Objekt und muss zur korrekten Verwendung
gecastet werden. Die Verwendung in einem Web-Context folgt im übernächsten Kapitel.