In the tutorial on Bean autowiring in Spring framework, you know in the case of byType autowire, we cannot declare more than one bean of the same dependency in Spring’s container. Because in this case, Spring does not know what bean to use for autowire.
Is there any solution when we need to declare multiple beans for the same object but still autowire? Fortunately, we still have one way, that is, you move to autowire bean using the @Autowired annotation and use the @Qualifier annotation that Spring supports for us. Let’s see what we need to do!
For easy visualization, I will create an example as follows:
With Spring dependency as follows:
1 2 3 4 5 |
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.0.3</version> </dependency> |
I will use Java 17 for this example:
1 2 3 4 |
<properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> |
Room class:
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; } } |
Table class
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 + "]"; } } |
Application class
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()); } } } |
And declare the Table and Room objects in the Spring configuration file:
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, now we can start!
As you all know, if we now declare more than one bean for the same Table object in our example as follows:
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> |
When we run, we get an error:
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 |
To resolve this error, we will use the @Qualifier annotation to specify which bean of the Table object will be autowire into the bean of the Room object by editing the Room class as follows:
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; } } |
The value in the @Qualifier annotation is the bean id of the bean that we need autowire. Here, I use bean id “table1”, which means that the value of the code attribute of the Table object will be “123456”.
Now, rerun the example, you will get the following results: