Spring Tutorial - Spring Constructor Injection








We can inject dependency via a constructor.

Constructor Dependency Injection occurs when a Java Beans's dependencies are provided to it in its constructor(s).

The Java Bean declares a constructor or a set of constructors, taking its dependencies from parameters, and the IoC container passes the dependencies to the Java Bean when instantiation occurs.

Example

Suppose we have the following interface and Java beans defined.

package com.java2s.common;
public interface Printer
{
  public void print();
}

After that we would create CSV printer which will output data in CSV format. The CSV printer implements the Printer interface.

package com.java2s.common;
public class CSVPrinter implements Printer
{
  public void print(){
    System.out.println("Csv Output Printer");
  }
}

Then it is time to create JSON printer which will output message in JSON format. The JSON printer also implements the Printer interface.

package com.java2s.common;
public class JSONPrinter implements Printer
{
  public void print(){
    System.out.println("Json Output Printer");
  }
}

A helper class with a constructor.

package com.java2s.common;
public class OutputHelper
{
  Printer outputGenerator;
    public OutputHelper(){
  }
    public OutputHelper(Printer p){
    this.outputGenerator = p;
  }
    public void print(){
      outputGenerator.print();
    }
    
}

The following Spring bean configuration file declares the beans and set the dependency via constructor injection by using constructor-arg tag.

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  <bean id="outputHelper" class="com.java2s.common.OutputHelper">
    <constructor-arg>
      <bean class="com.java2s.common.CSVPrinter" />
    </constructor-arg>
  </bean>
    <bean id="csvPrinter" class="com.java2s.common.CSVPrinter" />
    <bean id="jsonPrinter" class="com.java2s.common.JSONPrinter" />
</beans>




Load configuration and Run

The following code shows how to load the Spring configuration file and run the application.

package com.java2s.common;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext(
        "SpringBeans.xml");
    OutputHelper output = (OutputHelper)context.getBean("outputHelper");
              output.print();
  }
}

Output



Download Java2s_Spring_Constructor_Injection.zip





Constructor injection type ambiguities

The following Employee class has two constructor methods. Both of them accept 3 arguments with different data type.

package com.java2s.common;
public class Employee 
{
  private String name;
  private String address;
  private int age;
  public Employee(String name, String address, int age) {
    this.name = name;
    this.address = address;
    this.age = age;
  }
  public Employee(String name, int age, String address) {
    this.name = name;
    this.age = age;
    this.address = address;
  }
  public String toString(){
    return " name : " +name + " address : " + address + " age : " + age;
  }
}

The first one has the following parameters

public Employee(String name, String address, int age)

The second one is defined as follows.

public Employee(String name, int age, String address)

The age and address switched position.

When creating the Employee object in the Spring configuration xml file we use constructor-arg tag to provide values for the parameter in the constructor.

In the following Spring bean configuration file, we passed in 'java2s' for name, '1000' for address and '28' for age.


<myPreCode>
<beans ...
  <bean id="myEmployee" class="com.java2s.common.Employee">
    <constructor-arg>
      <value>java2s</value>
    </constructor-arg>
    <constructor-arg>
      <value>1000</value>
    </constructor-arg>
    <constructor-arg>
      <value>28</value>
    </constructor-arg>
        </bean>
</beans>

Here is the code to run the configuration we set above.

package com.java2s.common;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App 
{
    public static void main( String[] args )
    {
      ApplicationContext context = 
        new ClassPathXmlApplicationContext(new String[] {"Spring-Employee.xml"});
      Employee cust = (Employee)context.getBean("myEmployee");
      System.out.println(cust);
    }
}

Output

From the result string we can see that the second constructor is called rather than the first constructor.

Spring converts the argument '1000' to int, and then calls take the second constructor, even we passed in the value as a String type.

If Spring cannot find the proper constructor to use, it will prompt following error message

constructor arguments specified but no matching constructor 
found in bean 'myEmployee' (hint: specify index and/or 
type arguments for simple parameters to avoid type ambiguities)

In order to match the parameter type in the constructor, we can specify the data type for constructor, via type attribute in the constructor-arg tag.

<beans ...
  <bean id="myEmployee" class="com.java2s.common.Employee">
    <constructor-arg type="java.lang.String">
      <value>java2s</value>
    </constructor-arg>
    <constructor-arg type="java.lang.String">
      <value>1000</value>
    </constructor-arg>
    <constructor-arg type="int">
      <value>28</value>
    </constructor-arg>
  </bean>
</beans>

Run it again.