Spring an einem einfachem Beispiel (Tutorial)
Dieser Beitrag ist Teil einer (Tutorial-) Serie über die Einführung in das Spring Framework und stellt das Spring Framework an einem kleinen einfachem Beispiel vor.
Die Struktur des Projektes
Die verwendeten Frameworks und Werkzeuge sind hier beschrieben. Dieses Beispiel ist eine Konsolenanwendung, die den Service eines Taschenrechners aufruft. In diesem Beispiel werden die folgenden Technologien des Spring Frameworks vorgestellt:
- Die Definition einer Spring Bean mit einem Interface über die XML Konfiguration des Spring Frameworks.
- Die Verwendung von Spring Framework Utilities zur Validierung von Aufrufparametern.
- Die Erstellung eines JUnit-Tests mit der Verwendung von Java Hamcrest.
- Die Trennung der Test-Implementierung von der Produktiven-Implementierung.
- Die automatisches Dependency Injection (Autowired) des Taschenrechners.
- Die Verwendung von Logging.
- Das Definieren von Spring Beans mit Annotationen und das Auffinden der Spring Beans mit einem Component scan.
- Das Starten einer Konsolenanwendung.
Im folgendem Bild ist die Projektstruktur dargestellt.
Die Projektstruktur in Eclipse (© Frank Rahn)
Im folgendem Bild sind die benötigten Bibliotheken dargestellt. Das Maven Plugin wird hier nur für das Auflösen der Abhängigkeiten (Dependency) und das Downloaden der benötigten Bibliotheken verwendet.
Die benötigten Bibliotheken - Dependencies (© Frank Rahn)
Update
Das Maven Skript wurde vervollständigt und kann auch zum Builden ($ mvn clean package
) der Anwendung verwendet werden. Mit $ mvn eclipse:clean eclipse:eclipse
werden die Konfigurationsdateien für Eclipse neu erstellt – sie sind aber auch noch im Repository. Die Anwendung kann mit $ mvn exec:java
ausgeführt werden.
Die Literaturempfehlungen für dieses Beispiel
Der Service eines Taschenrechners
Zunächst wird die Schnittstelle des Services definiert. Diese erhält vorerst zwei Methoden um Zahlen zu addieren. Für eine Einführung in das Spring Framework ist dieser minimale Funktionsumfang dieser Schnittstelle ausreichend.
/** * Ein einfach Taschenrechner. * @author Frank W. Rahn */ public interface Calculator { /** * Addiere die rationalen Zahlen. * @param summands die Summanden * @return die Summe */ double add(double... summands); /** * Addiere die natürlichen Zahlen. * @param summands die Summanden * @return die Summe */ int add(int... summands); }
Hier die Implementierung des Services mit den ersten Prüfungen.
- In der Zeile 19 und 36 wird eine Prüfung mit Mitteln
Assert.notNull(summands)
des Spring Frameworks durchgeführt. Wenn der Summandnull
ist, wird die AusnahmeIllegalArgumentException
mit dem angegebenen Text als Nachricht geworfen.
/** * Eine Implementierung des einfach Taschenrechners. * @author Frank W. Rahn */ public class SimpleCalculator implements Calculator { /** * {@inheritDoc} * @see Calculator#add(int[]) */ @Override public int add(int... summands) { notNull(summands, "Die Summanden sind null"); int result = 0; for (int sum : summands) { result += sum; } return result; } /** * {@inheritDoc} * @see Calculator#add(double[]) */ @Override public double add(double... summands) { notNull(summands, "Die Summanden sind null"); double result = 0; for (double sum : summands) { result += sum; } return result; } }
Diese Modul wird mit einer XML basierenden Konfiguration aufgebaut.
- In der Zeile 15 wird für den Taschenrechner ein Alias definiert, mit dem der Taschenrechner zusätzlich aufrufbar ist.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd "> <description>Dieses ist die Konfiguration des Taschenrechners.</description> <!-- Den Taschenrechner definieren --> <bean id="simpleCalculator" class="de.rahn.services.calculator.standard.SimpleCalculator" /> <alias name="simpleCalculator" alias="calculator" /> </beans>
Der Test mit JUnit
Die JUnit Tests liegen im Source-Verzeichnis src/test
mit einer identischen Paketstruktur, wie unter src/java
. Im folgendem Quelltext ist ein JUnit Test für die Implementierung des Taschenrechner dargestellt.
- In der Zeile 17 wird eine Annotationen für die Konfiguration verwendet, diese lädt die Datei
SimpleCalculatorTest-context.xml
im gleichen Verzeichnis wie die KlasseSimpleCalculatorTest
. - Durch die Angabe der Annotation in Zeile 20 wird im Attribut
calculator
durch das Spring Framework eine Instanz der Implementierung des Services injiziert. - In der Zeile 35 wird angegeben, dass dieser Test nicht fehlschlägt, wenn die Ausnahme
IllegalArgumentException
geworfen wurde.
/** * Test der Klasse {@link SimpleCalculator}. * @author Frank W. Rahn */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class SimpleCalculatorTest { @Autowired private SimpleCalculator calculator; /** * Test method for {@link SimpleCalculator#add(double[])}. */ @Test public void testAddDoubleArray() { double result = calculator.add(1.0, 2.0); assertThat("Test der Addition", result, is(3.0)); } /** * Test method for {@link SimpleCalculator#add(int[])}. */ @Test(expected = IllegalArgumentException.class) public void testAddIntArray() { calculator.add((int[]) null); } }
Die folgende Konfigurationsdatei des Tests importiert nur die Konfigurationsdatei des Taschenrechners.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <description> Dieses ist die Konfiguration für den Test des Calculators. </description> <import resource="classpath:/de/rahn/services/calculator/calculator.xml" /> </beans>
Bei diesem Test wurde die Bibliothek Hamcrest verwendet. Diese Bibliothek verbessert die Ausgabe eines Fehlers.
Im folgendem Beispiel wird ein Fehler mit den Standard-Anweisungen von JUnit erzeugt.
double result = calculator.add(1.0, 2.0); assertEquals("Test der Addition", 4.0, result, 0);
java.lang.AssertionError: Test der Addition expected:<4.0> but was:<3.0> at org.junit.Assert.fail(Assert.java:93) at org.junit.Assert.failNotEquals(Assert.java:647) at org.junit.Assert.assertEquals(Assert.java:443) at de.rahn.services.calculator.standard.SimpleCalculatorTest.testAddDoubleArray...
Im folgendem Beispiel wird ein Fehler mit den Anweisungen von JUnit in Verbindung mit Hamcrest ausgelöst.
double result = calculator.add(1.0, 2.0); assertEquals("Test der Addition", 4.0, result, 0);
java.lang.AssertionError: Test der Addition Expected: is <4.0> got: <3.0> at org.junit.Assert.assertThat(Assert.java:780) at de.rahn.services.calculator.standard.SimpleCalculatorTest.testAddDoubleArray...
Die Anwendung mit Logging
Ein Anwendung, die das Ausführen des Taschenrechners ermöglicht.
- Dabei wird in der Zeile 18 ein Logger mit der Simple Logging Facade for Java (SLF4J) erzeugt, der dann in den Zeilen 31 und 34 verwendet wird.
- In der Zeile 21 wird vom Spring Framework eine Instanz des Taschenrechners in das Attribut
calculator
injiziert.
/** * Die Anwendung zum Aufrufen des Taschenrechners. * @author Frank W. Rahn */ @Component public class Application implements Runnable { private static final Logger logger = getLogger(Application.class); @Autowired(required = true) private Calculator calculator; /** * {@inheritDoc} * @see java.lang.Runnable#run() */ @Override public void run() { // Aufruf des Taschenrechners double result = calculator.add(1.0, 2, 3); logger.info("Ergebnis 1 = {}", result); result = calculator.add((double[]) null); logger.info("Ergebnis 2 = {}", result); } }
Die zugehörige XML Konfiguration. Diesmal wird das Package de.rahn.app
hierarchisch nach Spring Beans gescannt (Zeile 18). Diese werden durch die Annotation @Component
erkannt.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <description> Dieses ist die zentrale Konfiguration für die Anwendung. </description> <!-- Scanne das Package nach Spring Beans --> <context:component-scan base-package="de.rahn.app" /> </beans>
Der Starter, eine Konsolenanwendung, initialisiert die gesamte Anwendung (Zeile 15) und führt sie aus (Zeile 21).
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Die Klasse zum Starten der Anwendung. * @author Frank W. Rahn */ public class Starter { /** * @param args die Argumente der Anwendung */ public static void main(String[] args) { // Initialisierung von Spring ApplicationContext ctx = new ClassPathXmlApplicationContext( "/META-INF/spring/context-app.xml"); // Aufruf der Anwendung Runnable service = ctx.getBean("application", Runnable.class); service.run(); } }
Zum Abschluss die XML Konfiguration zum Einstieg in die Anwendung.
- Diese ist im Verzeichnis
META-INF/spring
abgelegt und verweist in den Zeilen 15 und 16 auf die eigentlichen Module.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd "> <description> Dieses ist die zentrale Konfiguration für die Anwendungen. </description> <!-- Die projektspezifischen Konfigurationen laden --> <import resource="classpath:/de/rahn/services/calculator/calculator.xml" /> <import resource="classpath:/de/rahn/app/application.xml" /> </beans>
Bei anderen Arten von Anwendungen ändert sich der Name der XML Konfigurationsdatei, wie z. B. bei Webanwendungen in context-web.xml
. So können mehrere von diesen Konfigurationen parallel nebeneinander liegen. Zusätzlich werden in diesem Verzeichnis allgemeine technische Konfigurationen, wie z. B. Datenbankinformationen, die von mehreren Modulen verwendet werden, abgelegt. Dadurch kann ein hoher Grad an Wiederverwendung erreicht werden.
Zum Abschluss das resultierende Klassendiagramm (UML) zu diesem Beispiel.
Klassendiagramm dieses Beispiels (© Frank Rahn)
Der Quellcode und Download des Beispiels
Quellcode ansehen bei GitHub:
Spring an einem einfachem Beispiel
Download einer ZIP-Datei von GitHub:
Spring an einem einfachem Beispiel
Die Maven Befehle
Eclipse Konfiguration neu erzeugen: $ mvn eclipse:clean eclipse:eclipse
Anwendung bauen: $ mvn clean install
Anwendung ausführen: $ mvn initialize exec:exec
Update am 28.09.2012
Es wurden folgende Änderungen an allen Projekten vorgenommen.
- Die Projekte wurden aus meinem lokalen Apache Subversion Repository in meine öffentlichen GitHub Repositories verschoben.
- Projekt test-spring-simple
- Projekt test-spring-jpa
- Projekt test-spring-web
- Die folgenden typischen Anpassungen an Git wurden an allen Projekten durchgeführt.
.directory
gelöscht.gitignore
hinzugefügtREADME.md
hinzugefügtCOPYRIGHT.md
hinzugefügt- In jedem Repository wurde für jeden Beitrag der Serie ein Branch angelegt.
develop-spring-an-einem-einfachen-beispiel
develop-spring-mit-aop
develop-spring-mit-jpa-und-hibernate
develop-spring-mit-einer-einfachen-webanwendung
develop-spring-mit-einer-webanwendung-mit-jpa-und-validierung
develop-spring-security-mit-einer-webanwendung
develop-spring-mit-restful-webservice
Updates von 06.10.2012 bis zum 14.10.2012
Es wurden folgende Änderungen an allen Projekten vorgenommen.
- Aktualisierung des OpenJDK auf die Version 1.7.0.
- Aktualisierung der Entwicklungsumgebung Eclipse auf die Version 4.2.1.
Die benötigten Plugins aus dem Eclipse Marketplace: - Aktualisierung der Datei
pom.xml
:- Anpassungen an die OpenJDK Version
- GitHub Einträge (SCM und URL) hinzugefügt
- Aktualisierung der Libraries auf aktuellerer Versionen (z. B. Spring Version 3.1.2.RELEASE, Hibernate Version 4.1.7.Final, JUnit Version 4.10, mockito Version 1.9.0, …)
Die genaueren Versionen bitte aus den jeweiligenpom.xml
auf GitHub entnehmen.
- Wer ist der optimale Java Bean Mapper? - Freitag, 22. September 2023
- Spring Boot Webanwendung: Die ersten Schritte (Tutorial) - Montag, 28. März 2016
- Mainframe-Zugriff via Java - Sonntag, 04. Mai 2014
Hinterlasse einen Kommentar
An der Diskussion beteiligen?Hinterlasse uns deinen Kommentar!