Konfiguration von Spring-Anwendungen

Konfiguration von Spring-Anwendungen

Die Konfiguration von Spring-Anwendungen ist ein elementarer Bestandteil des Frameworks. Damit können auch komplexeste Anforderungen in produktiven Anwendungen umgesetzt werden.

Berücksichtigt werden dabei die folgenden Features:

  • Die eigentliche Konfiguration der Anwendung
  • Die Konfiguration der Laufzeitumgebung sowie deren Überwachung
  • Die Unterstützung verschiedener Profile der Anwendung.

Konfiguration der Anwendung

Bei Spring Boot-Anwendungen wird hierzu automatisch eine Konfigurationsdatei geladen. Dabei werden simple Properties-Dateien (die application.properties)   oder YAML-Dateien (application.yml) unterstützt.

Innerhalb der Anwendung werden Properties mit der @Value-Annotation definiert. Diese lesen über eine Spring Expression einen Wert aus der Konfigurationsdatei:

Profiles

Mit Profiles werden unterschiedliche Stages der Anwendung konfiguriert. Dabei kann jegliche Konfiguration (XML, Annotations oder Java Config) zusätzlich mit der @Profile-Annotation einem benannten Profil zugeordnet werden.

Profile werden innerhalb der Konfiguration oder durch einen Aufruf-Parameter der Anwendung aktiviert.

Die oben bereits angesprochenen Konfigurations-Dateien werden automatisch mit Profiles ergänzt. Existiert beispielsweise ein Profile namens „test“, so wirde neben der application.properties-Datei auch eineapplication-test.propertiesgelesen.

Konfiguration der Laufzeitumgebung

Auch die Laufzeitumgebung der Anwendung kann konsequent in der application-Konfiguration erfolgen. Beispiele hierfür sind

  • Logging
  • Datenbank-URLs
  • Server-Ports
  • Aktive Profile

Im Folgenden Beispiel ist eine Konfiguration für Logging gegeben. Weiterhin wird das aktive Profile gesetzt:

 

Setup für Test-Datenbanken

Wird eine Spring-Boot-Anwendung mit einer Datenbank-Anbindung konfiguriert, so können automatisch Skripte zur Schema-Erstellung sowie zum initialen Befüllen der Tabellen ausgeführt werden. Diese Dateien sind die schema.sql bzw. die data.sql.

Beispiel: Eine schema.sql

Beispiel: Eine data.sql

Auch hier ist wiederum eine Unterscheidung verschiedener Stages möglich. Dies wird jedoch nicht über ein Profil geregelt sonder durch den Eintrag einer Platform in der Anwendungs-Konfiguration. Die folgende Konfiguration zeigt eine komplette Datenbank-Konfiguration für eine Test-Datenbank:

 

Gelesen werden dann die beiden Dateienschema-test.sqlund data-test.sql.

Der Spring Konfigurationsserver

In einer Cloud-basierten Lösung können die Konfigurationsdateien von einem zentralen Server, dem Spring Cloud Config Server, geliefert werden. Die Standard-Implementierung des Spring-Cloud-Projekts liest die Konfigurationswerte einfach aus einem Git-Repository. Werden Änderungen in die Versionsverwaltung gepushed so wird damit die Anwendung neu konfiguriert. Eine wirklich interessante Lösung! Selbstverständlich können die Konfigurationen aber auch klassisch in einer Datenbank oder dem Dateisystem abgelegt werden.


Seminar zum Thema

Weiterlesen

Spring Data

Spring Data

Spring Data ist ein zentrales Projekt des Spring Frameworks und besticht durch seine Einfachheit und Konsistenz. So können selbst komplexe Datenabfragen mit wenigen Zeilen an Quellcode erstellt werden. Insbesondere im Zusammenspiel mit Spring Boot ist es so möglich, mit wenigen Programmzeilen eine komplette Anwendung wie beispielsweise einen Restful WebService zu realisieren.

Eine Übersicht

Der Begriff „Datenabfragen“ ist im Übrigen nicht zufällig so allgemein gewählt: Spring Data selbst definiert nur eine relativ schlanke Abstraktionsschicht auf einen Datenbestand. So besitzen alle Datenobjekte eine eindeutige ID und werden über ein Repository mit  CRUD-Operationen verwaltet.

Alle weiteren Details sind abhängig von der konkret verwendeten Datenbank-Technologie. So unterscheidet sich selbstverständlich ein konkretes JPA-Repository mit einer transaktionsfähigen relationalen Datenbank im Hintergrund von einem Mongo-Repository, bei dem eine Dokumenten-orientierte Datenbank aus dem NoSQL-Umfeld angesprochen wird.

