Gute Software sollte sich an der entsprechenden Fachdomäne orientieren und nicht an der zugrundeliegenden Technologie. Um dies zu erreichen, wird allerdings eine Basis benötigt, die technisch ausgereift ist ohne Einschränkungen für die Entwicklung. Eine solche Basis kann mit dem Springframework geschaffen werden. Die Kombination von Spring, Annotations, Java Persistence (JPA) und Unit-Testing erlaubt eine flexible und modulare Architektur und könnte eine mögliche technische Basis für ein solches Softwaresystem sein.
Dieser Vortrag stellt einen Lösungsansatz anhand eines einfachen Beispiels vor. Die Aufbereitung der Inhalte orientiert sich dabei an einem typischen test-zentrierten Entwicklungsprozess. Folgende Themen werden angesprochen:
* Einleitung Spring und JPA
* Projektstruktur
* Entwicklung der API (der Schnittstellen)
* Test-getriebene Entwicklung der Implementierung
* Spring-unterstützte Integrationstests
Ausblick:
* Spring 2.1 - mehr Annotations; Verwaltung von Entities mit Spring
* Webschicht - Anbindung einer Webanwendung mit Java Server Faces (JSF)
* Spring-Webservices - Contract-First Webservices mit Spring-WS 1.0
3. Was ist „gute“ Software?
Software, die macht was sie soll
Qualitativ-hochwertige Software
Software, die den Kundenwünschen
entspricht
Thorsten Kamann ● thorsten.kamann@itemis.de 3
4. …und was man dafür braucht
Gute und flexible Einwandfreie techn.
Architektur Infrastruktur
Gute Gutes und
Projektorganisation motiviertes Team
Thorsten Kamann ● thorsten.kamann@itemis.de 4
5. Das Thema heute ist:
Gute und flexible Einwandfreie techn.
Architektur Infrastruktur
Gute Gutes und
Projektorganisation motiviertes Team
Thorsten Kamann ● thorsten.kamann@itemis.de 5
14. Leichtgewichtige Architekturen
Geringe Abhängigkeit zur Ablaufumgebung
• Code kennt seinen Container nicht
• Deployment entscheidet über die
Ablaufumgebung
• Während der Entwicklungszeit schneller
Servlet-Container anstatt J2EE-Server
Thorsten Kamann ● thorsten.kamann@itemis.de 14
23. Beispiel: Komponenten
• Defacto Standard im Bereich OR-
Mapping
• Vorlage für den JPA-Standard
• Voll JPA-kompatibel
Hibernate
Thorsten Kamann ● thorsten.kamann@itemis.de 23
24. Beispiel: Komponenten
• Dynamische Sprache
• 100% Integration in die Java-VM
• Mächtige Sprachfeatures
• Bi-direktionale Nutzung mit Java-
Code
• Ideal für Unit-Testing
Groovy
Thorsten Kamann ● thorsten.kamann@itemis.de 24
26. Exkurs: Maven
Features
• Beschreibung eines Projekts mittels Metadaten
• Beschreibung des resultierenden Artefakts und dessen
Abhängigkeiten
• Support von SNAPSHOT-Versionen
• Projektabhängigkeiten
• Anpassung des Buildprozess mit PlugIns
• Reporting
• Convention Over Configuration
• Release Management
Thorsten Kamann ● thorsten.kamann@itemis.de 26
27. Exkurs: Maven - Repositories
Lokales Repository
• Befindet sich auf dem lokalen Rechner
• Mit „install“ werden Artefakte installiert
• Nicht shareable
Remote Repository
• Befindet sich auf einem entfernten Server
• Mit „deploy“ werden Artefakte deployed:
per ssh, webdav, file, ftp,…
• Shareable
Thorsten Kamann ● thorsten.kamann@itemis.de 27
31. Exkurs: Spring [Was ist Spring?]
Inversion
Ansammlung von
of
API's
Control
Programmier-
modell
Thorsten Kamann ● thorsten.kamann@itemis.de 31
32. Exkurs: Spring [Komponenten]
Spring Core
AOP
WEB
JEE
Spring AOP
Spring MVC
AspectJ-Integration JMX
Struts
JMS
ORM WebWork
DAO JCA
Tapestry
JPA Remoting
Spring JDBC JSF
Hibernate EJB's
Transaction- PDF
Toplink Email
Management Portlets
JDO
Thorsten Kamann ● thorsten.kamann@itemis.de 32
33. Exkurs: Spring [Spring-Module]
Spring
Spring Spring
WebService
WebFlow Security
Spring Spring
Spring LDAP
Rich Client Extensions
Spring
Spring IDE Spring OSGI
BeanDoc
Spring Spring
Spring .NET
JavaConfig Batch
Thorsten Kamann ● thorsten.kamann@itemis.de 33
34. Exkurs: Spring [Features]
Leichtgewichtiger Container
• Zentralisierte und automatisierte
Konfiguration und Verdrahtung
• Nicht invasiv
• Fügt lose gekoppelte Komponenten (POJO's)
zu komplexen Systemen zusammen
• Skalierbar
• Verbessert die Testbarkeit der Komponenten
Thorsten Kamann ● thorsten.kamann@itemis.de 34
35. Exkurs: Spring [Features]
Abstraktions Transaktions-Management
• Erweiterbares Transaktions-Management
• Deklarative Konfiguration der
Transaktionen
• Nicht auf J2EE-Umgebungen beschränkt
Thorsten Kamann ● thorsten.kamann@itemis.de 35
36. Exkurs: Spring [Features]
Abstraktionsschicht für reines JDBC
• Reduziert den Code für auf JDBC-basierte
Anwendungen
• Vereinfacht die Fehlerbehandlung
• Bietet eine aussagekräftige Exception-
Hierarchie (herstellerunabhängig)
• Exceptions basieren auf der DAO-
Exception-Hierarchie
Thorsten Kamann ● thorsten.kamann@itemis.de 36
37. Exkurs: Spring [Features]
Integration O/R-Mapper
• Unterstützung von Hibernate, Toplink, JDO
und iBATIS SQL Maps
• Vereinfacht die Entwicklung mit diesen
O/R-Mappern
• Unterstützung von Transaktionen
• Unterstützung des DAO-Patterns
Thorsten Kamann ● thorsten.kamann@itemis.de 37
38. Exkurs: Spring [Features]
AOP Funktionalität
• Basiert auf AspectJ
• Vollständig integriert in das Spring
Konfigurations-Management
• Transaktions-Management basiert auf AOP
• Jedes Objekt in Spring kann mittels AOP
gemanaged werden
Thorsten Kamann ● thorsten.kamann@itemis.de 38
39. Exkurs: Spring [Features]
MVC-Webapplication Framework
• Benutzt die Spring-Core Funktionalitäten
• Sehr konfigurierbar durch verschiedene
Strategie-Interfaces
• Kombinierbar mit den verschiedensten
Viewtechnologien:
• JSP, Velocity, Tiles, iText, POI
Thorsten Kamann ● thorsten.kamann@itemis.de 39
40. Exkurs: Spring [Features]
Dynamische Sprachen
• Groovy, JRuby, BeanShell
• Eigener Namespace für jede Sprache
• Autom. Reloading
refresh-check-delay=quot;TIME_IN_MSECquot;
• Inline-Scripts
• Grails ist eine Spring Web MVC Anwendung
Thorsten Kamann ● thorsten.kamann@itemis.de 40
41. Exkurs: Spring [Features]
Abstraktionsschicht für JMS
• Unterstützt JMS 1.0.2 und 1.1
• Unterstützt synchrone und asynchrone Calls
• Bietet ein einfaches API mittels
JMSTemplate
Thorsten Kamann ● thorsten.kamann@itemis.de 41
42. Exkurs: Spring [Features]
Support für JMX
• MbeanExporter ermöglicht den Export
jedes SpringBeans als MBean
• Listener-Support
• Notification-Support
• Verschiedene Naming-Strategies
Thorsten Kamann ● thorsten.kamann@itemis.de 42
45. Exkurs: Java Persistence API
Konzept
• JSR 220
• Entities sind POJO‘s
• Oft Entities = Tabelle in DB
• Instanzen einer Entity sind Zeilen einer
DB-Tabelle
• Konfiguration per
• Annotations
• XML
Thorsten Kamann ● thorsten.kamann@itemis.de 45
46. Exkurs: Java Persistence API
Query Language
• Java Persistence Query Language
• Ähnelt SQL
• Arbeitet mit Entity-Instanzen anstatt
DB-Tabellen
Thorsten Kamann ● thorsten.kamann@itemis.de 46
48. Exkurs: Groovy
Features
• JSR 241
• Dynamische Sprache
• 100% Integration in die Java VM
• Mächtige Syntax
• Schnell erlernbar
• Support für Domain Specific Languages (DSL)
• Vereinfacht Unit-Testing (jUnit integriert)
• Mächtige XML-Verarbeitung
• Kompiliert zu Java Bytecode
Thorsten Kamann ● thorsten.kamann@itemis.de 48
49. Exkurs: Groovy
Closures
• Codeblöcke
• Können einen Wert/Objekt zurückgeben
• Referenzieren und verwenden Variablen
• call()(implizit/explizit) führt die Closure
aus
• Können an eine Variable gebunden werden
• Ähneln Java Inner Classes
Thorsten Kamann ● thorsten.kamann@itemis.de 49
50. Exkurs: Groovy
The Groovy Truth
Runtime type Evaluation criterion required for truth
Booleanwert muss true sein
Boolean
Matcher Der reguläre Ausdruck muss mindestens 1 Treffer haben
Collection Die Collection darf nicht leer sein
Map Die Map darf nicht leer sein
String Der String darf ebenfalls nicht leer sein
Number Muss ungleich 0 sein
Die Objektreferenz muss ungleich null sein
Alles andere
Thorsten Kamann ● thorsten.kamann@itemis.de 50
51. Exkurs: Groovy – Listen und Ranges
def list = [„item1“, „item2“, „item3“]
Eine Liste mit 3 Einträgen
assert list.size()
def emptyList = [] Eine leere Liste
assert !emptyList
Der ersten Liste wird ein
list << „item4“
Element hinzugefügt
assert list.size() == 4
Eine Range mit den Werten
def range = [1..4]
1, 2, 3, 4 wird erstellt
assert range.size() == 4
Eine Range mit den Werten
def range1 = [1..<4]
assert range1.size() == 3 1, 2, 3 wird erstellt
Thorsten Kamann ● thorsten.kamann@itemis.de 51
52. Exkurs: Groovy – Listen und Closures
def list = [„item1“, „item2“, „item3“]
Each-Closure
list.each{ print it+“ „}
> item1 item2 item3
Ein bestimmtes Element
assert list.find{it==„item2“}
finden
list = [„a1“, „a2“, „a3“, „i1“, „i2“]
Eine Anzahl an Elementen
assert list.findAll{
it.startsWith(„i“)}.size() == 3 aus der Liste finden
Thorsten Kamann ● thorsten.kamann@itemis.de 52
53. Exkurs: Groovy - Maps
def map = [key1: „value1“, key2: „value2“] Eine Map mit 2 Einträgen
assert map.size() == 2
wird erstellt
assert map.key1 == „value1“
Ein 3. Eintrag wird
map.key3 == „value3“
hinzugefügt
assert map.size() == 3
Alternative Zugriffsmethode
assert map[„key2“] == „value2“
assert map.get(„key2“) == „value2“ auf die Elemente der Map
def emptyMap = [:] Eine leere Map
assert !emptyMap
wird erstellt
Thorsten Kamann ● thorsten.kamann@itemis.de 53
55. Zum Beispiel: Projektstruktur
API
Implementierung
Integration
WebApp
Webservice
Thorsten Kamann ● thorsten.kamann@itemis.de 55
56. Zum Beispiel: Build
Build mit Maven
• Ein mvn install in dem Projekt
spring2-jpa-basic builded alle
Projekte
• Das Projekt spring2-jpa-
basic-m2 stellt eine
vollständige Maven
Installation zur Verfügung
• Zusätzlich gibt es Eclipse-
Launcher für die anfallenden
Tasks
Thorsten Kamann ● thorsten.kamann@itemis.de 56
66. Zum Beispiel: Impl - Entities
@Entity(table=„CUSTOMERS“) Entity auf Tabelle
public class Customer{
CUSTOMERS mappen
@Id
@GeneratedValue(
Primary Key
strategy = GenerationType.AUTO)
private Long id;
@OneToOne(targetEntity = Address.class,
1-zu-1 Beziehung
cascade = { CascadeType.ALL})
private IAddress address;
@Column(length = 40) Konfiguration einer
private String firstName;
Column in der Tabelle
…
CUSTOMERS
}
Thorsten Kamann ● thorsten.kamann@itemis.de 66
67. Zum Beispiel: Impl – persistence.xml
<persistence …>
Eindeutiger Name der
<persistence-unit
name=quot;spring2-jpa-basic-persistence-unitquot;> Persistence-Unit
<properties>
<property
name=quot;hibernate.jdbc.batch_sizequot; Eigenschaften der
value=quot;0quot;/>
Persistence-Unit
<property
name=quot;hibernate.default_batch_fetch_sizequot;
value=quot;5quot;/>
[…]
</properties>
</persistence-unit>
</persistence>
Thorsten Kamann ● thorsten.kamann@itemis.de 67
68. Zum Beispiel: Impl – DAO‘s
@Repository
Sorgt für die
public class CustomerDao
Übersetzung
implements ICustomerDao {
von Exceptions
@PersistenceContext(
unitName = quot;spring2-jpa-basic-persistence-unitquot;)
protected EntityManager entityManager; Injection des
Entity-Managers
public List<ICustomer> findAll() {
über Spring
return entityManager
.createQuery(quot;from Customer cquot;)
.getResultList();
Plain Java
}
[…]
}
Thorsten Kamann ● thorsten.kamann@itemis.de 68
69. Zum Beispiel: Impl – Spring-Config
<bean
class=„PersistenceAnnotationBeanPostProcessorquot; />
<bean
class=„PersistenceExceptionTranslationPostProcessorquot; />
Excpetion Translation
Support der Annotations in den DAO‘s
Thorsten Kamann ● thorsten.kamann@itemis.de 69
72. Zum Beispiel: Impl - Services
@Transactional
Dieser Service nimmt an
public class CustomerService
einer Transaction teil:
implements ICustomerService {
private ICustomerDao customerDao; -PROPAGATION_REQUIRED
private IAddressDao addressDao; -READWRITE
-ROLLBACKFOR:
[…]
-jede RuntimeException
Diese Methode hat nur
@Transactional(readOnly = true)
einen lesenden Zugriff
public List<ICustomer> findAllCustomers() {
return customerDao.findAll();
}
[…]
}
Thorsten Kamann ● thorsten.kamann@itemis.de 72
73. Zum Beispiel: Impl – Spring-Config
<bean id=quot;transactionManagerquot; JPA
class=„JpaTransactionManagerquot;>
Transaction-Manager
<property name=quot;entityManagerFactoryquot;
ref=quot;entityManagerFactoryquot; />
</bean> Transaktionen werden
per Annotations
<tx:annotation-driven
konfiguriert
transaction-manager=quot;transactionManagerquot; />
Thorsten Kamann ● thorsten.kamann@itemis.de 73
74. Zum Beispiel: Impl – Unit Testing
Thorsten Kamann ● thorsten.kamann@itemis.de 74
75. Zum Beispiel: Impl – Unit Testing
Warum Groovy?
• Leistungsfähigere Syntax
• Listen
• Maps
• Integriertes jUnit
• Closures
• Keine Mocks, stattdessen Maps mit Closures
def dao = [findById:{id->
new CustomerImpl(id:100L,firstName:“…“,…)}] as ICustomerDao
• SpringBuilder
• XML-Processing
Thorsten Kamann ● thorsten.kamann@itemis.de 75
76. Zum Beispiel: Impl – Unit Testing
public final void testChangeAddress() { Erzeugung einer neuen
IAddress expAddress = new Address( Instanz mit Constructor-
street: quot;s1quot;, city: quot;c1quot;, Enhancement
country: quot;c1quot;, zipCode: quot;z1quot;);
Implementierung des
def addressDao = [ IAddressDao
store:{entity -> expAddress}] as IAddressDao
Neue Instanz des
ICustomerService customerService =
new CustomerService(addressDao: addressDao) ICustomerService
def result = customerService
.changeAddress(expAddress); Ausführen und
assert expAddress == result Ergebnis vergleichen
}
Thorsten Kamann ● thorsten.kamann@itemis.de 76
80. Zum Beispiel: Integration
Spring
• AbstractJpaTests:
• Dependency Injection in Tests ohne Konfiguration
• Zugriff auf EntityManager
• Zugriff auf Spring-Ressourcen
• tearDown macht einen RollBack
• SpringContext wird einmalig pro TestCase initialisiert
DBUnit
• Erzeugt eine initiale Datenbefüllung
• Integrierbar in Spring
Thorsten Kamann ● thorsten.kamann@itemis.de 80
84. Zum Beispiel: Webapp
Spring & JSF
• org.springframework.web.jsf.DelegatingVariableResolver
• Erlaubt Injection von Spring-Komponenten in
ManagedBeans
• Alternativ Spring-MVC
• Bessere Navigation mit Spring-Webflow
Grails
• Web-Framework basierend auf Groovy und Spring
• Anbindung an Backend-System problemlos möglich
• Keine JSF-Unterstützung
Thorsten Kamann ● thorsten.kamann@itemis.de 84
88. Zum Beispiel: Webservice
Spring Webservice
• Contract-First Ansatz
• XML-Schema = Contract
• Nur der Endpoint muss programmiert werden
• WSDL wird zur Laufzeit erstellt
• Support von JAXB, Castor, XMLBeans,…
Thorsten Kamann ● thorsten.kamann@itemis.de 88
90. Ausblick auf Spring 2.5
Voller Java 6 und JEE 5
Support
Dependency Injection mit
Annotations
Autodetection von annotierten
Klassen
Built-In Support von Load-
Time-Weaving
Neue XML-Namespaces für
„context“ und „jms“
Thorsten Kamann ● thorsten.kamann@itemis.de 90
92. Fazit
Fazit
• Einfaches und flexibles System
• Wenige Abhängigkeiten von Systemkomponenten
• Leicht testbar
• Für alle Tasks bietet Spring eine Lösung
• Annotations vereinfacht die Konfiguration
• Sehr guter Support für Integrationstest
• Maven bietet eine sehr leistungsfähige Projektverwaltung
• Unittests mit Groovy machen Spaß und sind sehr effektiv
erstellt
Thorsten Kamann ● thorsten.kamann@itemis.de 92
93. Fazit
Verbesserungen
• Code-Generatoren vereinfachen die Erstellung von
Klassen und deren Annotations
• Integration von Groovy in alle Testbereiche (Unit,
Integration, Webtest, Webservicetest) kann die
Qualität dramatisch erhöhen
Thorsten Kamann ● thorsten.kamann@itemis.de 93