This example will show you how to use constructor injection to autowire spring bean as another bean’s constructor parameters.
1. Not Autowired Spring Bean Constructor Injection.
- This example has three spring beans defined. They are
companyBeanApple
,companyBeanIBM
andemployeeBean
. employeeBean
‘s constructor has five parameters and the parameters are specified manually.- The first three parameters are all
java.lang.String
type and the last two constructor parameter refer tocompanyBeanApple
andcompanyBeanIBM
. Below is the detailed XML configuration.<bean id="companyBeanApple" class="com.dev2qa.example.spring.bean.autowire.byconstructor.CompanyBean"> <property name="companyName" value="Apple Inc"></property> <property name="companyAddress" value="Palo alto"></property> <property name="companyProducts" value="iPhone, iPad, iMac"></property> </bean> <bean id="companyBeanIBM" class="com.dev2qa.example.spring.bean.autowire.byconstructor.CompanyBean"> <property name="companyName" value="IBM Inc"></property> <property name="companyAddress" value="New York"></property> <property name="companyProducts" value="PC, Notebook"></property> </bean> <bean id="employeeBean" class="com.dev2qa.example.spring.bean.autowire.byconstructor.EmployeeBean"> <constructor-arg type="java.lang.String" value="Jerry" index="0"> </constructor-arg> <constructor-arg type="java.lang.String" value="199999" index="1"> </constructor-arg> <constructor-arg type="java.lang.String" value="Java, Spring, JDBC" index="2"> </constructor-arg> <constructor-arg type="com.dev2qa.example.spring.bean.autowire.byconstructor.CompanyBean" ref="companyBeanIBM" index="3"> </constructor-arg> <constructor-arg type="com.dev2qa.example.spring.bean.autowire.byconstructor.CompanyBean" ref="companyBeanApple" index="4"> </constructor-arg> </bean>
- Please Note: For
<constructor-arg
XML element, index value starts from 0 and do not set it’s index attribute and name attribute simultaneously, otherwise, aorg.springframework.beans.factory.UnsatisfiedDependencyException
will be thrown and the error message may be like “Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.String]: Ambiguous constructor argument types – did you specify the correct bean references as constructor arguments?“. - CompanyBean.java
// Store one company info. public class CompanyBean { private String companyName; private String companyAddress; private String companyProducts; public String getCompanyName() { return companyName; } public void setCompanyName(String companyName) { this.companyName = companyName; } public String getCompanyAddress() { return companyAddress; } public void setCompanyAddress(String companyAddress) { this.companyAddress = companyAddress; } public String getCompanyProducts() { return companyProducts; } public void setCompanyProducts(String companyProducts) { this.companyProducts = companyProducts; } }
- EmployeeBean.java
public class EmployeeBean { private String employeeName; private String employeeSalary; private String employeeSkill; private CompanyBean employeeCompanyOld; private CompanyBean employeeCompanyNew; public String getEmployeeName() { return employeeName; } public void setEmployeeName(String employeeName) { this.employeeName = employeeName; } public String getEmployeeSalary() { return employeeSalary; } public void setEmployeeSalary(String employeeSalary) { this.employeeSalary = employeeSalary; } public String getEmployeeSkill() { return employeeSkill; } public void setEmployeeSkill(String employeeSkill) { this.employeeSkill = employeeSkill; } public CompanyBean getEmployeeCompanyOld() { return employeeCompanyOld; } public void setEmployeeCompanyOld(CompanyBean employeeCompanyOld) { this.employeeCompanyOld = employeeCompanyOld; } public CompanyBean getEmployeeCompanyNew() { return employeeCompanyNew; } public void setEmployeeCompanyNew(CompanyBean employeeCompanyNew) { this.employeeCompanyNew = employeeCompanyNew; } // EmployeeBean constructor with arguments. public EmployeeBean(String employeeName, String employeeSalary, String employeeSkill, CompanyBean employeeCompanyOld, CompanyBean employeeCompanyNew) { this.employeeName = employeeName; this.employeeSalary = employeeSalary; this.employeeSkill = employeeSkill; this.employeeCompanyOld = employeeCompanyOld; this.employeeCompanyNew = employeeCompanyNew; } public static void main(String[] args) { // Initiate Spring application context, this line code will invoke bean initialize method. ApplicationContext springAppContext = new ClassPathXmlApplicationContext("BeanSettings.xml"); // Get EmployeeBean by id. EmployeeBean employeeBean = (EmployeeBean) springAppContext.getBean("employeeBean"); System.out.println("Employee name : " + employeeBean.getEmployeeName()); System.out.println("Employee salary : " + employeeBean.getEmployeeSalary()); System.out.println("Employee skill : " + employeeBean.getEmployeeSkill()); System.out.println("Old company name : " + employeeBean.getEmployeeCompanyOld().getCompanyName()); System.out.println("Old company address : " + employeeBean.getEmployeeCompanyOld().getCompanyAddress()); System.out.println("Old company products : " + employeeBean.getEmployeeCompanyOld().getCompanyProducts()); System.out.println("New company name : " + employeeBean.getEmployeeCompanyNew().getCompanyName()); System.out.println("New company address : " + employeeBean.getEmployeeCompanyNew().getCompanyAddress()); System.out.println("New company products : " + employeeBean.getEmployeeCompanyNew().getCompanyProducts()); } }
- Above example execution output.
Employee name : Jerry Employee salary : 199999 Employee skill : Java, Spring, JDBC Old company name : IBM Inc Old company address : New York Old company products : PC, Notebook New company name : Apple Inc New company address : Palo alto New company products : iPhone, iPad, iMac
2. Make Above Spring Bean Autowired.
- To make reference type constructor parameter autowired, you just need to add
autowire="constructor"
in employeeBean definition like below.<bean id="employeeBean" class="com.dev2qa.example.spring.bean.autowire.byconstructor.EmployeeBean" autowire="constructor"> <constructor-arg type="java.lang.String" value="Jerry" index="0"> </constructor-arg> <constructor-arg type="java.lang.String" value="199999" index="1"> </constructor-arg> <constructor-arg type="java.lang.String" value="Java, Spring, JDBC" index="2"> </constructor-arg> </bean>
- Run the above example again, you will get the exception
org.springframework.beans.factory.NoUniqueBeanDefinitionException
, the error message is “No qualifying bean of type [com.dev2qa.example.spring.bean.autowire.byconstructor.CompanyBean] is defined: expected single matching bean but found 2: companyBeanApple, companyBeanIBM“. - So we can see spring bean constructor parameter auto-injection will inject bean by type. To fix this issue, you should use a unique class type constructor parameter or use a java.util.List parameter to group same class type parameter.