Spring Data Projekte

Die Spring-Entwickler haben damit nicht den Fehler gemacht zu versuchen, jegliche Datenzugriffs-Technologien allgemein zu abstrahieren. Dieser Versuch ist mit der allgemeinen JEE-Connector-Spezifikation bereits misslungen. Statt dessen gruppiert Spring Data verschiedene Implementierungen mit durchaus unterschiedlichen APIs unter einem gemeinsamen Namen.

Die Anzahl der Projekte ist selbst in der offiziellen Spring-Distribution bereits sehr umfassend und wird durch die Community permanent weiter ergänzt.

Gemeinsam ist all diesen Teilprojekten jedoch die grundsätzliche Arbeitsweise: Entitäten werden über ein dynamisch generiertes Repository im Storage abgelegt.

Ein einfaches Beispiel mit Spring Data JPA

Diese Arbeitsweise wird im folgenden Beispiel näher erläutert:

Wir beginnen hierzu mit einer einfachen Daten-Entität:

Zu beachten ist hierbei bereits, dass diese Entität die normalen Annotationen des Java Persistence APIs benutzt. Insbesondere kann @javax.persistence.Id benutzt werden, die Verwendung von @org.springframework.data.annotation.Id ist optional.

Das Repository selber ist für eine einfache Anwendung komplett trivial:

Die Methoden des CrudRepository werden von Spring zur Laufzeit automatisch generiert, so dass das Repository ohne jegliche eigene Programmierung injiziert und sofort benutzt werden kann. Es ist nicht notwendig, das umfangreiche API zu implementieren! Zur Laufzeit generiert Spring hierfür einen generischen Proxy, der die Aufrufe in geeigneter Form an den gekapselten JPA-EntityManager delegiert.

Dies ist übrigens keine Prototyp- oder Dummy-Implementierung! Es ist weder notwendig noch gebräuchlich noch sinnvoll, für den  produktiven Einsatz diese Methoden durch eigene Sequenzen zu ersetzen und damit zu „verbessern“.

Genügen die im Basis-Interface definierten Methoden nicht, können diese durch eigene ergänzt werden. Hierbei werden folgende Möglichkeiten bereitgestellt:

  • Namenskonventionen: Eine Methode mit der Signatur findByLastnameOrderedByHeight(String lastname) kann einfach im Interface deklariert werden. Eine Implementierung ist nicht notwendig, da das im Endeffekt zu generierende JQL-Statement wohl offensichtlich ist.
  • Sollen diese Namenskonvention nicht verwendet werden, kann statt dessen eine Methode beliebiger Signatur mit der @Query-Annotation versehen werden.

    Statt der Annotationen können auch Named Queries der orm.xml benutzt werden.
  • Und schließlich kann das Interface in einer abstrakten Klasse selbst programiert werden. Dabei werden aber selbstverständlich nur die besonders zu behandelnden Fälle implementiert.

Seminar zum Thema

Weiterlesen

Spring Boot

Was ist Spring Boot?

Mit Spring Boot hat die Spring Community eine echte Vereinfachung bei der Erstellung Spring-basierter Anwendung erreicht. Damit können mit wenigen Programmzeilen Prototypen selbst komplexer Anwendungen erstellt werden, die anschließend zum fertigen Produkt konfiguriert werden können. Der Funktionsumfang von Spring Boot umfasst:

  • Build-Management
    • Ein Spring Boot-Projekt kann mit einer simplen Build-Definition gebaut werden.
  • Projekt-Generator
    • Zur Neuanlage eines Projektes kann die Build-Konfiguration mit einem Online-Dienst der Spring-Community erstellt werden.
  • Convention over Configuration und Autoconfiguration
    • Für Rapid Prototyping sind keine Konfigurationsdateien oder Ähnliches vonnöten. Die Anwendung ist nach der Erstellung sofort lauffähig. Dies gilt auch dann, wenn beispielsweise für eine Web-Anwendung ein Server benötigt wird: Die Autoconfiguration startet einfach einen Tomcat auf Port 8080.
  • Externe Konfiguration
    • Für die ausgelieferte Programmversion muss selbstverständlich eine explizite Konfiguration erfolgen, die Autoconfiguration ist hierfür bestenfalls bedingt geeignet. Dazu bietet Spring Boot einen einfachen Mechanismus über Properties- oder YAML-Dateien. Eine Annotation-basierte Konfiguration ist natürlich auch möglich.
  • Monitoring der Runtime
    • Die in Produktion laufende Anwendung wird prnzipiell wie alle Java-Anwendungen über JMX überwacht. Mit dem Spring Actuator werden zusätzliche Metriken hinzugefügt, die via REST-Schnittstelle abgegriffen werden können.

