Die Stiefel zweimal fest geschnürt

Spring Boot 2 – eine Einführung: Aktuelle Abhängigkeiten & die Grundlage Spring 5

Michael Simons

© Shutterstock.com / GraphicsRF

Neue Themen, neue Funktionen aber auch einiges an Arbeit im Gepäck: Mit Spring Boot 2 läuten die Entwickler von Pivotal eine neue Generation der Konvention-vor-Konfiguration-Lösung für das Erstellen von Spring-Anwendungen ein. In dieser Artikelserie gibt Michael Simons, Senior Consultant bei innoQ Deutschland, eine umfassende Einführung in die Grundlagen und die Neuigkeiten der neuen Version von Spring Boot.

Michael Simons ist nicht nur Speaker auf der JAX 2018, sondern auch Autor des Buches „Spring Boot – Moderne Softwareentwicklung im Spring Ökosystem“, das beim dpunkt.verlag erschienen ist.

Spring Boot 2: Viele aktualisierte Abhängigkeiten

Spring Boot hat in den vergangenen drei Jahren frischen Wind in die Spring- und auch die Java-EE-Welt (jetzt Jakarta EE – Anm. der Redaktion) gebracht. Das Projekt war und ist kein neues Framework, sondern eine umfassende Lösung, die Abhängigkeitsmanagement, den Build und vieles andere erheblich vereinfacht. Es kann getrost postuliert werden, dass neue Spring-Projekte in der Regel mit Spring Boot umgesetzt werden sollen – unabhängig davon, ob Microservices oder Monolithen entstehen.

Ende September 2017 erschien die fünfte Generation des Spring Frameworks, heute soll aller Voraussicht nach Spring Boot 2 erscheinen. Upgrades der zentralen Abhängigkeiten, insbesondere dem Spring Framework selber aber auch Spring Security, sowie größere Refactorings und Aufräumarbeiten bringen neue Themen, neue Funktionen aber auch einiges an Arbeit mit sich. Diese Artikelserie beleuchtet einige davon.

Versionsupdates

Spring 5 und Spring Boot 2 setzen einheitlich Java 8 voraus. Das ermöglicht die Nutzung von Java-8-Funktionen im Kern. Dazu gehören Default-Methoden auf Interfaces und die damit einhergehende Deprecation von etlichen AbstractXXXConfigurer-Klassen, Nullable-Support und mehr.

Alle Java-EE-Spezifikationen, die auch in Spring genutzt werden, wurden auf Java EE 7 gehoben. Während Spring Boot 1 die letzte Spring-Boot-Version ist, die Java 7 unterstützt, wird Spring Boot 2 die erste Version sein, die auf Java 9 (und ab März dann vorausichtlich auf Java 10) lauffähig ist. Damit gehen dann auch etliche Upgrades grundlegender Abhängigkeiten, zum Beispiel zu Tomcat, Hibernate und Gradle einher. Die vollständige Liste finden Sie in der Spring Boot Bill of Materials (BOM).

HTTP/2-Support

Ein Highlight von Spring Boot 2 ist der fast automatisch verfügbare HTTP/2-Support: Die genutzten Versionen von Tomcat, Jetty, Undertow und Reactor Netty unterstützen HTTP/2 „out-of-the-box“. Die Konfiguration ist denkbar einfach: Das Server-Zertifikat muss mit Properties unter server.ssl.* konfiguriert werden, anschließend kann HTTP/2 via server.http2.enabled aktiviert werden. HTTP/2 ist ein wichtiger Baustein für ein schnelleres Web. Latenzen können mit Kompression von Header, Server-Push, Request-Pipelines und Multiplexing von Requests drastisch reduziert werden.

Aktuelle Versionen von Spring-Projekten

Zu den von Spring Boot verwalteten Abhängigkeiten gehören natürlich auch andere Spring Projekte, insbesondere Spring selber, aber auch Spring Data und Spring Security. Im Gegensatz zum Spring Cloud Stack sind diese Teil der Spring Boot BoM und ein Update auf Spring Boot 2 aktualisiert diese ebenfalls. Während das Update auf Spring Boot in den meisten Fällen wohl eher unproblematisch ist, so erweisen sich Änderungen in den Upstream-Projekten oftmals eher als kritisch. Bevor wir also auf spezifische Themen von Spring Boot 2 eingehen, stelle ich in diesem ersten Teil zunächst die neue Grundlage vor, also das Spring Framework 5 und dessen Highlights.

