Properti dengan Spring dan Spring Boot

1. Ikhtisar

Tutorial ini akan menunjukkan cara menyiapkan dan menggunakan properti di Spring melalui konfigurasi Java dan @PropertySource.

Kami juga akan melihat bagaimana properti bekerja di Spring Boot.

2. Daftarkan File Properti melalui Anotasi

Spring 3.1 juga memperkenalkan anotasi @PropertySource baru sebagai mekanisme praktis untuk menambahkan sumber properti ke lingkungan.

Kita dapat menggunakan anotasi ini bersama dengan anotasi @Configuration :

@Configuration @PropertySource("classpath:foo.properties") public class PropertiesWithJavaConfig { //... }

Cara lain yang sangat berguna untuk mendaftarkan file properti baru adalah menggunakan placeholder, yang memungkinkan kita untuk memilih file yang tepat secara dinamis saat runtime :

@PropertySource({ "classpath:persistence-${envTarget:mysql}.properties" }) ...

2.1. Mendefinisikan Beberapa Lokasi Properti

The @PropertySource penjelasan adalah diulangi sesuai dengan Java 8 konvensi. Oleh karena itu, jika kita menggunakan Java 8 atau lebih tinggi, kita dapat menggunakan anotasi ini untuk mendefinisikan beberapa lokasi properti:

@PropertySource("classpath:foo.properties") @PropertySource("classpath:bar.properties") public class PropertiesWithJavaConfig { //... }

Tentu saja, kita juga dapat menggunakan anotasi @PropertySources dan menentukan larik @PropertySource . Ini berfungsi di semua versi Java yang didukung, tidak hanya di Java 8 atau lebih tinggi:

@PropertySources({ @PropertySource("classpath:foo.properties"), @PropertySource("classpath:bar.properties") }) public class PropertiesWithJavaConfig { //... }

Dalam kedua kasus tersebut, perlu diperhatikan bahwa jika nama properti bertabrakan, pembacaan sumber terakhir akan diutamakan.

3. Menggunakan / Menyuntikkan Properti

Memasukkan properti dengan anotasi @Value sangat mudah:

@Value( "${jdbc.url}" ) private String jdbcUrl;

Kami juga dapat menentukan nilai default untuk properti:

@Value( "${jdbc.url:aDefaultUrl}" ) private String jdbcUrl;

PropertySourcesPlaceholderConfigurer baru yang ditambahkan di Spring 3.1 menyelesaikan $ {…} placeholder dalam nilai properti definisi kacang dan anotasi @Value .

Akhirnya, kita bisa mendapatkan nilai properti menggunakan API Lingkungan :

@Autowired private Environment env; ... dataSource.setUrl(env.getProperty("jdbc.url"));

4. Properti Dengan Spring Boot

Sebelum kita masuk ke opsi konfigurasi lanjutan untuk properti, mari luangkan waktu untuk melihat dukungan properti baru di Spring Boot.

Secara umum, dukungan baru ini melibatkan lebih sedikit konfigurasi dibandingkan dengan Spring standar , yang tentu saja merupakan salah satu tujuan utama Boot.

4.1. application.properties: File Properti Default

Boot menerapkan konvensi tipikal atas pendekatan konfigurasi ke file properti. Ini berarti kita cukup meletakkan file application.properties di direktori src / main / resources kita , dan itu akan otomatis terdeteksi . Kami kemudian dapat menyuntikkan properti apa pun yang dimuat darinya seperti biasa.

Jadi, dengan menggunakan file default ini, kita tidak perlu mendaftarkan PropertySource secara eksplisit atau bahkan menyediakan jalur ke file properti.

Kita juga dapat mengonfigurasi file yang berbeda saat runtime jika perlu, menggunakan properti lingkungan:

java -jar app.jar --spring.config.location=classpath:/another-location.properties

Mulai Spring Boot 2.3, kami juga dapat menentukan lokasi wildcard untuk file konfigurasi .

Misalnya, kita dapat menyetel properti spring.config.location ke config / * / :

java -jar app.jar --spring.config.location=config/*/

Dengan cara ini, Spring Boot akan mencari file konfigurasi yang cocok dengan pola direktori config / * / di luar file jar kita. Ini berguna ketika kita memiliki banyak sumber properti konfigurasi.

Sejak versi 2.4.0 , Spring Boot mendukung penggunaan file properti multi-dokumen , seperti yang dilakukan oleh YAML:

baeldung.customProperty=defaultValue #--- baeldung.customProperty=overriddenValue

Perhatikan bahwa untuk file properti, notasi tiga garis diawali dengan karakter komentar ( # ).

4.2. File Properti Khusus Lingkungan

Jika kita perlu menargetkan lingkungan yang berbeda, ada mekanisme bawaan untuk itu di Boot.

Kita cukup mendefinisikan file application-environment.properties di direktori src / main / resources , dan kemudian menyetel profil Spring dengan nama lingkungan yang sama.

Misalnya, jika kita mendefinisikan lingkungan “staging”, itu berarti kita harus mendefinisikan profil staging dan kemudian application-staging.properties .

File env ini akan dimuat dan akan diutamakan daripada file properti default. Perhatikan bahwa file default akan tetap dimuat, hanya saja ketika terjadi benturan properti, file properti khusus lingkungan akan diutamakan.

4.3. File Properti Uji-Spesifik

Kita mungkin juga memiliki persyaratan untuk menggunakan nilai properti yang berbeda saat aplikasi kita sedang diuji.

Spring Boot menangani ini untuk kami dengan melihat di direktori src / test / resources kami selama pengujian dijalankan . Sekali lagi, properti default akan tetap dapat diinjeksi seperti biasa, tetapi akan diganti jika terjadi benturan.

4.4. The @TestPropertySource Anotasi

Jika kita membutuhkan kontrol yang lebih terperinci atas properti pengujian, maka kita dapat menggunakan anotasi @TestPropertySource .

Ini memungkinkan kami menyetel properti pengujian untuk konteks pengujian tertentu, lebih diutamakan daripada sumber properti default:

@RunWith(SpringRunner.class) @TestPropertySource("/foo.properties") public class FilePropertyInjectionUnitTest { @Value("${foo}") private String foo; @Test public void whenFilePropertyProvided_thenProperlyInjected() { assertThat(foo).isEqualTo("bar"); } }

Jika kita tidak ingin menggunakan file, kita dapat menentukan nama dan nilai secara langsung:

@RunWith(SpringRunner.class) @TestPropertySource(properties = {"foo=bar"}) public class PropertyInjectionUnitTest { @Value("${foo}") private String foo; @Test public void whenPropertyProvided_thenProperlyInjected() { assertThat(foo).isEqualTo("bar"); } }

Kita juga bisa mendapatkan efek serupa menggunakan argumen properti dari anotasi @SpringBootTest :

@RunWith(SpringRunner.class) @SpringBootTest( properties = {"foo=bar"}, classes = SpringBootPropertiesTestApplication.class) public class SpringBootPropertyInjectionIntegrationTest { @Value("${foo}") private String foo; @Test public void whenSpringBootPropertyProvided_thenProperlyInjected() { assertThat(foo).isEqualTo("bar"); } }

4.5. Properti Hierarki

Jika kita memiliki properti yang dikelompokkan bersama, kita dapat menggunakan anotasi @ConfigurationProperties , yang akan memetakan hierarki properti ini ke dalam grafik objek Java.

Mari kita ambil beberapa properti yang digunakan untuk mengonfigurasi koneksi database:

database.url=jdbc:postgresql:/localhost:5432/instance database.username=foo database.password=bar

Dan kemudian mari gunakan anotasi untuk memetakannya ke objek database:

@ConfigurationProperties(prefix = "database") public class Database { String url; String username; String password; // standard getters and setters }

Spring Boot menerapkan konvensi itu melalui pendekatan konfigurasi lagi, secara otomatis memetakan antara nama properti dan bidang yang sesuai. Yang perlu kita sediakan hanyalah prefiks properti.

Jika Anda ingin menggali lebih dalam tentang properti konfigurasi, lihat artikel mendalam kami.

4.6. Alternatif: File YAML

Spring juga mendukung file YAML.

All the same naming rules apply for test-specific, environment-specific, and default property files. The only difference is the file extension and a dependency on the SnakeYAML library being on our classpath.

YAML is particularly good for hierarchical property storage; the following property file:

database.url=jdbc:postgresql:/localhost:5432/instance database.username=foo database.password=bar secret: foo

is synonymous with the following YAML file:

database: url: jdbc:postgresql:/localhost:5432/instance username: foo password: bar secret: foo

It's also worth mentioning that YAML files do not support the @PropertySource annotation, so if we need to use this annotation, it would constrain us to using a properties file.

Another remarkable point is that in version 2.4.0 Spring Boot changed the way in which properties are loaded from multi-document YAML files. Previously, the order in which they were added was based on the profile activation order. With the new version, however, the framework follows the same ordering rules that we indicated earlier for .properties files; properties declared lower in the file will simply override those higher up.

Additionally, in this version profiles can no longer be activated from profile-specific documents, making the outcome clearer and more predictable.

4.7. Importing Additional Configuration Files

Prior to version 2.4.0, Spring Boot allowed including additional configuration files using the spring.config.location and spring.config.additional-location properties, but they had certain limitations. For instance, they had to be defined before starting the application (as environment or system properties, or using command-line arguments) as they were used early in the process.

In the mentioned version, we can use the spring.config.import property within the application.properties or application.yml file to easily include additional files. This property supports some interesting features:

  • adding several files or directories
  • the files can be loaded either from the classpath or from an external directory
  • indicating if the startup process should fail if a file is not found, or if it's an optional file
  • importing extensionless files

Let's see a valid example:

spring.config.import=classpath:additional-application.properties, classpath:additional-application[.yml], optional:file:./external.properties, classpath:additional-application-properties/

Note: here we formatted this property using line breaks just for clarity.

Spring will treat imports as a new document inserted immediately below the import declaration.

4.8. Properties From Command Line Arguments

Besides using files, we can pass properties directly on the command line:

java -jar app.jar --property="value"

We can also do this via system properties, which are provided before the -jar command rather than after it:

java -Dproperty.name="value" -jar app.jar

4.9. Properties From Environment Variables

Spring Boot will also detect environment variables, treating them as properties:

export name=value java -jar app.jar 

4.10. Randomization of Property Values

If we don't want determinist property values, we can use RandomValuePropertySource to randomize the values of properties:

random.number=${random.int} random.long=${random.long} random.uuid=${random.uuid}

4.11. Additional Types of Property Sources

Spring Boot supports a multitude of property sources, implementing a well-thought-out ordering to allow sensible overriding. It's worth consulting the official documentation, which goes further than the scope of this article.

5. Configuration Using Raw Beans — the PropertySourcesPlaceholderConfigurer

Besides the convenient methods of getting properties into Spring, we can also define and regiter the property configuration bean manually.

Working with the PropertySourcesPlaceholderConfigurer gives us full control over the configuration, with the downside of being more verbose and most of the time, unnecessary.

Let's see how we can define this bean using Java configuration:

@Bean public static PropertySourcesPlaceholderConfigurer properties(){ PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer(); Resource[] resources = new ClassPathResource[ ] { new ClassPathResource( "foo.properties" ) }; pspc.setLocations( resources ); pspc.setIgnoreUnresolvablePlaceholders( true ); return pspc; }

6. Properties in Parent-Child Contexts

This question comes up again and again: What happens when our web application has a parent and a child context? The parent context may have some common core functionality and beans, and then one (or multiple) child contexts, maybe containing servlet-specific beans.

In that case, what's the best way to define properties files and include them in these contexts? And how to best retrieve these properties from Spring?

We'll give a simple breakdown.

If the file is defined in the Parent context:

  • @Value works in Child context: YES
  • @Value works in Parent context: YES
  • environment.getProperty in Child context: YES
  • environment.getProperty in Parent context: YES

If the file is defined in the Child context:

  • @Value works in Child context: YES
  • @Value works in Parent context: NO
  • environment.getProperty in Child context: YES
  • environment.getProperty in Parent context: NO

7. Conclusion

This article showed several examples of working with properties and properties files in Spring.

Seperti biasa, seluruh kode yang mendukung artikel tersedia di GitHub.