Die einzelnen Funktionen werden im Folgenden detaillierter beschrieben.

Features

 Build Management

Der Build-Prozess einer Spring Boot-Anwendung wird über Gradle oder über Maven definiert. Die Grundideen sind in beiden Systemen die selben und werden hier an einem Maven-Projekt beschrieben:

Als erstes stellt Spring Boot eine Parent-POM zur Verfügung, in der alle (!) möglichen Spring-Dependencies einer Applikation abstrakt deklariert sind:

Ein konkretes POM eines Projekts definiert als Dependencies die Teile des Frameworks, die benutzt werden sollen durch „Starter“. So wird im folgenden Beispiel ein Projekt mit der Spring Core-Komponente sowie der Test-Umgebung definiert:

 

Projekt Generator Spring Initializr

Mit Hilfe des online verfügbaren Projekt-Generators Spring Initializr wird ein POM für ein Projekt sowie eine simple Rahmenanwendung generiert. Die notwendigen Starter können durch eine einfache Oberfläche hinzugefügt werden. Das fertige Projekt wird als Archiv geladen werden.

Convention over Configuration und Autoconfiguration

Eine Spring Boot-Anwendung wird über eine zentrale Einstiegsklasse definiert, die mit @SpringBootApplication annotiert ist.  Damit sind die folgenden Features automatisch aktiviert:

  • Diese Klasse ist automatisch eine @Configuration
  • ComponentScan für alle Unterpakete, so dass automatisch alle @Components gefunden werden
  • Automatisches Laden der application.properties oder alternativ einer application.yaml zur Anwendungs-Konfiguration. Hierin werden Anwendungs-spezifische Konfigurationen definiert, aber auch die restliche Konfiguration (Logging, Ports, URLs…) werden hier zentral gepflegt.
  • Spring-Profile werden unterstützt. So werden Profile-abhängige Konfigurationen wie application-<profile>.properties automatisch erkannt und gemerged.

 

Zusätzlich wird eine Autokonfiguration angeboten, die einiges an Hintergrund-„Magie“ durchführt. Dies sei an einem konkreten Beispiel demonstriert:

  • Die Anwendung benötigt eine Datenbank und deklariert somit in seinem POM den Starter für JDBC.
  • Zusätzlich wird ein Datenbanktreiber angegeben.
  • Jetzt startet die Autokonfiguration und erzeugt automatisch eine DataSource. Dazu wird untersucht, ob der angegebene  Datenbank-Treiber eine Embedded-Konfiguration ermöglicht. Hier sind aktuell H2, Derby und die HSQLDB unterstützt.

Diese Autokonfiguration kann aber beispielsweise auch einen kompletten Jetty-Server konfigurieren und starten. Dazu ist nur der Web-Starter zu inkludieren.

Externe Konfiguration

Die eben besprochene Autoconfiguration ist für Prototyping sehr praktisch. Für reale Anwendungen muss diese jedoch durch explizite Konfiguration ersetzt werden, also beispielsweise den Port des Jetty-Servers oder eine DataSource. Dazu bietet Spring Boot

  • die application.properties
    • spring.datasource.user=Hugo
  • Aufruf-Parameter der Anwendung
    • -Dspring.datasource.user=Hugo
  • Falls zumindest eine DataSource definiert ist wird die Autokonfiguration nicht durchgeführt.

Monitoring

Der Spring-Actuator stellt umfangreiche Informationen via JMX oder über eine REST-Schnittstelle zur Verfügung. Darin werden nicht nur die aktuellen Metriken des Java-Prozesses angezeigt sondern auch beispielsweise das Geflecht der Spring-Beans.

Das Hinzufügen des Actuators erfolgt wie bei Spring Boot üblich durch das Hinzufügen des Starters zum POM. Welche Endpoints aktiviert werden wird in der application.properties definiert.

Ebenso einfach können die Metriken über Jolokia abgegriffen werden.

Fazit

Spring Boot wird zwar als Ergänzung zum Spring-Framework angeboten, ist nach meiner Auffassung aber so überzeugend, dass selbst simple Projekte damit realisiert werden sollten. Selbst wenn „nur“ der Build-Prozess mit Parent Startern benutzt wird, ist der Mehrwert den Aufwand der Einarbeitung in jedem Falle wert. Dies beschreibt ein anderer Artikel zu Spring Boot, darin wird ein RESTful Web Service mit Datenbank-Anbindung programmiert. Die Datenbank-Anbindung mit Spring Data ist Thema eines weiteren Artikels.


