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
String
s 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 List
s, Set
s, Map
s und Property
s:
<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
Set
s und Property
s 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
Anhand der Grafik lässt sich der Lebenszyklus einer Bean mit Standard-Konstruktor und Setter-Methoden beschreiben: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
Ob eine Bean alssingleton
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.