KAPITEL 1
Spring Boot in a Nutshell
Dieses Kapitel erkundet die drei Kerneigenschaften von Spring Boot und untersucht, wie diese Ihnen als Entwickler zur Seite stehen.
Die drei Grundeigenschaften von Spring Boot
Die drei Kerneigenschaften von Spring Boot, auf denen alles andere aufbaut, sind ein vereinfachtes AbhÀngigkeitsmanagement, ein vereinfachtes Deployment und die Autokonfiguration.
Starter fĂŒr vereinfachtes AbhĂ€ngigkeitsmanagement
Einer der genialen Aspekte von Spring Boot besteht darin, dass es das Dependency- oder AbhÀngigkeitsmanagement handhabbar macht.
Falls Sie bereits einmal ernsthaft Software entwickelt haben, mussten Sie sich bestimmt schon mehrfach den Kopf hinsichtlich des AbhĂ€ngigkeitsmanagements zerbrechen. Jede FĂ€higkeit, die Sie mit Ihrer Anwendung anbieten, erfordert im Vorfeld ĂŒblicherweise eine Reihe von AbhĂ€ngigkeiten. Falls Sie zum Beispiel ein RESTful-Web-API bereitstellen, mĂŒssen Sie eine Möglichkeit zur VerfĂŒgung stellen, Endpoints ĂŒber HTTP anzubieten, auf Anfragen (Requests) zu lauschen, diese Endpoints an Methoden/Funktionen zu binden, die diese Anfragen verarbeiten, um dann passende Antworten (Responses) zu erzeugen und zurĂŒckzuliefern.
Jede primĂ€re AbhĂ€ngigkeit zieht fast zwangslĂ€ufig zahllose weitere sekundĂ€re AbhĂ€ngigkeiten nach sich, um ihre versprochene FunktionalitĂ€t zu erfĂŒllen. Um bei unserem Beispiel eines RESTful-API zu bleiben: Wir können eine Reihe von AbhĂ€ngigkeiten erwarten (in einer vernĂŒnftigen, wenn auch strittigen Struktur), die Code enthalten, der Responses in einem bestimmten Format liefert, z.B. JSON, XML, HTML, Code zum Marshalling/Demarshalling von Objekten in bestimmte Formate, Code zum Lauschen auf und Verarbeiten von Anfragen und zum ZurĂŒckgeben von Antworten auf diese, Code zum Decodieren komplexer URIs, die benutzt werden, um vielseitige APIs zu erzeugen, Code zum UnterstĂŒtzen verschiedener Ăbertragungsprotokolle und mehr.
Selbst fĂŒr dieses relativ einfache Beispiel mĂŒssen wir wahrscheinlich schon mit einer groĂen Anzahl von AbhĂ€ngigkeiten in unserer Build-Datei rechnen. Und wir haben an dieser Stelle noch gar nicht darĂŒber nachgedacht, welche Art FunktionalitĂ€t wir in unsere Anwendung aufnehmen wollen, sondern nur ihre nach auĂen gerichteten Interaktionen betrachtet.
Reden wir nun ĂŒber Versionen und ĂŒber jeder einzelne dieser AbhĂ€ngigkeiten.
Die gemeinsame Benutzung von Bibliotheken erfordert eine gewisse PrÀzision, da es sein kann, dass eine Version einer speziellen AbhÀngigkeit nur mit einer bestimmten Version einer anderen AbhÀngigkeit getestet wurde (oder gar nur mit ihr korrekt funktioniert). Solche Probleme, die unweigerlich auftauchen, bezeichne ich als »AbhÀngigkeits-Whack-a-Mole« (»Hau den Maulwurf«).
Genau wie das namengebende Spiel kann auch AbhÀngigkeits-Whack-a-Mole sehr frustrierend sein. Anders als bei dem Spiel gibt es jedoch keine Preise zu gewinnen, wenn man Bugs, die aus falschen Zuordnungen resultieren, jagt und zerhaut, sondern höchstens seltsame Diagnosen und Stunden, die man mit der Suche nach ihnen verplempert hat.
Doch jetzt kommen Spring Boot und seine Starter. Spring-Boot-Starter sind Bills of Materials (BOMs; also quasi StĂŒcklisten), die aufgrund der erwiesenen Tatsache erstellt werden, dass Sie eine bestimmte Funktion in der Mehrzahl der FĂ€lle auf nahezu dieselbe Weise bereitstellen.
Jedes Mal, wenn wir im oben angefĂŒhrten Beispiel ein API bauen, stellen wir Endpoints bereit, lauschen auf Anfragen, verarbeiten die Anfragen, wandeln Objekte um, tauschen Informationen in verschiedenen Standardformaten aus, senden und empfangen Daten mit einem bestimmten Protokoll ĂŒber die Leitung und mehr. Dieses Muster aus Entwurf/Entwicklung/Benutzung Ă€ndert sich nicht sehr, sondern ist ein branchenĂŒbliches Vorgehen, das so oder so Ă€hnlich verwendet wird. Und wie andere vergleichbare Muster lĂ€sst es sich sehr schön in einem Spring-Boot-Starter festhalten.
Das HinzufĂŒgen eines einzigen Starters, z.B. spring-boot-starter-web, fasst alle dazugehörigen FunktionalitĂ€ten in einer einzigen AnwendungsabhĂ€ngigkeit zusammen. Alle AbhĂ€ngigkeiten, die in diesem einen Starter enthalten sind, sind darĂŒber hinaus versionssynchronisiert. Das heiĂt, sie wurden erfolgreich zusammen getestet, und die enthaltene Version von Bibliothek A funktioniert einwandfrei mit der enthaltenen Version von Bibliothek B ⊠und C ⊠und D und so weiter. Dadurch wird unsere Liste mit den AbhĂ€ngigkeiten und damit unser Leben drastisch vereinfacht, da es ziemlich unwahrscheinlich wird, dass schwer zu identifizierende Versionskonflikte zwischen AbhĂ€ngigkeiten auftreten, die Sie fĂŒr die wichtigen Funktionen Ihrer Anwendung zur VerfĂŒgung stellen mĂŒssen.
In den seltenen FĂ€llen, in denen Sie FunktionalitĂ€t einbauen mĂŒssen, die von einer anderen Version einer enthaltenen AbhĂ€ngigkeit bereitgestellt wird, können Sie die getestete Version einfach ĂŒbergehen.
| Falls Sie sich ĂŒber die vorgegebene Version einer AbhĂ€ngigkeit hinwegsetzen mĂŒssen, dann tun Sie das ⊠allerdings sollten Sie dann wahrscheinlich Ihre Tests ausweiten, um die Risiken auszuschalten, die Sie sich durch Ihr Vorgehen möglicherweise einhandeln. |
Sie können AbhĂ€ngigkeiten, die fĂŒr Ihre Anwendung unnötig sind, auch ausschlieĂen. Dabei gelten allerdings dieselben VorsichtsmaĂnahmen.
Alles in allem rationalisiert das Starter-Konzept von Spring Boot Ihre AbhĂ€ngigkeiten und verringert den Aufwand, der nötig ist, um ganze Gruppen von Fertigkeiten in Ihre Anwendungen einzubauen. Es verringert auĂerdem den fĂŒr Tests, Wartung und Aktualisierung anfallenden Overhead.
AusfĂŒhrbare JARs fĂŒr ein vereinfachtes Deployment
Vor langer, langer Zeit, als Application-Server ĂŒber die Erde streiften, waren Deployments von Java-Anwendungen eine komplexe Angelegenheit.
Um eine funktionierende Anwendung mit z.B. Datenbankzugriff auf den Weg zu bringen â wie bei vielen Microservices heutzutage und fast allen Monolithen damals und heute â, mĂŒssten Sie Folgendes tun:
- Installieren und Konfigurieren des Application-Servers
- Installieren der Datenbanktreiber
- Erzeugen einer Datenbankverbindung
- Erzeugen eines Connection Pools
- Kompilieren und Testen Ihrer Anwendung
- Deployment Ihrer Anwendung und deren (meist zahlreichen) AbhÀngigkeiten auf dem Application-Server
Diese Liste geht ĂŒbrigens davon aus, dass Administratoren die Maschine/virtuelle Maschine fĂŒr Sie konfigurieren und Sie irgendwann einmal unabhĂ€ngig von diesem Prozess die Datenbank erzeugt haben.
Spring Boot stellte einen GroĂteil dieses schwerfĂ€lligen Deployment-Prozesses auf den Kopf und fasste die genannten Schritte zu einem einzigen Schritt zusammen â vielleicht auch zwei, falls Sie das Kopieren oder Verschieben einer einzelnen Datei (mit cf push) als tatsĂ€chlichen Schritt betrachten wollen.
Spring Boot war nicht der Ursprung des sogenannten Ăber-JAR, hat es aber revolutioniert. Anstatt jede Datei aus dem Anwendungs-JAR und allen abhĂ€ngigen JARs herauszukitzeln, sie dann zu einem einzigen Ziel-JAR zu kombinieren â ein Vorgang, der manchmal als Shading bezeichnet wird â, gingen die Entwickler von Spring Boot die Sache von einer ganz neuen Seite an: Was wĂ€re, wenn wir JARs schachteln und dabei ihr vorgesehenes und ĂŒbergebenes Format beibehalten könnten?
Das Schachteln von JARs anstelle des Shading behebt viele potenzielle Probleme, da uns keine etwaigen Versionskonflikte begegnen werden, wenn AbhÀngigkeit JAR A und AbhÀngigkeit JAR B jeweils eine andere Version von C benutzen; es lÀsst auch potenzielle rechtliche Probleme verschwinden, die auftreten, wenn man Software neu packt und sie mit anderer Software kombiniert, die eine andere Lizenz verwendet. BehÀlt man alle abhÀngigen JARs in ihrem Ursprungsformat, dann vermeidet man ganz geschickt diese und andere Probleme.
Es ist auĂerdem trivial, den Inhalt eines ausfĂŒhrbaren JAR in Spring Boot zu extrahieren, sollten Sie dies wĂŒnschen. Unter bestimmten UmstĂ€nden gibt es gute GrĂŒnde dafĂŒr, und ich werde darauf in diesem Buch eingehen. FĂŒr den Augenblick reicht es, zu wissen, dass das ausfĂŒhrbare JAR in Spring Boot fĂŒr Sie da ist.
Das einzelne Spring-Boot-JAR mit all den AbhĂ€ngigkeiten macht das Deployment zu einem Kinderspiel. Anstatt alle AbhĂ€ngigkeiten zu sammeln und sicherzustellen, dass sie deployt werden, sorgt das Spring-Boot-Plug-in dafĂŒr, dass sie in das Ausgabe-JAR eingebunden werden. Ist das erledigt, kann die Anwendung ĂŒberall ausgefĂŒhrt werden, wo es eine Java Virtual Machine (JVM) gibt. Es reicht, dazu einen Befehl wie java -jar <SpringBootAppName.jar> auszufĂŒhren.
Da gibt es aber noch mehr.
Durch Einstellen einer einzigen Eigenschaft in Ihrer Build-Datei kann das Spring-Boot-Build-Plug-in dieses eine JAR vollstĂ€ndig (selbst) ausfĂŒhrbar machen. Immer noch unter der Voraussetzung, dass es eine JVM gibt, mĂŒssen Sie nun nicht die ganze lĂ€stige Zeile java -jar <SpringBootAppName.jar eintippen, sondern können die AusfĂŒhrung mit einem einfachen <SpringBootAppName.jar> erreichen (natĂŒrlich mĂŒssen Sie hier Ihren eigenen Dateinamen einsetzen) â das war es auch schon. Einfacher geht es wirklich nicht.
Autokonfiguration
Die Autokonfiguration, die Spring-Boot-Neulingen manchmal wie Zauberei erscheinen mag, ist vielleicht der gröĂte »Machtmultiplikator«, den Entwickler durch Spring Boot gewinnen. Ich bezeichne sie oft als die Superkraft eines Entwicklers: Spring Boot gibt Ihnen wahnsinnige ProduktivitĂ€t, indem es Meinungen zu weit verbreiteten und oft wiederholten Use Cases Ă€uĂert.
Meinungen in Software? Und das hilft?!?
Wenn Sie schon lange als Entwickler unterwegs sind, dann haben Sie zweifellos bemerkt, dass sich manche Muster oft wiederholen. NatĂŒrlich nicht perfekt, aber zu einem groĂen Teil; vielleicht 80 bis 90 Prozent der Zeit bewegen sich die Dinge in einem bestimmten Bereich aus Design, Entwicklung oder AktivitĂ€t.
Ich habe bereits auf diese Wiederholung in der Software hingedeutet, da sie es ist, die Spring-Boot-Starter so unglaublich konsistent und nĂŒtzlich macht. Wiederholung bedeutet auch, dass sich diese AktivitĂ€ten, wenn wir dann zu dem Code kommen, der zum Erledigen einer bestimmten Aufgabe geschrieben werden muss, hervorragend fĂŒr eine Rationalisierung anbieten.
Um einmal ein Beispiel aus Spring Data zu borgen, ein mit Spring Boot verwandtes und durch Spring Boot ermöglichtes Projekt: Wir wissen, dass wir jedes Mal, wenn wir Zugriff auf eine Datenbank benötigen, irgendeine Art von Verbindung zu dieser Datenbank öffnen mĂŒssen. Wir wissen auĂerdem, dass diese Verbindung geschlossen werden muss, wenn unsere Anwendung ihre Aufgaben erledigt hat, um potenzielle Probleme zu vermeiden. Zwischen dem Ăffnen und SchlieĂen richten wir wahrscheinlich zahlreiche Anforderungen an die Datenbank, fĂŒr die wir Abfragen benutzen â einfache und komplexe, schreibgeschĂŒtzte und schreibbare. Die korrekte Erstellung dieser Abfragen erfordert eine gewisse MĂŒhe.
Stellen Sie sich nun vor, wir könnten all das rationalisieren. Automatisch eine Verbindung öffnen, wenn wir die Datenbank angeben. Automatisch die Verbindung schlieĂen, wenn die Anwendung fertig ist. Einfachen und erwarteten Konventionen folgen, um mit minimalem Aufwand Ihrerseits automatisch Abfragen zu erzeugen. Wieder durch eine einfache Konvention eine einfache Anpassung selbst dieses minimalen Codes erlauben, um komplexe, spezialisierte Abfragen zu erzeugen, die zuverlĂ€ssig konsistent und effizient sind.
Diese Herangehensweise an Code wird manchmal als Konvention vor Konfiguration bezeichnet und kann auf den ersten Blick irritierend wirken, wenn eine bestimmte Konvention Ihnen neu ist. Falls Sie jedoch vorher schon einmal Ăhnliches implementiert haben und viele Hundert Zeilen lang den immer wieder gleichen Setup/Teardown/Konfigurationscode schreiben mussten, um selbst die einfachen Aufgaben zu erledigen, dĂŒrfte dies sehr erfrischend sein. Spring B...