Seminar zum Thema

Weiterlesen

Jolokia – Simples Management von Java-Anwendungen

Jolokia – Simples Management von Java-Anwendungen

Mit Hilfe von Jolokia ist das moderne Management von Java-Anwendungen im Vergleich zu einer reinen JMX-Lösung deutlich simpler geworden. Weiterhin ist Jolokia sehr populär und wird von praktisch allen Java-basierten Produkten wie Applikationsservern und Spring Boot-Anwendungen unterstützt.

Eine Übersicht zu JMX

Die Java Management Extension ist die Grundlage jeglicher Überwachung eines Java-Prozesses. Die über das Betriebssystem erfassbaren Metriken (CPU, Speicher, I/O) sind für Java-Anwendungen viel zu grob bzw. messen durch die interne Verwaltung des Hauptspeichers durch die Java Virtual Machine schlicht und ergreifend falsch. Weiterhin stehen relevante Informationen wie die Garbage Collection so nicht zur Verfügung.

Diese Lücke schließt JMX. Dieses ursprünglich als Extension bereitgestellte Framework ist seit langem Bestandteil jeder Java-Installation. Die Grundidee ist, über einen JMX-Agenten quasi beliebige Informationen aus dem Java-Prozess lesen zu können. Dazu wird eine so genannte „Managed Bean“ mit Attributen und Operationen definiert. Auf diese wird durch einen eindeutigen Namen zugegriffen. Das Format dieses Namens, der so genannte ObjectName, ermöglicht eine  hierarchische Struktur und damit auch ein Suchen und Filtern.

Obwohl diese Technik sehr praktisch und auch sehr einfach zu erweitern ist, bleiben im konkreten Einsatz ein paar Fragen offen:

  • Authentifizierung und Verschlüsselung sind in JMX realisiert, aber es fehlt ein Rollen-Konzept. So kann die Sicht auf die Hierarchie der Managed Beans oder der Zugriff auf Bean-Attribute und Operationen nicht eingeschränkt werden.
  • Das Netzwerk-Protokoll ist nicht REST-basiert. Damit ist es relativ kompliziert, Überwachungs- und Orchestrierungssoftware an das JMX-System zu koppeln.

Die Kernfunktionen von Jolokia

Jolokia realisiert diese Anforderungen. Dazu definiert das Framework ein REST-API zum lesenden und schreibenden Zugriff auf das interne JMX-System. Durch die Verwendung des standardisierten http-Protokolls werden die etablierten Security-Mechanismen zur Authentifizierung und Verschlüsselung benutzt. Zusätzlich können in einem Access-Restriktor Rollen-basierte Zugriffsbeschränkungen und Filter definiert werden.

Die Daten der Abfragen werden im JSON-Format geliefert, so dass eine Analyse und Weiterverarbeitung ohne großen Aufwand erfolgen kann. Damit ist die Anbindung an andere System (Monitoring, Orchestrierung) gegeben.

Integration von Jolokia

Für JEE-Applikationsserver stellt Jolokia ein Web-Archiv zur Verfügung. Dieses wird als zusätzliche Anwendung installiert und stellt den Jolokia-Endpunkt zur Verfügung. Authentifizierung und Verschlüsselung übernimmt hierbei der Applikationsserver.

Für Standalone-Anwendungen kann Jolokia über einen Java-Agent eingebunden werden. Dieser startet einen http-Server der Java Runtime. Netzwerk- und Port-Konfiguration erfolgen durch Aufruf-Parameter:

java   -javaagent:jolokia-agent.jar=port=${JAVA_JOLOKIA_PORT},host=0.0.0.0

Auch für Java-Anwendungen im Docker-Container ist Jolokia hervorragend geeignet. Hier muss nur der vom Server bereitgestellte Endpunkt durch ein Port-Mapping freigeschaltet werden.


Seminar zum Thema

Weiterlesen

Git in Integrata-Seminaren – Teil 3

Verwendung von Git in Seminaren

Für Veranstaltungen mit Programmier-Übungen bietet es sich geradezu an, Git in Integrata-Seminaren einzusetzen. Die Vorteile liegen auf der Hand:

  • Referenten haben Zugriff auf die Musterlösung in verschiedenen Ständen und können Verbesserungen bzw. Fehler einspielen.
  • Referenten und Kunden haben für die Seminarinstallation einen simplen Zugriff für die Installation der Musterlösungen.
  • Mit Hilfe von Tags können Versionsstände der Broschüre direkt mit Versionsständen der Übungen verknüpft werden.
  • Die Teilnehmer des Seminars erhalten im Nachgang Zugriff auf die Musterlösungen. Auch hier können Fehler und Verbesserungen jederzeit gepflegt werden.

