Panduan untuk @ConfigurationProperties di Spring Boot

1. Perkenalan

Spring Boot memiliki banyak fitur berguna termasuk konfigurasi eksternal dan akses mudah ke properti yang ditentukan dalam file properti . Tutorial sebelumnya menjelaskan berbagai cara untuk melakukannya.

Sekarang kita akan mempelajari anotasi @ConfigurationProperties secara lebih mendetail.

2. Penyiapan

Tutorial ini menggunakan pengaturan yang cukup standar. Kami mulai dengan menambahkan spring-boot-starter-parent sebagai induk di pom.xml kami :

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

Untuk dapat memvalidasi properti yang ditentukan dalam file, kita juga membutuhkan implementasi JSR-303, dan hibernate-validator adalah salah satunya.

Mari tambahkan juga ke pom.xml kita :

 org.hibernate hibernate-validator 6.0.16.Final  

Halaman "Memulai dengan Hibernate Validator" memiliki detail lebih lanjut.

3. Properti Sederhana

Dokumentasi resmi menyarankan agar kami mengisolasi properti konfigurasi ke dalam POJO terpisah .

Jadi mari kita mulai dengan melakukan itu:

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

Kami menggunakan @Configuration sehingga Spring membuat kacang Spring dalam konteks aplikasi.

@ConfigurationProperties berfungsi paling baik dengan properti hierarki yang semuanya memiliki awalan yang sama; oleh karena itu, kami menambahkan awalan email .

Framework Spring menggunakan bean setter Java standar, jadi kita harus mendeklarasikan setter untuk setiap propertinya.

Catatan: Jika kita tidak menggunakan @Configuration di POJO, maka kita perlu menambahkan @EnableConfigurationProperties (ConfigProperties.class) di kelas aplikasi Spring utama untuk mengikat properti ke dalam POJO:

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

Itu dia! Spring akan secara otomatis mengikat properti apa pun yang ditentukan dalam file properti kami yang memiliki email awalan dan nama yang sama dengan salah satu bidang di kelas ConfigProperties .

Musim semi menggunakan beberapa aturan santai untuk properti pengikatan. Akibatnya, semua variasi berikut terikat ke properti hostName :

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

Oleh karena itu, kita dapat menggunakan file properti berikut untuk mengatur semua bidang:

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

3.1. Spring Boot 2.2.0 Memperbarui

Mulai Spring Boot 2.2, Spring menemukan dan mendaftarkan kelas @ConfigurationProperties melalui pemindaian jalur kelas . Oleh karena itu, tidak perlu membuat anotasi kelas seperti itu dengan @Component (dan meta-anotasi lainnya seperti @Configuration), atau bahkan menggunakan @EnableConfigurationProperties:

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

Pemindai jalur kelas yang diaktifkan oleh @SpringBootApplication menemukan kelas ConfigProperties , meskipun kami tidak menganotasi kelas ini dengan @Component.

Selain itu, kita dapat menggunakan yang @ConfigurationPropertiesScan penjelasan untuk memindai lokasi kustom untuk kelas properti konfigurasi:

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

Dengan cara ini Spring akan mencari kelas properti konfigurasi hanya dalam paket com.baeldung.properties .

4. Properti Bersarang

Kita dapat memiliki properti bersarang di Daftar, Peta, dan Kelas.

Mari buat kelas Kredensial baru untuk digunakan pada beberapa properti bertingkat:

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

Kita juga perlu memperbarui ConfigProperties kelas untuk menggunakan Daftar, sebuah Peta , dan Kredensial kelas:

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 }

File properti berikut akan menyetel semua bidang:

#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. Menggunakan @ConfigurationProperties pada Metode @Bean

Kita juga bisa menggunakan @ConfigurationProperties penjelasan pada @Bean metode -annotated.

Pendekatan ini mungkin berguna terutama saat kita ingin mengikat properti ke komponen pihak ketiga yang berada di luar kendali kita.

Mari buat kelas Item sederhana yang akan kita gunakan dalam contoh berikutnya:

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

Sekarang mari kita lihat bagaimana kita dapat menggunakan @ConfigurationProperties pada metode @Bean untuk mengikat properti eksternal ke instance Item :

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

Akibatnya, properti dengan awalan item akan dipetakan ke instance Item yang dikelola oleh konteks Spring.

6. Validasi Properti

@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.

Perhatikan bahwa semua bidang ImmutableCredentials adalah final. Juga, tidak ada metode penyetel.

Selain itu, penting untuk ditekankan bahwa untuk menggunakan pengikatan konstruktor, kita perlu secara eksplisit mengaktifkan kelas konfigurasi kita baik dengan @EnableConfigurationProperties atau dengan @ConfigurationPropertiesScan .

9. Kesimpulan

Dalam artikel ini, kami menjelajahi anotasi @ConfigurationProperties dan menyoroti beberapa fitur berguna yang disediakannya, seperti pengikatan santai dan Validasi Bean.

Seperti biasa, kode tersedia di Github.