Middels bestanden die er als volgt uitzagen, kon je met het toenmalige
com.interface21 framework aan de slag:
<bean name="clinton" class="com.interface21.domain.President">
<property name="firstName">Bill</property>
<property name="lastName">Clinton</property>
<property name="country" beanRef="usa"/>
</bean>
<bean name="usa" class="com.interface21.domain.Country">
<property name="name">United States of America</property>
</bean>
Fast forward naar 2007.
Er is sinds 2003 veel gebeurd in de Java wereld. Een van de
belangrijkste gebeurtenissen die de Dependency Injection (DI) wereld
beinvloed heeft is toch wel de ontwikkeling van annotaties.
Spring heeft altijd het gebruik van XML aangehangen voor het doen van
DI, hoewel dit door de abstract van de BeanFactory en de onderliggen
BeanDefinitionReaders niet een 1-op-1 koppeling is. De laatste tijd
ziet men met onder andere Guice en het al wat langer bestaande EJB3
dat DI middels annotaties ook grotere vluchten neemt. Wat ik in de
rest van dit postje wil doen is de verschillende manier van DI in
Spring aan het licht brengen en dan hopelijk een discussie op gang
brengen over het wel en wee van de verschillende methoden.
Wat goed onthouden dient te worden is het feit dat alle methoden van
DI met elkaar gecombineerd kunnen worden. Zo kan een met Spring
JavaConfig geconfigureerde bean gebruikt worden in XML en andersom en
zo kan een @Autowired component ook in XML verrijkt worden met
properties.
We nemen voor elk voorbeeld de volgende objecten die we willen
configureren:
class Service {
private Dao dao; // setters omitted
}
class Dao {
private DataSource dataSource; // setter omitted
}
class DataSource {
private String url, username, password, driverClass; // setters
omitted
}
1a. Dependency Injection met Spring XML (traditional)
Als eerste de welbekende manier van DI met Spring XML, een uitvloeisel
van het bovengenoemde voorbeeld:
<bean id="service" class="com.mycompany.Service">
<property name="dao" ref="dao"/>
</bean>
<bean id="dao" class="com.mycompany.Dao">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="com.mycompany.DataSource">
<property name="url" value="jdbc:oracle:thin:@dev001:1521:db01"/>
<property name="username" value="alef"/>
<property name="password" value="pass"/>
<property name="driverClass" value="oracle.jdbc.Driver"/>
</bean>
Uiteraard zou gebruik van bijvoorbeeld inner-beans het geheel een stuk
eenvoudiger kunnen maken.
1b. Dependency Injection met de Spring Magic P-namespace
Een feature die nog niet zoveel gebruik wordt is de P-namespace. Meer
hierover kun je lezen op het Interface21 blog (http://
blog.interface21.com/main/2006/11/25/xml-syntax-sugar-in-spring-20/).
De configuratie die je hierboven ziet kan met de P-namespace
versimpeld worden tot het volgende:
<bean id="service" class="com.mycopany.Service" p:dao-ref="dao"/>
<bean id="dao" class="com.mycompany.Dao" p:dataSource-ref="dataSource"/
>
<bean id="dataSource" class="com.mycompany.DataSource"
p:url="jdbc:oracle:thin:@dev001:1521:db01"
p:username="alef"
p:password="pass"
p:driverClass="oracle.jdbc.Driver"/>
Om de P-namespace te kunnen gebruiken moet je wel een extra schema
opnemen in je XML bestand. Meer hierover staat in de blog entry
hierboven.
2. Dependency Injection met Spring JavaConfig
Een van de nieuwe manier van het doen van DI in Spring is Spring
JavaConfig. Deze techniek heeft al lang in een prive sandbox gezeten,
maar heeft zoals wij altijd zeggen, 'een tijdje op de backburner
gestaan' om te rijpen. Spring JavaConfig is ook verder uitgewerkt op
het Interface21 blog (http://blog.interface21.com/main/2006/11/28/a-
java-configuration-option-for-spring/). Het idee is om in plaats van
XML bestanden als configuratie te gebruiken aparte Java classes te
maken die configuratie bevatten. Let op: we gaan in het onderstaande
voorbeeld dus niet de Dao, de Service en de DataSource zelf bewerken
om ze te configureren, we nemen alleen een aparte configuratie class
op:
@Configuration
public class MyConfig {
@Bean public Dao dao() {
Dao dao = new Dao();
dao.setDataSource(dataSource());
return dao;
}
@Bean public Service service() {
Service service = new Service();
service.setDao(dao);
return service;
}
@Bean public DataSource dataSource() {
DataSource ds = new DataSource();
ds.setUser("alef");
ds.setPassword("pass");
ds.setUrl("jdbc:oracle:thin:@dev001:1521:db01");
ds.setDriverClass("oracle.jdbc.Driver");
return ds;
}
}
Een variant hierop overigens is het configureren van de DataSource in
XML en de rest in Java. Vervang hiervoor de dataSource() method door
het volgende:
@ExternalBean public abstract DataSource dataSource();
3. Dependency Injection met @Autowire, @Component en JSR-250
annotations
De laatste manier, de we recentelijk in Spring 2.1 M1 geintroduceerd
hebben maakt ook gebruik van annotaties, maar dan op de classes die je
configureert. Deze manier is uitgebreider gedocumenteerd in de blog
entry door Mark Fisher (http://blog.interface21.com/main/2007/05/14/
annotation-driven-dependency-injection-in-spring-21/). Heronder vind
je het voorbeeld met @Autowired en @Component.
@Component
public class Dao {
@Autowired
private DataSource dataSource;
}
@Component
public class Service {
@Autowired
private Dao dao;
}
De DataSource class blijft hetzelfde en deze moet nog opgezet worden
in XML, aangezien hij String waarden geconfigureerd moet krijgen. Dit,
samen met een enkele configuratie directive die class path scanning
voor @Component componenten aanzet vind je in onderstaand stukje XML:
<context:component-scan base-package="blog"/>
<bean id="dataSource" class="com.mycompany.DataSource">
<property name="url" value="jdbc:oracle:thin:@dev001:1521:db01"/>
<property name="username" value="alef"/>
<property name="password" value="pass"/>
<property name="driverClass" value="oracle.jdbc.Driver"/>
</bean>
Goed, nu aan jullie de vraag? Wat vind je de mooiste manier en
waarom!!!
groetjes,
Alef
Ik denk dat ik niet zo'n voorstander ben van het verdelen van
configuratie over java-classes en xml-bestanden. Ik hou het liever bij
elkaar, dat maakt het wel zo overzichtelijk. Methode 3 valt dus af. De
voordelen van javaConfgig zie ik ook niet zo. Ok, je bent van de veel
bekritiseerde XML-brei af, maar naar mijn mening is de java
configuratie van hetzelfde laken een pak. Als je eenmaal aan de XML-
config gewend bent dan werkt dat prima. De p-namespace variant maakt
de XML-configuratie wat korter en dat is wel goed. Maar veel
leesbaarder wordt het er niet door. Bovenstaande is natuurlijk bekeken
door een bril die al tijden de 1a-variant gebruikt en daar eigenlijk
wel tevreden over is. Wat misschien nog wel interessant is is of de
tijd die Spring nodig heeft om een javaConfig configuratie in de lucht
te krijgen misschien significant korter (of langer...) is dan een
xmlConfig. Als je aan het ontwikkelen bent is een wat kortere
opstarttijd (soms) wel handig.
Groeten,
Maarten ten Ham