Mục lục
Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu về cách hoạt động của @Value annotation trong Spring.
@Value annotation được sử dụng để chú thích các thuộc tính trong class hoặc các tham số đầu vào của method hay constructor để đặt tiêm các giá trị tương ứng được cấu hình trong các tệp cấu hình, ngoài ra nó còn được sử dụng để đặt giá trị mặc định cho các thuộc tính hoặc tham số đầu vào của method, constructor.
Default Value
Trường hợp sử dụng cơ bản nhất của @Value annotation là đặt giá trị mặc định cho các thuộc tính trong class.
@Value("John") private String trainee; @Value("100") private int hoursOfCode; @Value("true") private boolean passedAssesmentTest;
Một điểm chúng ta cần lưu ý là @Value chỉ nhận các gía trị kiểu String, sau đó những giá trị này sẽ được chuyển đổi sang kiểu dữ liệu tương ứng với kiểu dữ liệu của thuộc tính đã khai báo.
Spring Environment
Việc sử dụng @Value annotation để tiêm các giá trị được đặt trong các file cấu hình là một trong những cách sử dụng phổ biến nhất trong các ứng dụng Spring chạy trong thực tế.
Đầu tiên, chúng ta sẽ cùng đặt các giá trị trong file cấu hình chẳng hạn như application.properties hoặc application.yml tuỳ thuộc vào định dạng mà dự án các bạn đang sử dụng.
Giả sử mình có 3 thuộc tính được đặt giá trị trong file application.properties như thế này.
car.brand=Audi car.color=Red car.power=150
Để tiêm các giá trị này vào các thuộc tính trong một class chúng ta có thể sử dụng cú pháp như sau:
@Value("${car.brand") private String brand; @Value("${car.color}") private String color; @Value("${car.power}") private int power;
Ngoài ra chúng ta có thể đặt giá trị mặc định cho các thuộc tính này trong trường hợp một có giá trị tương ứng được đặt trong tệp application.properties.
@Value("${car.type:Sedan}") private String type;
Trong ví dụ trên, nếu chúng ta không đặt giá trị cho thuộc tính car.type thì gía trị mặc định của type là Sedan.
System Variables
Chúng ta cũng có thể truy cập các thuộc tính của hệ thống được Spring sử dụng khi khởi chạy ứng dụng.
@Value("${user.name}") // Or @Value("${username}") private String userName; @Value("${number.of.processors}") // Or @Value("${number_of_processors}") private int numberOfProcessors; @Value("${java.home}") private String java;
Các gía trị này có thể đặt bởi các định dạng khác nhau nhưng chúng vẫn có thể tìm đúng được giá trị mong muốn của chúng ta.
@Value với biểu thức SpEL
Trong @Value chúng ta có thể sử dụng biểu thức SpEL để lấy các giá trị.
Giả sử nếu chúng ta có thuộc tính hệ thống được đặt tên là priority, thì giá trị của nó sẽ được áp dụng là:
@Value("#{systemProperties['priority']}") private String spelValue;
Nếu chúng ta không đặt giá trị cho thuộc tính systemProperties.priority thì giá trị NULL sẽ được đặt cho spelValue. Nếu muốn đặt giá trị mặc định thay vì NULL chúng ta có thế làm như sau:
@Value("#{systemProperties['priority'] ?: 'some default'}") private String spelSomeDefault;
Hoặc nếu chúng ta có một tập giá trị được ngăn cách bởi dấu phẩy thì chúng ta có thể sử dụng biểu thức SpEL để tách chuỗi và trả về một danh sách các giá trị tương ứng.
@Value("#{'${listOfValues}'.split(',')}") private List<String> valuesList;
@Value với Constructor Injection
Chúng ta có thể sử dụng @Value trên các tham số đầu vào của một constructor. Thông thường chúng ta thường sử dụng trong constructor injection.
public class PriorityProvider { private String priority; @Autowired public PriorityProvider(@Value("${priority:normal}") String priority) { this.priority = priority; }
Bây giờ, giá trị priority sẽ tương ứng với priority:normal được chỉ định trong application.properties.
@Value với Setter injection
Chúng ta cũng có thể sử dụng @Value trên các tham số đầu vào của một Setter method injection.
public class CollectionProvider { private List<String> values = new ArrayList<>(); @Autowired public void setValues(@Value("#{'${listOfValues}'.split(',')}") List<String> values) { this.values.addAll(values); } // standard getter }
Ở trên chúng ta đã sử dụng biểu thức SpEL để đưa danh sách các giá trị vào phương thức setValues.
@Value annotation với Map
Chúng ta có thể tiêm các thuộc tính có kiểu dữ liệu Map thông qua @Value annotation. Để làm được điều này đầu tiên chúng ta cần định nghĩa một thuộc tính dạng key-value trong file application.properties.
valuesMap={key1: '1', key2: '2', key3: '3'}
Sau đó, tiêm valuesMap vào thuộc tính có kiểu dữ liệu là Map như sau:
@Value("#{${valuesMap}}") private Map<String, Integer> valuesMap;
Chúng ta cũng có thể sử dụng một trong những giá trị của một key tương ứng bằng cách chỉ định rõ giá trị của key tương ứng trong @Value annotation.
@Value("#{${valuesMap}.key1}") private Integer valuesMapKey1;
Nếu không chắc chắn một key có tồn tại trong tệp cấu hình hay không thì chúng ta có thể sử dụng biểu thức an toàn để nó giúp chúng ta đặt giá trị thành NULL thay vì ném ra một exception.
Ngoài ra chúng ta có thể đặt giá trị mặc định trong trường hợp không có các giá trị tương ứng của một Map hay một key tương ứng được định nghĩa trong file application.properties.
@Value("#{${unknownMap : {key1: '1', key2: '2'}}}") private Map<String, Integer> unknownMap; @Value("#{${valuesMap}['unknownKey'] ?: 5}") private Integer unknownMapKeyWithDefaultValue;
Các phần tử của Map có thể lọc trước khi tiêm vào bằng cách sử dụng biểu thức SpEL.
Giả sử loại bỏ các phần tử có giá trị bé hơn 1.
@Value("#{${valuesMap}.?[value>'1']}") private Map<String, Integer> valuesMapFiltered;
Chúng ta cũng có thể tiêm tất cả các thuộc tính hệ thống được Spring sử dụng vào một Map với cú pháp ngắn gọn như sau:
@Value("#{systemProperties}") private Map<String, String> systemPropertiesMap;
Nguồn