In meinem letzten Blogeintrag habe ich bewusst die alte Spring Batch Version 1.x als Grundlage für das Beispiel genommen. Meine Erfahrungen haben gezeigt, dass diese Version noch häufig zum Einsatz kommt. In diesem Beitrag möchte ich einen kleinen Überblick über die Änderungen geben und zeigen, dass der Wechsel auf die neue Version 2.1 gar nicht so aufwändig ist und man dadurch viele Vorteile hat.
Migration
Zunächst einmal fällt auf, dass die Job-Konfiguration durch den neuen Batch-Namespace deutlich lesbarer ist. Es lässt sich aus meiner Sicht viel einfacher und schneller die Grundstruktur erfassen. Die Angabe der fatal-exception-classes entfällt, da nun mit include-exclude-Filtern gearbeitet wird. Neben den skippable-exception-classes können noch retryable-exception-classes definiert werden. Im Vergleich zum springframework in der Version 3 ist Spring Batch nicht abwärtskompatibel, so dass bestehende Konfigurationen nicht mehr verwendet werden können. Zusätzlich haben sich auch einige Änderungen am Datenbank-Schema ergeben. Dies stellt aber normalerweise kein Problem dar, da eine Migration der Job-Daten nicht notwendig sein sollte.
In der alten Version wurde als Standard eine item-orientierte Verarbeitung verwendet. Neu ist nun die Zusammenfassung von 1-n items zu einem chunk. Daraus ergibt sich der Vorteil, dass alle Items, die zu einer Transaktion gehören (commit-interval) als Paket an den ItemWriter gereicht werden. Der Entwickler braucht nun nicht mehr die Methoden mark, reset, flush, and clear implementieren, da die Rollback-Logik nun vom Framework selbst übernommen wird.
1<job id="flatFileJob" parent="simpleJob" xmlns="http://www.springframework.org/schema/batch"> 2 <step id="step1" next="step2"> 3 <tasklet> 4 <chunk reader="fileItemReader" writer="itemWriter" commit-interval="5" skip-limit="100"> 5 <streams> 6 <stream ref="fileItemReader" /> 7 </streams> 8 <skippable-exception-classes> 9 <include class="java.lang.Exception"/> 10 <exclude class="org.springframework.beans.factory.BeanCreationNotAllowedException"/> 11 <exclude class="java.lang.IllegalStateException"/> 12 <exclude class="javax.naming.NameNotFoundException"/> 13 </skippable-exception-classes> 14 </chunk> 15 <listeners> 16 <listener ref="loggerListener"/> 17 </listeners> 18 </tasklet> 19 </step> 20 <step id="step2"> 21 <tasklet ref="mailTasklet"/> 22 </step> 23</job>
Für die Nutzung von Platzhaltern muss nicht mehr der Umweg über einen StepExecutionResourceProxy genommen werden. Mit dem eingeführten late-binding von Job-Parametern wird das etwas eleganter gelöst. Die Ausdrücke sind in der Spring Expression Language formuliert, womit sich noch einige weitere nützliche Features ergeben. Die Angabe von scope=“step“ ist wichtig, damit der ApplicationContext den Step jedes Mal neu instanziiert, wenn der Job gestartet wird.
1<bean id="itemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step"> 2 <property name="comments"> 3 <list> 4 <value>#</value> 5 <value>**</value> 6 </list> 7 </property> 8 <property name="resource" value="#{jobParameters['file.name']}"/> 9 <property name="lineMapper" ref="flatFileLineMapper"/> 10</bean>
Für die Transformation der Items wird nun der PatternMatchingCompositeLineTokenizer bzw. PatternMatchingCompositeLineMapper verwendet. Im Vergleich zum PrefixMatchingCompositeLineTokenizer kann man hier mit Patterns arbeiten und ist nicht nur auf das Präfix des Satzes beschränkt, was die Flexibilität deutlich verbessert. Ein weiterer Vorteil ist die Möglichkeit, dass man nun die Tokenizer beliebig den jeweiligen FieldSet-Mappern zuordnen kann, was die Testbarkeit und Kapselung optimiert, insbesondere bei komplexen Datenstrukturen.
1<bean id="flatFileLineMapper" 2 class="org.springframework.batch.item.file.mapping.PatternMatchingCompositeLineMapper"> 3 <property name="tokenizers"> 4 <map> 5 <entry key="10*" value-ref="recordType10" /> 6 <entry key="20*" value-ref="recordType20" /> 7 <entry key="21*" value-ref="recordType21" /> 8 </map> 9 </property> 10 <property name="fieldSetMappers"> 11 <map> 12 <entry key="1*" value-ref="fieldSetMapper1" /> 13 <entry key="2*" value-ref="fieldSetMapper2" /> 14 </map> 15 </property> 16</bean>
Fazit
Das gezeigte Beispiel ist nicht sehr komplex und kann nicht alle Neuerungen/Änderungen beinhalten. Darüber hinaus gibt es verschiedene Arten von Jobs. Es geht hier nicht immer um Dateiverarbeitung 😉 Aber generell lässt sich sagen, dass für die Umstellung ein gewisses Maß an Vorwissen vorhanden sein muss, um die kleinen Hürden erfolgreich zu überwinden. Diese Investition lohnt sich aber, da man mit der 2.1 nicht nur eine stabilere Version hat, sondern man sich auch nochmal Gedanken über die einzelnen Batches macht und vielleicht noch den einen oder anderen Bug oder vorhandene Fehlerquelle dabei ausbaut. Wichtig zu wissen ist allerdings, dass man Spring 3.x im Einsatz haben muss. Für große Infrastrukturen mit vielen Batches würde ich bei der Migration über die Entwicklung eines Skriptes nachdenken, was zumindest die Grundgerüste der XML-Konfigurationen transformiert. Ich als alter COBOL/Host-Entwickler bin wirklich begeistert von dem Framework und ich kann jedem nur ans Herz legen mal einen ausführlichen Blick darauf zu werfen 🙂
Weitere Beiträge
von Dennis Schulte
Dein Job bei codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog-Autor*in
Dennis Schulte
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.