Lesen Sie auch: Spring 5 ist da! Frühling für Enterprise Java

Spring 5: Die Grundlage von Spring Boot 2 und seinen Modulen

Ende September 2017 erschien die fünfte Generation des Spring Frameworks. Spring 5 ist Grundlage für die meisten der in Spring Boot kuratierten Frameworks und schafft die Grundlagen für das Thema „Reaktive Programmierung“.

Reaktive Programmierung mit Spring 5

Ein dominierendes Thema von Spring 5 ist das reaktive Programmiermodell. Reaktive Programmierung ist kein neues Thema und auch kein Alleinstellungsmerkmal von Spring 5 und Spring Boot 2. Das Flow-API von Java 9 und Implementierungen wie Project Reactor und ReactiveX stellen Basistechnologien bereit, während Frameworks wie Vert.x vollständig dem reaktiven Programmiermodell folgen.

Spring 5 wählt einen anderen Ansatz und stellt das reaktive Programmiermodell parallel zum vorhandenem Ansatz bereit. Angefangen vom häufigen Einstiegspunkt, dem Web-Frontend über Security bis hin zum Datenspeicher gibt es nicht-blockierende Alternativen. Damit steht ein Weg bereit, der auch in Organisationen zu bewältigen ist, die sich nicht allzu weit von einem bekannten Stack entfernen möchten.

Das Kernthema reaktiver Programmierung sind nicht schnellere Anwendungen, sondern robustere und ressourcenschonendere Bausteine von Systemen – ein elementares Ziel in Zeiten, in denen Anwendungen oftmals nur kleine Bausteine innerhalb eines großen Systems sind. Das Reactive Manifest definiert reaktive Anwendungen als „elastisch, robust, jederzeit antwortbereit und nachrichtenorientiert.“

Erreicht werden diese Ziele unter anderem dadurch, dass Springs reaktive Infrastruktur keine Threads mehr exklusiv blockiert. Langlebige, teilweise langsame Verbindungen belegen also nicht mehr dauerhaft Ressourcen. Der Speicherverbrauch kann durch Datenverarbeitung auf Basis von Datenströmen reduziert werden. Ergebnisse werden nicht am Stück, sondern Elementweise verarbeitet.

Mono und Flux

In einigen der folgenden Beispiele werden die Klassen Mono und Flux genutzt. Sie sind beide Implementierungen eines Publisher des Flow-APIs und stellen Sequenzen von Dingen dar, die entlang eines Zeitstrahls passieren, beziehungsweise veröffentlicht werden. Die Verarbeitung erfolgt dabei asynchron und ist zu Ende, wenn ein ein Publisher keine weiteren Elemente mehr anbietet. Durch Operatoren entstehen neue Publisher. Ein Mono veröffentlich dabei 0 oder 1, ein Flux n Elemente. Abbildung 1 zeigt die Darstellung eines Flux. Diagramme dieser Art werden auch als Marble-Diagramm bezeichnet.

Abb. 1: Zeitleiste eines Flux‘

Spring WebFlux

Vorweg sei noch einmal deutlich gesagt, dass das neue Spring-WebFlux-Modul nur das „Gesicht“ reaktiver Programmierung mit Spring ist. Reactive zieht sich durch etliche Spring-Module bis in Spring Core. Spring WebFlux steht als Alternative zum klassischen Spring Web MVC zur Verfügung, wie Abbildung 2 zeigt.

Abb. 2: Spring WebFlux als Alternative zu Spring Web MVC

Natürlich steht für WebFlux mit org.springframework.boot:spring-boot-starter-webflux ein entsprechender Starter zur Verfügung, der unter anderem automatisch @EnableWebFlux definiert. Die transitiven Abhängigkeiten des Starters werden benötigt, unabhängig davon, ob das klassische oder funktionale Programmiermodell für WebFlux eingesetzt wird.

Klassisch

Deutlich sichtbar ist die Tatsache, die klassischen Spring-Web-MVC-Annotationen @Controller und @RequestMapping auch für WebFlux zur Verfügung stehen. Das erleichtert den Einstieg und ein reaktiver Spring-Controller könnte wie in Listing 1 aussehen:

@RestController
public class DemoRestController {
    @GetMapping("/helloworld")
    public Mono getGreeting(
        @RequestParam(defaultValue = "World") String name
    ) {
        return Mono.just("Hello")
            .flatMap(s -> Mono
                .just(s + ", " + name + "!\n")
            );
    }
}

Ein asynchrones, nicht-blockierendes „Hello, World“. Die Spring-Infrastruktur und auch die automatische Konfiguration in Spring Boot wurde neu geschnitten.HandlerMapping und HandlerAdapter nutzen nun entweder die klassischen Mechanismen HttpServletRequest und HttpServletResponse oder die reaktiven ServerHttpRequest und ServerHttpResponse. WebFlux ist lauffähig auf allen Servlet 3.1 Containern, die das Non-Blocking IO API unterstützen, aber auch auf anderen, asynchronen Laufzeitumgebungen wie Netty und Undertow. Als Basis-Technologie für die Stream-Verarbeitung wird Project-Reactor genutzt. Sie können allerdings auch alternativ RxJava konfigurieren und nutzen.

In einer Spring-Boot-2-Anwendung, die den Starter spring-boot-starter-webflux nutzt, funktioniert der Controller in Listing 1 out-of-the-box. Spring Boot verwendet dann standardmäßig Netty. Spring 5 kann weiterhin auch ohne Spring Boot genutzt werden, der passende Server ist dann programmatisch zu registrieren.

Funktional
Annotationen sind nicht universal beliebt. Im Rahmen von Spring 5 und dem reaktiven Programmiermodell wird auch dieses Thema behandelt und eine weitere Möglichkeit bereitgestellt, einen Spring-Kontext zu konfigurieren. Listing 2 zeigt eine alternative Möglichkeit, Handler und Routen vollständig ohne Annotationen zu definieren.

public class DemoFunctionalProgrammingModel {
    public static void main(String...a) {

        HandlerFunction helloWorld =
            request -> ServerResponse.ok().body(
                Mono.just("Hello, World"), String.class
            );


        RouterFunction helloSpringRoute =
            request ->  {
                if(request.method() == GET &&
                    request.path().equals("/hellospring")
                ) {
                    return Mono.just(r ->
                        ok().body(
                            Mono.just("Functional Spring"),
                            String.class
                        )
                    );
                } else {
                    return Mono.empty();
                }
            };

        RouterFunction helloWorldRoute =
            RouterFunctions.route(
                GET("/helloworld"), helloWorld);

        RouterFunction routes = helloSpringRoute
            .and(helloWorldRoute);

        HttpHandler httpHandler = RouterFunctions
            .toHttpHandler(routes);
        HttpServer.create(8080)
            .newHandler(new ReactorHttpHandlerAdapter(httpHandler))
            .block();

        CountDownLatch latch = new CountDownLatch(1);
        Thread awaitThread = new Thread(() -> {
            try {
                latch.await();
            } catch (InterruptedException ex) {
            }

        });
        awaitThread.setDaemon(false);
        awaitThread.start();
    }
}

Während das funktionale Routing von Requests nur für Spring WebFlux zur Verfügung steht, kann die funktionale Bean-Registrierung im gesamten Kontext genutzt werden. Aus der Klasse GenericApplicationContext stammt registerBean. Die Methode nimmt nun Java 8 Supplier entgegen: context.registerBean(MyService.class, MyService::new);

Reaktive Clients, Tests

Im obigen Schnelldurchgang wurde der neue WebClient unterschlagen, der das AsyncRestTemplate mittelfristig ablösen wird. Das RestTemplate an sich bleibt bestehen. Die neue Infrastruktur ist als @WebFluxTest-Slice vollständig testbar.

Nur noch WebFlux?

Das auf der Servlet-Spezifikation basierende Spring MVC Framework wird weiterhin First-Class-Unterstützung erhalten, bestehende Anwendungen müssen nicht grundlos auf WebFlux umgeschrieben werden. Aktuell profitieren Anwendungen, die blockierende APIs wie JPA oder JDBC nutzen, nicht von WebFlux. Anwendungen, für deren Stack durchgehend nicht-blockierende Protokolle und Treiber zur Verfügung stehen, erhalten einen vollständig nicht-blockierenden Stack.

Lesen Sie auch: Sicher in die Cloud mit Angular und Spring

Kotlin-Extensions

Richtig interessant werden Router-Funktionen, funktionale Bean-Registrierung und andere Kleinigkeiten zusammen mit Springs neuem, offiziellem Support für Kotlin. Listing 3 zeigt eindrucksvoll, dass eine Spring-Boot-Anwendung nicht mehr nach Spring aussehen muss und vollständig auf Annotationen und XML verzichten kann. In der Klasse Handler manifestiert sich die Anwendung, die Klasse Router bildet URLs auf die Funktionen der Handler ab und nutzt dazu die spezielle DSL router. Ähnliches wird für die Bean-Registrierung mit beans zur Verfügung gestellt.

class Handler {
    fun sayHello(req: ServerRequest) =
            ok().body(
                    Mono.just("Hello, ${req.queryParam("name").orElse("World")}"),
                    String::class.java
            )

    fun andGoodbye(req: ServerRequest) =
            ok().body(
                    Mono.just("Goodbye"),
                    String::class.java
            )
}

class Router(val handler: Handler) {
    fun routes() = router {
        ("/greetings" and accept(TEXT_HTML)).nest {
            GET("/hello", handler::sayHello)
            GET("/goodbye", handler::andGoodbye)
        }
    }
}

fun beans() = beans {
    bean()
    bean {
        Router(ref()).routes()
    }
}

@SpringBootApplication
class Application

fun main(args: Array) {
    runApplication(*args)
}

Natürlich gilt auch hier das Gleiche, das seit Jahren für Spring- und andere Anwendungen gilt: Frameworkspezifische Annotationen und Klassen haben nur selten etwas in fachlichen Klassen verloren. Die Controller in den hier gezeigten Beispielen verarbeiten Daten direkt; in jeder realistischen Applikation sollten nach wie vor Anwendungs- und Serviceschicht getrennt werden.

Im nächsten Teil gehe ich auf Änderungen in den Projekten Spring Data und Spring Security ein. Diese werden mit einiger Sicherheit auch Ihre Anwendungen bei der Aktualisierung von Spring Boot 1 auf Spring Boot 2 betreffen und teilweise eine aktive Migration erfordern.

Spring Boot – Moderne Softwareentwicklung im Spring Ökosystem

Das Spring-Boot-Buch erscheint im Januar 2018 und wird alle aktuellen Themen rund um Spring Boot 2 beinhalten. Dazu gehören neben dem reaktiven Programmiermodell mit Spring 5 auch die neue Actuator-Infrastruktur, der Support von Micrometer.io und vieles mehr.

Dieses Buch soll interessierte Entwickler aus dem Java-EE-Bereich ebenso wie Spring-Entwickler ansprechen und ihnen ein „Rezept“ an die Hand geben, immer wiederkehrende Aufgaben aus dem fachlichen Alltag elegant und ohne Ablenkung mit Spring Boot abzuwickeln.

Weitere Informationenen zum Buch gibt es hier!

Geschrieben von
Michael Simons
Michael Simons
Michael Simons arbeitet als Senior Consultant bei innoQ Deutschland. Er ist Mitglied des NetBeans Dream Teams und Gründer der Euregio JUG. Michael schreibt auf seinem Blog über Java, Spring und Softwarearchitektur. Auf Twitter ist er unterwegs als @rotnroll666, wo er sich unter anderem mit Java, Musik und den kleineren und größeren Problemen als Ehemann und Vater von zwei Kindern beschäftigt. Im Januar 2018 wird Michaels Buch "Spring Boot -- Moderne Softwareentwicklung im Spring-Ökosystem" im dpunkt.verlag erscheinen. Das Buch ist bereits heute unter springbootbuch.de vorbestellbar. Es behandelt Spring Boot 2 und das neue, reaktive Programmierparadigma von Spring 5 ebenso wie Spring-Grundlagen und spricht damit erfahrene Spring-Entwickler wie auch Spring-Neulinge an. Die Schaubilder in diesem Artikel stammen ebenso aus dem Buch, genau wie einige der gezeigten Beispiele. Der Code ist ist bereits jetzt auf GitHub verfügbar.
Kommentare

Hinterlasse einen Kommentar

2 Kommentare auf "Spring Boot 2 – eine Einführung: Aktuelle Abhängigkeiten & die Grundlage Spring 5"

avatar
400
  Subscribe  
Benachrichtige mich zu:
trackback

[…] Aktuelle Abhängigkeiten & die Grundlage Spring 5 […]

Benjamin Toth
Gast

Sehr guter Beitrag, habe mir auch das entsprechende Buch gekauft (Spring Boot2), wirklich sehr gelungen!