Repository-Organisation

Nachdem wir uns in Teil 1 mit den Grundlagen von Git und in Teil 2 mit dem Git-Plugin für Eclipse beschäftigt haben konzentrieren wir uns im Folgenden auf die Organisation des Repositories. Für jedes Seminar wird ein eigenes Repository angelegt, hier beispielsweise für das Seminar Docker und Java das Repository org.javacream.training.docker:

Das Repository für das Docker-Training

Das Repository besteht aus drei Branches:

  • initial kann vom Referenten als Ausgangsbasis des Praktikums benutzt werden.
  • master enthält die aktuellen Musterlösungen.
  • develop enthält alle Commits, die den aktuellen Stand des Praktikums definiert haben. Dieser Branch enthält somit alle Zwischenstände und soll die komplette Historie halten.

Neben den Branches existieren Tags, und zwar jeweils in Paaren. Der Name dieser Tags enthält die Versionsnummer der Broschüre:

  • <broschürenversion> tagged den Stand der Musterlösung für diese Broschürenversion
  • <broschürenversion>_initial tagged die, eventuell leere Praktikumsumgebung dieser Broschürenversion.

Die relevanten Stände des Praktikums befinden sich damit in initial und in master bzw. genauer: In den Tags.

Arbeiten im Seminar

Die im Folgenden dargestellte Arbeitsweise verlangt nicht, dass die Teilnehmer Git kennen und verwenden müssen! Nur der Referent nutzt die Möglichkeiten des Versionsverwaltungssystems.

Zur Vorbereitung der Praktikumsumgebung cloned sich der Referent am Einfachsten das gesamte Repository lokal auf seinen Referentenrechner. Dann wird der Tag, der den initialen Stand zur aktuellen Broschüre enthält ausgechecked.

git checkout  <broschürenversion>_initial

Alternativ kann über GitHub für einen Release auch eine Zip-Datei geladen werden.

Egal wie der initiale Stand erzeugt wurde: Dieser wird nun den Teilnehmern zur Verfügung gestellt.

Nun erzeugt sich der Referent an der Stelle dieses Tags einen neuen Branch, der für dieses Seminar verwendet werden soll. Als Namen verwende ich integrata_<startdatum_des_seminars>. Auf diesem Branch wird nun die Musterlösung für das Seminar fortlaufend ergänzt und relevante Stände werden mit sprechenden Commits gesichert. Der Seminarlauf wird somit auf diesem Branch in nachvollziehbarer Form abgebildet. Die Sourcen für die Muster können dem master-Branch entnommen werden. Zwischenstände findet der Referent bei Bedarf im develop-Branch. Dieser enthält ja alle jemals als relevant erachteten Stände.

Am Ende des Seminars befindet sich der Seminar-Branch auf dem Stand der Lösung für die durchgeführte Schulung. Dieser Stand muss selbstverständlich nicht exakt der Musterlösung entsprechen! Ganz im Gegenteil kann der Referent hier eigene Lösungswege gehen, Vertiefungen einführen oder aber auch nachrangige Themen weglassen.

Ressourcen für die Teilnehmer

Am Ende des Seminars erhalten die Teilnehmer

  • Den Ausgangsstand,
  • die in der Broschüre verwendete Musterlösung, also den Stand mit dem korrespondierenden Tag,
  • den Seminar-Stand.

Die ersten  beiden werden als Zip-Dateien verteilt, letzteres sinnvoll als Git-Repository: Die Teilnehmer sollen ja bei Bedarf auch die Zwischenstände nachvollziehen können. Die hierfür notwendigen Kenntnisse von Git sollten vorausgesetzt werden können oder werden vom Referenten kurz vermittelt. Hierzu kann vom Teilnehmer beispielsweise Eclipse mit dem Git-Plugin benutzt werden, wie es im zweiten Teil dieser Serie beschrieben wurde.

Ressourcen für den Seminar-Verantwortlichen

Sind im Rahmen des Seminars Verbesserungen, kreative Ideen oder Fehlerbehebungen erfolgt, so wird der Seminar-Branch als Git-Repository dem Seminar-Verantwortlichen zur Verfügung gestellt. Dies erfolgt aktuell über einen Filetransfer per Mail oder ähnlichem.

 

Seminare zum Thema

Weiterlesen