Anleitung zu @ConfigurationProperties im Spring Boot

1. Einleitung

Spring Boot bietet viele nützliche Funktionen, einschließlich der externen Konfiguration und des einfachen Zugriffs auf Eigenschaften, die in Eigenschaftendateien definiert sind . In einem früheren Tutorial wurden verschiedene Möglichkeiten beschrieben, wie dies durchgeführt werden kann.

Wir werden jetzt die Annotation @ConfigurationProperties genauer untersuchen.

2. Setup

Dieses Tutorial verwendet ein ziemlich standardmäßiges Setup. Wir beginnen damit, Spring-Boot-Starter-Parent als Parent in unserer pom.xml hinzuzufügen :

 org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE  

Um in der Datei definierte Eigenschaften validieren zu können, benötigen wir auch eine Implementierung von JSR-303, und der Hibernate-Validator ist eine davon.

Fügen wir es auch unserer pom.xml hinzu :

 org.hibernate hibernate-validator 6.0.16.Final  

Weitere Informationen finden Sie auf der Seite „Erste Schritte mit dem Hibernate Validator“.

3. Einfache Eigenschaften

In der offiziellen Dokumentation wird empfohlen, die Konfigurationseigenschaften in separate POJOs zu isolieren .

Beginnen wir also damit:

@Configuration @ConfigurationProperties(prefix = "mail") public class ConfigProperties { private String hostName; private int port; private String from; // standard getters and setters }

Wir verwenden @Configuration, damit Spring im Anwendungskontext eine Spring Bean erstellt.

@ConfigurationProperties funktioniert am besten mit hierarchischen Eigenschaften, die alle dasselbe Präfix haben. Daher fügen wir ein Mail- Präfix hinzu.

Das Spring-Framework verwendet Standard-Java-Bean-Setter, daher müssen wir Setter für jede der Eigenschaften deklarieren.

Hinweis: Wenn wir @Configuration im POJO nicht verwenden, müssen wir @EnableConfigurationProperties (ConfigProperties.class) in der Hauptanwendungsklasse von Spring hinzufügen , um die Eigenschaften an das POJO zu binden:

@SpringBootApplication @EnableConfigurationProperties(ConfigProperties.class) public class EnableConfigurationDemoApplication { public static void main(String[] args) { SpringApplication.run(EnableConfigurationDemoApplication.class, args); } }

Das ist es! Spring bindet automatisch alle in unserer Eigenschaftendatei definierten Eigenschaften, die das Präfix mail und denselben Namen wie eines der Felder in der ConfigProperties- Klasse haben .

Spring verwendet einige entspannte Regeln für die Bindungseigenschaften. Infolgedessen sind die folgenden Variationen alle an die Eigenschaft hostName gebunden :

mail.hostName mail.hostname mail.host_name mail.host-name mail.HOST_NAME 

Daher können wir die folgende Eigenschaftendatei verwenden, um alle Felder festzulegen:

#Simple properties [email protected] mail.port=9000 [email protected] 

3.1. Spring Boot 2.2

Ab Spring Boot 2.2 findet und registriert Spring @ ConfigurationProperties- Klassen über das Scannen von Klassenpfaden . Daher ist es nicht erforderlich, solche Klassen mit @Component (und anderen Meta-Annotationen wie @Configuration) zu kommentieren oder die @EnableConfigurationProperties zu verwenden:

@ConfigurationProperties(prefix = "mail") public class ConfigProperties { private String hostName; private int port; private String from; // standard getters and setters } 

Der von @SpringBootApplication aktivierte Klassenpfad-Scanner findet die ConfigProperties- Klasse, obwohl wir diese Klasse nicht mit @Component kommentiert haben.

Darüber hinaus können wir die Annotation @ConfigurationPropertiesScan verwenden , um benutzerdefinierte Speicherorte nach Konfigurationseigenschaftsklassen zu durchsuchen :

@SpringBootApplication @ConfigurationPropertiesScan("com.baeldung.configurationproperties") public class EnableConfigurationDemoApplication { public static void main(String[] args) { SpringApplication.run(EnableConfigurationDemoApplication.class, args); } }

Auf diese Weise sucht Spring nur im Paket com.baeldung.properties nach Konfigurationseigenschaftsklassen .

4. Verschachtelte Eigenschaften

Wir können verschachtelte Eigenschaften in Listen, Karten und Klassen haben.

Erstellen wir eine neue Klasse für Anmeldeinformationen , die für einige verschachtelte Eigenschaften verwendet werden soll:

public class Credentials { private String authMethod; private String username; private String password; // standard getters and setters }

Wir müssen auch die aktualisieren ConfigProperties Klasse eine verwenden , List, eine Karte , und die Credentials Klasse:

public class ConfigProperties { private String host; private int port; private String from; private List defaultRecipients; private Map additionalHeaders; private Credentials credentials; // standard getters and setters }

Die folgende Eigenschaftendatei legt alle Felder fest:

#Simple properties [email protected] mail.port=9000 [email protected] #List properties mail.defaultRecipients[0][email protected] mail.defaultRecipients[1][email protected] #Map Properties mail.additionalHeaders.redelivery=true mail.additionalHeaders.secure=true #Object properties mail.credentials.username=john mail.credentials.password=password mail.credentials.authMethod=SHA1

5. Verwenden von @ConfigurationProperties für eine @ Bean- Methode

Wir können auch die Verwendung @ConfigurationProperties Anmerkung auf @Bean -annotated Methoden.

Dieser Ansatz kann besonders nützlich sein, wenn wir Eigenschaften an eine Komponente eines Drittanbieters binden möchten, die außerhalb unserer Kontrolle liegt.

Erstellen wir eine einfache Item- Klasse, die wir im nächsten Beispiel verwenden werden:

public class Item { private String name; private int size; // standard getters and setters }

Nun wollen wir sehen, wie wir @ConfigurationProperties für eine @ Bean- Methode verwenden können, um externalisierte Eigenschaften an die Item- Instanz zu binden :

@Configuration public class ConfigProperties { @Bean @ConfigurationProperties(prefix = "item") public Item item() { return new Item(); } }

Folglich wird jedes Element-Präfix Eigenschaft auf die abgebildet werden Artikel Instanz vom Frühjahr Kontext verwaltet.

6. Eigenschaftsüberprüfung

@ConfigurationProperties ermöglicht die Validierung von Eigenschaften im JSR-303-Format. Dies ermöglicht alle möglichen netten Dinge.

Lassen Sie uns beispielsweise die Eigenschaft hostName obligatorisch machen:

@NotBlank private String hostName;

Als nächstes machen wir die authMethod- Eigenschaft von 1 bis 4 Zeichen lang:

@Length(max = 4, min = 1) private String authMethod;

Dann die Hafeneigenschaft von 1025 bis 65536:

@Min(1025) @Max(65536) private int port; 

Schließlich muss die from- Eigenschaft mit einem E-Mail-Adressformat übereinstimmen:

@Pattern(regexp = "^[a-z0-9._%+-][email protected][a-z0-9.-]+\\.[a-z]{2,6}$") private String from; 

Dies hilft uns, viele if - else - Bedingungen in unserem Code zu reduzieren und lässt ihn viel sauberer und prägnanter aussehen.

Wenn eine dieser Überprüfungen fehlschlägt, kann die Hauptanwendung nicht mit einer IllegalStateException gestartet werden .

The Hibernate Validation framework uses standard Java bean getters and setters, so it's important that we declare getters and setters for each of the properties.

7. Property Conversion

@ConfigurationProperties supports conversion for multiple types of binding the properties to their corresponding beans.

7.1. Duration

We'll start by looking at converting properties into Duration objects.

Here we have two fields of type Duration:

@ConfigurationProperties(prefix = "conversion") public class PropertyConversion { private Duration timeInDefaultUnit; private Duration timeInNano; ... }

This is our properties file:

conversion.timeInDefaultUnit=10 conversion.timeInNano=9ns

As a result, the field timeInDefaultUnit will have a value of 10 milliseconds, and timeInNano will have a value of 9 nanoseconds.

The supported units are ns, us, ms, s, m, h and d for nanoseconds, microseconds, milliseconds, seconds, minutes, hours, and days, respectively.

The default unit is milliseconds, which means if we don't specify a unit next to the numeric value, Spring will convert the value to milliseconds.

We can also override the default unit using @DurationUnit:

@DurationUnit(ChronoUnit.DAYS) private Duration timeInDays;

This is the corresponding property:

conversion.timeInDays=2

7.2. DataSize

Similarly, Spring Boot @ConfigurationProperties supports DataSize type conversion.

Let's add three fields of type DataSize:

private DataSize sizeInDefaultUnit; private DataSize sizeInGB; @DataSizeUnit(DataUnit.TERABYTES) private DataSize sizeInTB;

These are the corresponding properties:

conversion.sizeInDefaultUnit=300 conversion.sizeInGB=2GB conversion.sizeInTB=4

In this case, the sizeInDefaultUnit value will be 300 bytes, as the default unit is bytes.

The supported units are B, KB, MB, GB, and TB. We can also override the default unit using @DataSizeUnit.

7.3. Custom Converter

We can also add our own custom Converter to support converting a property to a specific class type.

Let's add a simple class Employee:

public class Employee { private String name; private double salary; }

Then we'll create a custom converter to convert this property:

conversion.employee=john,2000

We will convert it to a file of type Employee:

private Employee employee;

We will need to implement the Converter interface, then use @ConfigurationPropertiesBinding annotation to register our custom Converter:

@Component @ConfigurationPropertiesBinding public class EmployeeConverter implements Converter { @Override public Employee convert(String from) { String[] data = from.split(","); return new Employee(data[0], Double.parseDouble(data[1])); } }

8. Immutable @ConfigurationProperties Binding

As of Spring Boot 2.2, we can use the @ConstructorBinding annotation to bind our configuration properties.

This essentially means that @ConfigurationProperties-annotated classes may now be immutable.

@ConfigurationProperties(prefix = "mail.credentials") @ConstructorBinding public class ImmutableCredentials { private final String authMethod; private final String username; private final String password; public ImmutableCredentials(String authMethod, String username, String password) { this.authMethod = authMethod; this.username = username; this.password = password; } public String getAuthMethod() { return authMethod; } public String getUsername() { return username; } public String getPassword() { return password; } }

As we can see, when using @ConstructorBinding, we need to provide the constructor with all the parameters we'd like to bind.

Beachten Sie, dass alle Felder von ImmutableCredentials endgültig sind. Es gibt auch keine Setter-Methoden.

Darüber hinaus ist es wichtig zu betonen, dass wir zur Verwendung der Konstruktorbindung unsere Konfigurationsklasse entweder mit @EnableConfigurationProperties oder mit @ConfigurationPropertiesScan explizit aktivieren müssen .

9. Fazit

In diesem Artikel haben wir die Annotation @ConfigurationProperties untersucht und einige der nützlichen Funktionen hervorgehoben, die sie bietet, wie z. B. entspanntes Binden und Bean-Validierung.

Wie üblich ist der Code auf Github verfügbar.