Trong bài viết về Bean autowiring trong Spring, các bạn đã biết trong trường hợp autowire byType, chúng ta không thể khai báo nhiều hơn 1 bean của cùng một đối tượng phụ thuộc trong Spring container. Bởi vì lúc này Spring không biết phải sử dụng bean nào để mà autowire.
Vậy có giải pháp nào khi chúng ta cần khai báo nhiều bean cho cùng một đối thuộc mà vẫn autowire được hay không? Thật may là chúng ta vẫn có một cách, đó là các bạn hãy chuyển qua autowire bean sử dụng annotation @Autowired và sử dụng annotation @Qualifier mà Spring hỗ trợ cho chúng ta. Hãy xem chúng ta cần làm gì nhé các bạn!
Để dễ hình dung, mình sẽ tạo một ví dụ như sau:
Với Spring dependency như sau:
1 2 3 4 5 |
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.0.3</version> </dependency> |
Mình sẽ sử dụng Java 17 cho ví dụ này:
1 2 3 4 |
<properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> |
Class Room:
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.springqualifier; import org.springframework.beans.factory.annotation.Autowired; public class Room { @Autowired private Table table; public Room() {} public Room(Table table) { this.table = table; } public Table getTable() { return table; } public void setTable(Table table) { this.table = table; } } |
Class Table
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package com.huongdanjava.springqualifier; public class Table { private String code; public void setCode(String code) { this.code = code; } @Override public String toString() { return "Table [code=" + code + "]"; } } |
Class Application
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package com.huongdanjava.springqualifier; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); Room room = (Room) context.getBean("room"); if (room.getTable() != null) { System.out.println(room.getTable().toString()); } } } |
Và khai báo đối tượng Table và Room trong tập tin cấu hình của Spring:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config /> <bean id="room" class="com.huongdanjava.springqualifier.Room"> </bean> <bean id="table1" class="com.huongdanjava.springqualifier.Table"> <property name="code" value="123456" /> </bean> </beans> |
OK, giờ chúng ta có thể bắt đầu rồi!
Như các bạn đã biết, nếu bây giờ mình khai báo nhiều hơn 1 bean cho cùng một đối tượng Table trong ví dụ của chúng ta như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config /> <bean id="room" class="com.huongdanjava.springqualifier.Room"> </bean> <bean id="table1" class="com.huongdanjava.springqualifier.Table"> <property name="code" value="123456" /> </bean> <bean id="table2" class="com.huongdanjava.springqualifier.Table"> <property name="code" value="789012" /> </bean> </beans> |
thì khi chạy chúng ta sẽ gặp lỗi:
1 2 3 4 5 |
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.huongdanjava.springqualifier.Table] is defined: expected single matching bean but found 2: table1,table2 at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1126) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545) ... 15 more |
Để giải quyết lỗi này, chúng ta sẽ sử dụng annotation @Qualifier để chỉ định rõ bean nào của đối tượng Table sẽ được autowire vào bean của đối tượng Room bằng cách chỉnh sửa class Room 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 |
package com.huongdanjava.springqualifier; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; public class Room { @Autowired @Qualifier("table1") private Table table; public Room() {} public Room(Table table) { this.table = table; } public Table getTable() { return table; } public void setTable(Table table) { this.table = table; } } |
Giá trị trong annotation @Qualifier là bean id của bean mà chúng ta cần autowire. Ở đây, mình sử dụng bean id “table1”, có nghĩa giá trị của thuộc tính code của đối tượng Table sẽ là “123456”.
Bây giờ, chạy lại ví dụ, các bạn sẽ nhận được kết quả như sau: