Mình đã giới thiệu với các bạn về annotation @Value để ingest giá trị của các property nằm trong các tập tin properties với Spring framework. Tất nhiên, chúng ta cũng có thể sử dụng annotation @Value này trong Spring Boot. Thế nhưng, trong Spring Boot, chúng ta cũng có một annotation khác là @ConfigurationProperties để làm việc này. Sự khác nhau giữa 2 annotation là gì và tại sao họ lại tạo thêm mới một annotation khác để ingest giá trị của các property trong tập tin properties? Hãy cùng tìm hiểu trong bài viết này các bạn nhé!
Đầu tiên, mình sẽ tạo một Spring Boot project như sau:
Trong đó, class SpringBootConfigurationPropertiesApplication implement interface CommandLineRunner để có thể chạy Java console, với nội dung ban đầu như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package com.huongdanjava.springboot; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringBootConfigurationPropertiesApplication implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(SpringBootConfigurationPropertiesApplication.class, args); } @Override public void run(String... args) throws Exception { } } |
Class Student sẽ chứa thông tin sinh viên với một số thuộc tính như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com.huongdanjava.springboot; public class Student { private String name; private String clazz; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } } |
Tập tin student.properties chứa thông tin của sinh viên với nội dung như sau:
1 2 |
student.name=Khanh student.clazz=Class A |
Sử dụng annotation @Value, chúng ta có thể ingest giá trị của những properties nằm trong tập tin student.properties vào đối tượng Student
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com.huongdanjava.springboot; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; @Component @PropertySource("classpath:student.properties") public class Student { @Value("${student.name}") private String name; @Value("${student.clazz}") private String clazz; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } } |
rồi hiển thị các thông tin này ra console như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.huongdanjava.springboot; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringBootConfigurationPropertiesApplication implements CommandLineRunner { @Autowired private Student student; public static void main(String[] args) { SpringApplication.run(SpringBootConfigurationPropertiesApplication.class, args); } @Override public void run(String... args) throws Exception { System.out.println(student.getClazz() + "-" + student.getName()); } } |
Kết quả:
Nếu bây giờ, các bạn sử dụng annotation @ConfigurationProperties trong class Student bằng cách khai báo như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package com.huongdanjava.springboot; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; @Component @PropertySource("classpath:student.properties") @ConfigurationProperties("student") public class Student { private String name; private String clazz; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } } |
chạy lại thì kết quả vẫn tương tự.
Như các bạn thấy, với việc sử dụng annotation @ConfigurationProperties, mình không cần phải khai báo thuộc tính nào của đối tượng Student sẽ được ingest vào giá trị của property nào trong tập tin student.properties. Mọi thứ đều hoàn toàn tự động.
Để làm được điều này, tất nhiên chúng ta phải tuân theo một số nguyên tắc các bạn nhé! 🙂
Ở ví dụ trên, “student” chính là prefix mà annotation @ConfigurationProperties sẽ sử dụng để tự động ingest các properties trong tập tin student.properties. Những properties nào bắt đầu là “student” và phần còn lại trùng với tên thuộc tính của đối tượng Student sẽ được ingest giá trị vào thuộc tính đó của đối tượng Student. Ở đây, phần còn lại của những properties này sẽ không phân biệt hoa, thường, gạch dưới hay gạch ngang nhé các bạn.
Ví dụ, mình có thể khai báo tập tin student.properties như sau:
1 2 |
student.N-AME=Khanh student.CLazz=Class A |
thì kết quả vẫn như vậy nha các bạn! Cái này người ta gọi là relaxed binding. 🙂
Tất nhiên, nếu các properties của chúng ta không start với student:
1 2 |
N-AME=Khanh CLazz=Class A |
thì các bạn không cần khai báo prefix trong annotation @ConfigurationProperties nữa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package com.huongdanjava.springboot; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; @Component @PropertySource("classpath:student.properties") @ConfigurationProperties() public class Student { private String name; private String clazz; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } } |
Trong trường hợp đối tượng Student có chứa một collection hoặc array, ví dụ như:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
package com.huongdanjava.springboot; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; @Component @PropertySource("classpath:student.properties") @ConfigurationProperties() public class Student { private String name; private String clazz; private List<Integer> scores; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } public List<Integer> getScores() { return scores; } public void setScores(List<Integer> scores) { this.scores = scores; } } |
thì các bạn có thể khai báo như sau trong tập tin student.properties để Spring Boot tự động ingest giá trị của biến scores vào đối tượng Student nhé:
1 2 3 |
N-AME=Khanh CLazz=Class A scores=7,10 |
Khi đó, kết quả sẽ là:
Trong trường hợp đối tượng Student còn chứa một đối tượng khác, ví dụ như:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
package com.huongdanjava.springboot; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; @Component @PropertySource("classpath:student.properties") @ConfigurationProperties() public class Student { private String name; private String clazz; private List<Integer> scores; private Address address = new Address(); class Address { private String street; private String city; public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } public List<Integer> getScores() { return scores; } public void setScores(List<Integer> scores) { this.scores = scores; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } } |
thì với khai báo như sau trong tập tin properties:
1 2 3 4 5 |
N-AME=Khanh CLazz=Class A scores=7,10 address.street=Street 1 address.city=HCM |
Thông tin của đối tượng Address cũng được ingest như bình thường: