Guida a @ConfigurationProperties in Spring Boot

1. Introduzione

Spring Boot ha molte funzioni utili tra cui la configurazione esternalizzata e un facile accesso alle proprietà definite nei file delle proprietà . Un tutorial precedente descriveva vari modi in cui ciò poteva essere fatto.

Esploreremo ora l' annotazione @ConfigurationProperties in maggiore dettaglio.

2. Configurazione

Questo tutorial utilizza una configurazione abbastanza standard. Iniziamo aggiungendo spring-boot-starter-parent come genitore nel nostro pom.xml :

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

Per essere in grado di convalidare le proprietà definite nel file, abbiamo anche bisogno di un'implementazione di JSR-303, e hibernate-validator è uno di questi.

Aggiungiamolo anche al nostro pom.xml :

 org.hibernate hibernate-validator 6.0.16.Final  

La pagina "Guida introduttiva a Hibernate Validator" contiene ulteriori dettagli.

3. Proprietà semplici

La documentazione ufficiale consiglia di isolare le proprietà di configurazione in POJO separati .

Quindi iniziamo facendo questo:

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

Usiamo @Configuration in modo che Spring crei un bean Spring nel contesto dell'applicazione.

@ConfigurationProperties funziona meglio con proprietà gerarchiche che hanno tutte lo stesso prefisso; quindi, aggiungiamo un prefisso di posta .

Il framework Spring utilizza i setter di bean Java standard, quindi dobbiamo dichiarare i setter per ciascuna delle proprietà.

Nota: se non usiamo @Configuration nel POJO, dobbiamo aggiungere @EnableConfigurationProperties (ConfigProperties.class) nella classe principale dell'applicazione Spring per associare le proprietà al POJO:

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

Questo è tutto! Spring collegherà automaticamente qualsiasi proprietà definita nel nostro file di proprietà che abbia il prefisso mail e lo stesso nome di uno dei campi nella classe ConfigProperties .

La primavera usa alcune regole rilassate per legare le proprietà. Di conseguenza, le seguenti variazioni sono tutte associate alla proprietà hostName :

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

Pertanto, possiamo utilizzare il seguente file delle proprietà per impostare tutti i campi:

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

3.1. Spring Boot 2.2

A partire da Spring Boot 2.2, Spring trova e registra le classi @ConfigurationProperties tramite la scansione del percorso di classe . Pertanto, non è necessario annotare tali classi con @Component (e altre meta-annotazioni come @Configuration), o anche utilizzare @EnableConfigurationProperties:

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

Lo scanner del percorso di classe abilitato da @SpringBootApplication trova la classe ConfigProperties , anche se non abbiamo annotato questa classe con @Component.

Inoltre, possiamo utilizzare l' annotazione @ConfigurationPropertiesScan per analizzare le posizioni personalizzate per le classi delle proprietà di configurazione:

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

In questo modo Spring cercherà le classi delle proprietà di configurazione solo nel pacchetto com.baeldung.properties .

4. Proprietà nidificate

Possiamo avere proprietà annidate in elenchi, mappe e classi.

Creiamo una nuova classe Credentials da utilizzare per alcune proprietà annidate:

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

È inoltre necessario aggiornare la classe ConfigProperties per utilizzare una classe List, una mappa e le credenziali :

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 }

Il seguente file delle proprietà imposterà tutti i campi:

#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. Utilizzo @ConfigurationProperties su un @Bean Metodo

Possiamo anche utilizzare il @ConfigurationProperties annotazione @Bean metodi -annotated.

Questo approccio può essere particolarmente utile quando vogliamo associare proprietà a un componente di terze parti che è al di fuori del nostro controllo.

Creiamo una semplice classe Item che useremo nel prossimo esempio:

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

Ora vediamo come possiamo usare @ConfigurationProperties su un @Bean metodo per associare le proprietà esternalizzate alla voce esempio:

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

Di conseguenza, qualsiasi proprietà con prefisso elemento verrà mappata all'istanza Item gestita dal contesto Spring.

6. Convalida della proprietà

@ConfigurationProperties provides validation of properties using the JSR-303 format. This allows all sorts of neat things.

For example, let's make the hostName property mandatory:

@NotBlank private String hostName;

Next, let's make the authMethod property from 1 to 4 characters long:

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

Then the port property from 1025 to 65536:

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

Finally, the from property must match an email address format:

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

This helps us reduce a lot of if – else conditions in our code, and makes it look much cleaner and more concise.

If any of these validations fail, then the main application would fail to start with an IllegalStateException.

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.

Nota che tutti i campi di ImmutableCredentials sono definitivi. Inoltre, non ci sono metodi setter.

Inoltre, è importante sottolineare che per utilizzare l'associazione del costruttore, dobbiamo abilitare esplicitamente la nostra classe di configurazione con @EnableConfigurationProperties o con @ConfigurationPropertiesScan .

9. Conclusione

In questo articolo, abbiamo esplorato l' annotazione @ConfigurationProperties e evidenziato alcune delle funzioni utili che fornisce, come il binding rilassato e la convalida dei bean.

Come al solito, il codice è disponibile su Github.