Home ORDIX AG             Dienstleistung             Trainingsshop    Kunden / Referenzen Aktuelles    Kontakt
Home  Pfeil  ORDIX News  Pfeil  2/2008  Pfeil  Java/J2EE/JEE
suche: 
Dieser Artikel richtet sich an Java-Entwickler und Architekten, die einen schnellen Einstieg in das Spring- Framework erhalten möchten.

Glossar

Dependency Injection (DI)
Auch bekannt als Hollywood-Prinzip (Don't call us, we call you). Objekte holen sich ihre Referenzen nicht selbst, sondern bekommen sie zugewiesen (injiziert).
IDE
Integrated Development Environment. Eine integrierte Entwicklungsumgebung ist ein Anwendungsprogramm zur Entwicklung von Software.


Von der Planung bis zur schlüsselfertigen Übergabe.

Spring - So flexibel wie Sie selbst


Wo andere Frameworks aufhören, da setzt Spring an. Spring bietet Unterstützung für fast alle Bereiche in der Java-Entwicklung. Dieser Artikel veranschaulicht, wie dies mit Hilfe der Dependency Injection erreicht werden kann. Anschließend stellen wir die Spring-IDE als Plugin für Eclipse vor.

Achtung Baustelle!

Haben Sie schon mal erfolgreich einen Hausbau hinter sich gebracht, oder einen größeren Umbau durchgeführt? Falls ja, werden Sie mir bestimmt zustimmen, dass eine solche Maßnahme kein Zuckerschlecken ist. Sie müssen sich von verschiedenen Handwerksbetrieben Angebote einholen, diese vergleichen und alles irgendwie koordinieren. Es gibt Tage, da tummeln sich auf so einer Bausstelle schon mal einige Handwerksbetriebe und Sie müssen sich mit jedem abstimmen, damit sich die Handwerker nicht gegenseitig im Wege stehen. Wäre es da nicht viel einfacher, man beauftragt einen Betrieb und lässt alles aus einer Hand schlüsselfertig erledigen?

Java-Entwicklung ist auch eine Baustelle

Bei der Entwicklung von JEE-Anwendungen hat es der Java-Entwickler nicht viel leichter (i. d. R. staubt es nicht so viel). Es gibt viele Probleme, die gelöst werden müssen. Man kann zwar keinen Handwerker beauftragen, aber es gibt auf dem Markt zahlreiche Tools und Frameworks. Und es ist eine große Herausforderung, alle genauer unter die Lupe zu nehmen und dann auch noch zu koordinieren. Wäre es nicht auch hier wünschenswert, alles aus einer Hand geliefert zu bekommen?

Mit dem Spring-Framework [1] bekommen Sie (fast) alles aus einer Hand und Sie haben wieder die Zeit, sich um die wesentlichen Aufgaben, nämlich die Implementierung der Geschäftslogik zu kümmern.

Der Kern von Spring ist mehr als eine Kaffeebohne

Eigentlich muss man sich fragen, ob der Begriff Framework auf Spring überhaupt zutrifft. Spring funktioniert nicht wie andere Frameworks, z. B. kümmert sich Hibernate um die Persistenz einer Anwendung, Struts erleichtert die Entwicklung von Web-Applikationen und Log4j erstellt Log-Ausgaben. Man sieht hier, dass sich die bekannten Frameworks immer einer bestimmten Aufgabe widmen. Spring gliedert sich hingegen in alle Bereiche einer JSE- bzw. JEE-Anwendung ein. Besser sollte man allerdings sagen: Spring kann sich eingliedern, denn es stellt sich nicht die Frage, ob man Spring verwenden möchte, oder nicht. Es stellt sich vielmehr die Frage, welche Elemente man von Spring einsetzen möchte.

Der Kern von Spring

Dependency Injection (DI) und ein Framework für die aspektorientierte Programmierung sind die Kerntechnologien von Spring und bilden die Grundlage für die gesamte Arbeit mit Spring. In diesem Artikel soll der Fokus auf die Dependency Injection gelegt und anhand von Beispielen der Einsatz in der Praxis demonstriert werden.

public class Referent implements OrdixMitarbeiter {
 
  private Seminar seminar;
  private String name;
     
  public Referent(String name) { this.name = name; }
  public Seminar getSeminar() { return seminar; }
  public void setSeminar(Seminar seminar) { this.seminar = seminar; }
  public String getName() { return this.name; }
  public void halteSpringSeminar() {
    seminar.halten(); // Verwendung des injizierten Seminars
  }
}
Abb. 1: Die Klasse Referent implementiert das Interface OrdixMitarbeiter.
public class Seminar {
   
  private String name;
  private String dauer;
  
  public Seminar(String name) { this.name = name; }
  public String getName() { return this.name; }
  public String getDauer() { return dauer; }
  public void setDauer(String dauer) { this.dauer = dauer; }
     
  public void halten() {
    System.out.println("Das " + name + "-Seminar dauert " + dauer + " Tage!");
  }
}
Abb. 2: Die Seminar-Klasse enthält die nötigen Informationen.
public class Main_ohne_Spring {
 
  public static void main(String[] args) {
    // Referent erzeugen:
    OrdixMitarbeiter referent = new Referent("Thomas Rohde"); 
    Seminar spring = new Seminar("Spring2"); // Seminar erzeugen
    spring.setDauer(3);
    System.out.println("Ihr Referent: " + referent.getName());
    referent.setSeminar(spring); // Seminar zuweisen
    referent.halteSpringSeminar(); // Seminar halten
  }
}
Abb. 3: Eine Verwendung ohne Spring.
<beans>
  <bean id="spring-kurs" class="de.ordix.spring.di.Seminar">
    <constructor-arg value="Spring2" />
    <property name="dauer" value="3" />
  </bean>
  <bean id="referent" class="de.ordix.spring.di.Referent">
    <constructor-arg value="Thomas Rohde" />
    <property name="seminar" ref="spring-kurs" />
  </bean>
</beans>
Abb. 4: Die Spring-Konfiguration in der Datei spring-di.xml.
public class Main_mit_Spring {
 
  public static void main(String[] args) {
    ApplicationContext appContext =
      new ClassPathXmlApplicationContext
      ("de/ordix/spring/di/spring-di.xml");
        
    // Aus dem Spring-Anwendungkontext wird der Referent geholt
    OrdixMitarbeiter referent = 
      (OrdixMitarbeiter) appContext.getBean("referent");
    System.out.println("Ihr Referent: " + referent.getName());
    referent.halteSpringSeminar();// Seminar halten
  }
}
Abb. 5: Der Programmaufruf mit Spring.
Ihr Referent: Thomas Rohde
Das Spring2-Seminar dauert 3 Tage!
Abb. 6: Ausgabe auf der Konsole.
Abb. 7: Die Spring-IDE im Überblick.
Abb. 7: Die Spring-IDE im Überblick. vergrößern

Ein ORDIX Szenario: Seminarbuchung

Stellen Sie sich also folgendes Szenario vor: Ein ORDIX Mitarbeiter soll nächste Woche ein Seminar halten, beispielsweise unseren neuen Spring-Kurs [2]. Zur besseren Wiederverwendbarkeit gönnen wir uns als erstes ein Interface namens OrdixMitarbeiter. Dann brauchen wir noch die Klasse Referent, die das Interface implementiert, wie Abbildung 1 zeigt. Das Interface OrdixMitarbeiter schreibt lediglich vor, dass Referent eine Methode getName() und dazu eine Methode halteSpringSeminar() implementieren muss. Für eine Verwendung des Interfaces ohne Spring müssen wir dem Referenten natürlich auch noch ein Seminar zuordnen. Dazu wird dann noch eine Methode setSeminar() benötigt. (Bei der Verwendung von Spring entfällt diese allerdings - aber dazu später mehr.) Abschließend, aber ganz wichtig, benötigen wir eine Klasse Seminar, damit der Referent es zugeordnet bekommen kann. Das könnte dann im Folgenden so aussehen wie in Abbildung 2.

Der Programmaufruf ohne Spring

Die soeben erstellten Klassen müssen nun von einem Programm aufgerufen werden, damit Referent auch sein Seminar zugeordnet wird. Abbildung 3 verdeutlicht, wie das ohne Spring aussehen könnte. Fällt Ihnen etwas auf? Wir verwenden hier zwei Dinge, die nicht wirklich schön sind:

  • Es wird mit dem Schlüsselwort new sowohl ein Referent, als auch ein Seminar erzeugt. Das ist für einen Austausch der Implementierung, z. B. für Unit-Tests, ein großer Nachteil. Unter Umständen befinden sich im Code verstreut mehrere Instanzen von Referent und Seminar. Diese müssten alle ausgetauscht werden.
  • Über die Methode setSeminar() bekommt der Referent das Seminar übergeben. Wir verknüpfen an dieser Stelle also die beiden Klassen fest miteinander. Der Nachteil hinsichtlich zukünftiger Wartbarkeit ist, dass Klassen nicht mehr so einfach gegen andere Klassen ausgetauscht werden können.

Die Spring-Konfiguration

Bevor wir uns den Quellcode der main-Methode für eine Verwendung mit Spring ansehen, sollten wir einen Blick auf die Konfigurationsdatei spring-di.xml werfen. Spring verwendet immer eine Konfigurationsdatei. Je nach logischem Aufbau können aber auch mehrere Dateien verwendet werden. Das ist kein Problem, sondern erhöht die Übersichtlichkeit.

Als Hauptelement wird immer das Element <beans> deklariert. Alle Unterelemente werden dann zu Spring-Beans, indem sie mit dem Tag <bean> definiert werden. In der Konfiguration in Abbildung 4 gibt es zwei Spring-Beans: spring-kurs und referent. Die Beans werden über ihre eindeutige ID identifiziert, die frei vergeben werden kann. Das Attribut class legt fest, zu welcher Java-Klasse diese Spring-Bean gehört, bzw. welche Java-Klasse die Spring-Bean instanzieren soll.

Eine Spring-Bean repräsentiert also ein Objekt einer bestimmten Klasse und kann Abhängigkeiten zu anderen Klassen injiziert bekommen. Dadurch erhält man eine lose Kopplung und kann die Implementierung leichter austauschen. Abbildung 5 zeigt den entsprechenden Programmaufruf. Hier ist es völlig egal, wie die konkrete Implementierung von OrdixMitarbeiter (hier also Referent) aussieht. Es gibt auch keine Abhängigkeiten zur konkreten Klasse Seminar, wie im Beispiel in Abbildung 3.

Das property-Element einer Spring-Bean

Beide Bean-Deklarationen besitzen in ihrem Body ein property-Attribut. Über dieses Attribut können den Klassenattributen mit Hilfe von setter-Methoden innerhalb der Java-Klasse Werte zugewiesen werden. Im Beispiel bekommt der Spring-Kurs eine Dauer von drei Tagen zugewiesen. Spring erkennt an dieser Stelle übrigens selbstständig den Datentyp und kann daher dem Integer-Attribut in der Klasse Seminar die 3 zuweisen. Werfen wir nun einen Blick auf das property-Attribut der Bean referent. Dort wird dem Referenten das Seminar, also der spring-kurs, zugewiesen. Da wir es hier nicht mit einem einfachen Datentyp zu tun haben, wird das ref-Attribut verwendet. Somit bekommt der referent den spring-kurs als Referenz injiziert.

Das constructor-arg-Element einer Spring-Bean

Neben dem property-Attribut ist Ihnen vielleicht schon das Element constructor-arg aufgefallen. Wie der Name schon vermuten lässt, können mit dem Attribut constructor-arg Werte bzw. Referenzen an den Konstruktor einer Java-Klasse übergeben werden. Hier wird dem Referenten ein Name zugewiesen: "Thomas Rohde" in diesem Fall. Das wäre auch über eine setter-Methode mit Hilfe des property-Attributs möglich gewesen. Aber es wurde hier das constructor-arg-Attribut verwendet, um sicherzustellen, dass ein Referent immer einen Namen hat. Das Seminar bekommt auf die gleiche Weise den Namen "Spring2" zugewiesen. Der entsprechende Java-Programmaufruf in der main-Methode findet sich in Abbildung 5.

Der Programmaufruf mit Spring

Zunächst muss man sich in einer Spring-Anwendung den ApplicationContext besorgen. Dazu wird hier mit der Klasse ClassPathXmlApplicationContext die Spring-Konfiguration eingelesen (spring-di.xml), die im Classpath liegen muss. Die Konfiguration wird dem Attribut appContext zugewiesen. appContext ist vom Typ ApplicationContext und besitzt u. a. eine Methode getBean(), mit der der referent aus der Konfiguration geladen wird.

Da wir sowohl dem Referenten als auch dem Seminar schon in der Spring-Konfiguration Name, Dauer etc. zugewiesen haben, können wir nun davon profitieren: Im Java-Quellcode reicht ein Aufruf von referent.getName(), um den Namen des Referenten abzufragen und ihn dazu aufzufordern, mit referent.halteSpringSeminar() anschließend das Spring-Seminar zu halten und er erledigt seine Aufgabe wie erwartet. Als Bestätigung erscheint auf der Konsole eine Ausgabe, wie sie in Abbildung 6 gezeigt wird. Das gesamte Projekt steht Ihnen natürlich auch zum Download [3] bereit.

Die Spring-IDE für heißen Kaffee

Da Sie zukünftig ja wieder genügend Zeit haben, sich Ihrer wesentlichen Aufgabe - der Implementierung der Geschäftslogik - zu widmen, sollten Sie sich Ihre Arbeit mit Hilfe der Spring-IDE noch ein wenig angenehmer gestalten.

Die Spring-IDE ist eine grafische Benutzeroberfläche (siehe Abbildung 7) für die Arbeit mit den Spring-Konfigurationsdateien und steht als Plugin für Eclipse zur Verfügung [4]. Die Installation sollte am besten über die Update-Funktion von Eclipse erfolgen. Nach der Installation muss man sein Projekt einmalig der Spring-IDE bekannt machen. Dazu finden Sie nach einem Rechtsklick auf das Projekt im Kontextmenü den Eintrag "Spring Tools" und dann den Eintrag "Add Spring Project Nature". Danach bekommt ihr Projekt-Icon zur Kennzeichnung ein kleines "s". Jetzt müssen Sie der Spring-IDE noch mitteilen, welche Dateien die Spring-Konfigurationen enthalten. Dazu finden Sie in den Projekteigenschaften den Eintrag "Spring -> Beans Support". Mit Hilfe des Add-Buttons können nun die Konfigurationsdateien hinzugefügt werden.

Der Spring-Explorer

Eclipse kennt jetzt eine neue View namens "Spring Explorer". Sie zeigt eine strukturierte Ansicht der Spring-Anwendung in Form eines Navigationsbaumes. Nach einem Doppelklick auf den entsprechenden Eintrag (z. B. eine Spring-Bean) springt der Cursor sofort in die Spring-Konfiguration an die zugehörige Position. Die Spring-IDE kann natürlich auch bei der Erstellung einer Spring-Konfiguration unterstützen. So bietet sie eine Quellcodevervollständigung sowie eine Fehlerkennung, sowohl für die Referenzierung anderer Spring-Beans, als auch für den Zugriff auf Java-Klassen.

Bei gedrückter Strg-Taste kann man auch direkt die Hyperlink-Funktionalität verwenden und zu anderen Spring-Beans navigieren oder in den zugehörigen Java-Code verzweigen. Falls nun Ihr Interesse geweckt ist, schauen Sie sich auf jeden Fall einmal die Spring-IDE-Website [4] an. Dort können Sie das Plugin für Eclipse herunterladen und es werden Ihnen sämtliche Funktionen vorgestellt.

Fazit

Mit der Dependency Injection, eine der Kernfunktionalitäten von Spring, lässt sich eine Anwendung leicht konfigurieren, bleibt stets skalierbar und Sie vermeiden die feste Verknüpfung von Objekten. Um noch einmal auf das Eingangsthema Hausbau zurückzukommen, steht der Rohbau zu diesem Zeitpunkt schon fast. Für die restlichen Aufgaben holen Sie sich nun einfach die Funktionen von Spring, die Sie für Ihre Anwendung benötigen.

Thomas Rohde (info@ordix.de).