Für alle, die den Einheiten-Dschungel nicht mehr durchblicken:
Zum Auftakt gibt es direkt ein Schmankerl: Der Begriff Dependency Injection (in diesem Fall genauer: Contexts and Dependency Injection for the Java EE platform, kurz CDI) geistert ja ununterbrochen durch die Medien, und so manch einer wird auch wissen, worum es sich dabei handelt. DI ist kurz gesagt ein Design Pattern, dass behaviour von dependency resolution trennt und somit eine Menge sogenannten glue code (Instanzierung mit new, Schreiben von Factories, Lookup über JNDI usw.) einspart. Da dies ja auch ein generelles Ziel des Spring Frameworks ist, liegt es nahe, diese beiden Ansätze zu verbinden.
Tatsächlich hatte Spring ein ähnliches Feature bereits in sein Framework integriert, änderte diesen aber ab Version 3 und unterstützte fortan den vom Java Community Process erarbeiteten Standard JSR 330. Auch Google bietet mit Guice ein kompatibles Framework an. Der Vorteil von JSR-330 ist im Gegensatz zu dem ehemaligen WebBeans-Standard (JSR 299) übrigens die Möglichkeit, DI ohne JEE-Profil in ganz normalen Java SE-Anwendungen zu nutzen.
Nun sollte ich langsam zum wichtigen Teil kommen: Was viele eben wohl nicht wissen, ist, wie einfach sich die ganze Sache in Java-Projekte mit Spring integrieren lässt. Hier geht es nämlich ein bisschen weg von den umfangreichen XML-Konfigurationen, wegen denen Spring so bekannt und gefürchtet ist und hin zu Annotationen, die – wo es sinnvoll ist – einiges an Schreibarbeit abnehmen können.
Mein Beispiel ist ein simples Web-Projekt mit Spring 3.0 und JSF 2.0, welches erfolgreich und kurz die Verheiratung zweier Technologien zeigt.
Es existieren zwei Interfaces, deren Implementierungen jeweils ein Service und eine Bean sind. Der Service ist einfach nur ein POJO, die Bean ist eine ManagedBean mit RequestScope, welche den String des Service bereitstellt und später vom JSF in eine HTML-Seite gerendert wird. Der interessante Teil sind die Annotationen…
1 2 3 4 5 6 | @Named("exampleService") public class ExampleService implements IExampleService { public String getHelloWorld() { return "Hello World!"; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Named("exampleBean") @Scope("request") public class ExampleBean implements IExampleBean { @Inject @Named("exampleService") private IExampleService exampleService; public void setExampleService(IExampleService exampleService) { this.exampleService = exampleService; } public String getOutput() { return exampleService.getHelloWorld(); } } |
@Named kann sowohl eine Klasse mit einem Namen ausweisen als auch ohne Parameter benutzt werden. @Named wird auch immer benötigt, wenn man eine Klasse injecten möchte (in Kombination mit @Inject). Ganz so magisch ist das ganze doch nicht, deshalb funktioniert die DI natürlich nur mit einem Setter zusammen (siehe ExampleBean).
Es fehlen noch die paar Zeilen XML (siehe applicationContext.xml), welche Spring dazu nötigen, das genannte Package zu scannen und die entsprechenden Klassen zu instanzieren:
<beans> <context:component-scan base-package="com.example" /> </beans>
JSF benötigt (siehe faces-config.xml) außerdem noch die Anweisung, nicht den eigenen EL-Resolver zu nutzen, sondern den von Spring bereitgestellten:
<application> <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver> </application>
Das Projekt könnt ihr euch hier runterladen und entweder in euer Eclipse importieren oder per Maven mit “mvn jetty:run” starten. Unter http://localhost:8080 ist dann das Beispiel verfügbar.