Einstieg in Spring Boot, Teil 12 Arbeiten mit mehreren Systemumgebungen
In der Softwareentwicklung ist es oft erforderlich, mit mehreren Umgebungen zu arbeiten, etwa Entwicklung oder Produktion. Profile in Spring Boot erlauben es, schnell zwischen den entsprechenden Konfigurationen zu wechseln.
Anbieter zum Thema

Verschiedene Systemumgebungen zeichnen sich zum Beispiel durch verschiedene Datenbanken oder Unterschiede in der Authentifizierung aus. So werden während der Entwicklung gerne wartungsarme In-Memory-Datenbanken benutzt oder das Einloggen in die Anwendung für den Entwickler aus Zeitgründen automatisiert. Weitere Unterschiede in den Umgebungen könnten angebundene Systeme wie LDAP-Server oder Tests mit Mock-Objekten betreffen.
Jede dieser Umgebungen kann also grundverschieden aufgebaut sein und erfordert deshalb eine unterschiedliche Konfiguration. In Spring betrifft diese Konfiguration zum einen die Properties in application.properties (oder application.yml) und zum anderen die Konfiguration von Beans.
In der Praxis möchte man natürlich möglichst schnell zwischen den Umgebungskonfigurationen wechseln (und nicht etwa alle Properties in application.properties von Hand anpassen). Wünschenswert wäre, durch Setzen eines einzelnen Parameters mit dem Namen der Umgebung, auf eine andere Properties-Datei zu wechseln und andere Beans in den Spring-Container zu laden. Kein Problem, genau dafür wurden Profile geschaffen!
Property-Dateien in Profilen
Properties wurden im vorhergehenden Beitrag dieser Reihe ausführlich besprochen. Für Spring Boot heißt die Standard-Properties-Datei application.properties (oder application.yml bei Verwendung des YAML-Formats) und liegt im Ordner src/main/resources.
Um eine umgebungsspezifische Variante der Datei zu erstellen, hängt man den Namen der Umgebung als Suffix mit Bindestrich an das application an. Hier heißt die Datei application-prod.properties, der Name des Profils ist also prod. In der Datei wird zu Testzwecken einfach ein anderer Port für eine beliebige Spring Boot-Anwendung festgelegt:
server.port=8081
Ein Start der Anwendung nach diesen Änderungen zeigt, dass die Anwendung nach wie vor auf Port 8080 lauscht. Auch die Log-Meldungen weisen darauf hin, dass das neue Profil noch nicht verwendet wird („No active profile set, falling back to default profiles: default“).
Spring muss offensichtlich noch mitgeteilt werden, dass das neue Profil auch verwendet werden soll. Dazu gibt es verschiedene Möglichkeiten, beispielsweise kann das Profil in der Spring Tool Suite (STS) in der Run-Konfiguration ausgewählt werden.
Nach dem Start mit dem prod-Profil ist die Anwendung nun unter Port 8081 erreichbar und auch im Log wird das gewünschte Profil prod ausgegeben.
Application.properties (ohne Suffix) bleibt übrigens in src/main/resources erhalten. Properties die nur dort konfiguriert sind, werden nach wie vor benutzt. Wenn Eigenschaften in den umgebungsspezifischen Dateien angegeben sind, dann werden diese gezogen. Properties lassen sich also quasi überschreiben.
Beans in Profilen
Beans lassen sich mit der Annotation @Profile mit dem Namen der Umgebung versehen, in der sie aktiv sein sollen. Im folgenden Beispiel wird eine Klasse namens DevPersister für das Profil dev konfiguriert:
@Configuration
@Profile("dev")
public class DevPersister {
@Bean
public Persister databasePersister() {
return new DatabasePersister(DBType.Dev);
}
}
Diese Konfiguration wird also nur bei Verwendung des dev-Profils in den Spring-Container geladen. Die gleiche Konfiguration einer Klasse für das Profil prod sieht dementsprechend wie folgt aus:
@Configuration
@Profile("prod")
public class ProdPersister {
@Bean
public Persister databasePersister() {
return new DatabasePersister(DBType.Prod);
}
}
Je nach aktiviertem Profil findet sich also die eine oder die andere Klasse im Container und in der Folge wird die Klasse DatabasePersister entweder für die Entwicklung oder für die Produktion konfiguriert (hier nur durch den Parameter im Konstruktor angedeutet).
Die Klasse im Beispiel ist mit @Configuration annotiert. @Profile kann man in Konfigurationen und allen Komponenten (also auch Controllern, Services und Repositories) verwenden.
Mit dem Not-Operator (!) lässt sich eine Bean auch gezielt in einem bestimmten Profil deaktivieren. Die Bean ist dann in allen anderen Profilen vorhanden:
@Profile("!dev")
Außerdem ist es möglich, eine Bean für mehrere Profile zu qualifizieren, diese werden dann kommasepariert aufgeführt:
@Profile("dev", "prod")
Aktivieren von Profilen
Es gibt mehrere Möglichkeiten, ein Profil zu aktivieren. Welche davon gewählt wird, hängt von der Art der Anwendung und der Umgebung ab, in der sie ausgeführt wird. Die Auswahl des Profils in der STS-Konfiguration wurde oben schon gezeigt. Während der Entwicklung ist das eine einfache und praktikable Option.
Es ist auch möglich, das aktive Profil in einer Property in application.properties zu setzen, sie heißt spring.profiles.active:
spring.profiles.active=dev
Oder aber man übergibt den Profilnamen als JVM-Systemparameter beim Start der Anwendung:
java -Dspring.profiles.active=dev -jar DemoApplication.jar
Diese Variante hat den Vorteil, dass die Anwendungsdateien nicht mehr angefasst werden müssen, und bietet sich deshalb auf der Produktionsmaschine an. Es gibt weitere Methoden wie die programmatische Registrierung von Profilen oder die Verwendung der Annotation _@ActiveProfiles_ in Tests, die hier aber nur der Vollständigkeit halber erwähnt werden.
Spring-Profile eignen sich perfekt für die Arbeit mit verschiedenen Umgebungen und kaum eine Unternehmensanwendung mit angebundenen Subsystemen kommt ohne sie aus. Die Anwendung lässt sich damit aber auch genauso gut für verschiedene Kunden, Mandanten oder Marken anpassen.
Schnell kommt man auf den Gedanken, dass sich womöglich auch verschiedene Sprachen damit realisieren lassen. Dafür existiert aber eine eigene Lösung, die in einem der nächsten Beiträge vorgestellt wird. Erst einmal widmen wir uns der Frage, wie sichDatenbankabfragen mit dem JDBC-Template erstellen lassen.
(ID:47331416)