Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon

Implementing Dependency Injection in Spring [Tutorial]

Save for later
  • 9 min read
  • 21 Aug 2018

article-image

Spring is a lightweight and open source enterprise framework created way back in 2003. Modularity is the heart of the Spring framework. Because of this, Spring can be used from the presentation layer to the persistence layer.

The good thing is, Spring doesn't force you to use Spring in all layers. For example, if you use Spring in the persistence layer, you are free to use any other framework in the presentation of the controller layer. In this article we will look at implementing Dependency Injection (DI) in Spring Java application.

This tutorial is an excerpt taken from the book  'Java 9 Dependency Injection', written by Krunal Patel, Nilang Patel.

Spring is a POJO-based framework; a servlet container is suffice to run your application and a fully-fledged application server is not required.


DI is a process of providing the dependent objects to other objects that need it. In Spring, the container supplies the dependencies. The flow of creating and managing the dependencies is inverted from client to container. That is the reason we call it an IoC container.

A Spring IoC container uses the Dependency Injection (DI) mechanism to provide the dependency at runtime.  Now we'll talk about how we can implement the constructor and setter-based DI through Spring's IoC container.

Implementing Constructor-based DI


Constructor-based dependency is generally used where you want to pass mandatory dependencies before the object is instantiated. It's provided by a container through a constructor with different arguments, and each represents dependency.

When a container starts, it checks whether any constructor-based DI is defined for <bean>. It will create the dependency objects first, and then pass them to the current object's constructor. We will understand this by taking the classic example of using logging. It is good practice to put the log statement at various places in the code to trace the flow of execution.

Let's say you have an EmployeeService class where you need to put a log in each of its methods. To achieve separation of concern, you put the log functionality in a separated class called Logger. To make sure the EmployeeService and Logger are independent and loosely coupled, you need to inject the Logger object into the EmployeeService object. Let's see how to achieve this by constructor-based injection:

public class EmployeeService {
     private Logger log;
     //Constructor
      public EmployeeService(Logger log) {
          this.log = log;
      }

//Service method.
public void showEmployeeName() {
log.info("showEmployeeName method is called ....");
log.debug("This is Debuggin point");
log.error("Some Exception occured here ...");
}

}

public class Logger {
public void info(String msg){
System.out.println("Logger INFO: "+msg);
}
public void debug(String msg){
System.out.println("Logger DEBUG: "+msg);
}
public void error(String msg){
System.out.println("Logger ERROR: "+msg);
}
}

public class DIWithConstructorCheck {

public static void main(String[] args) {

ApplicationContext springContext = new ClassPathXmlApplicationContext("application-context.xml");
EmployeeService employeeService = (EmployeeService) springContext.getBean("employeeService");
employeeService.showEmployeeName();

}
}


As per the preceding code, when these objects are configured with Spring, the EmployeeService object expects the Spring container to inject the object of Logger through the constructor. To achieve this, you need to set the configuration metadata as per the following snippet:

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">

<!-- All your bean and its configuration metadata goes here -->
<bean id="employeeService" class="com.packet.spring.constructor.di.EmployeeService">
<constructor-arg ref="logger"/> 
</bean>

<bean id="logger" class="com.packet.spring.constructor.di.Logger">
</bean>

</beans>


In the preceding configuration, the Logger bean is injected into the employee bean through the constructor-arg element. It has a ref attribute, which is used to point to other beans with a matching id value.  This configuration instructs Spring to pass the object of Logger into the constructor of the EmployeeService bean.

You can put the <bean> definition in any order here. Spring will create the objects of <bean> based on need, and not as per the order they are defined here.


For more than one constructor argument, you can pass additional <constructor-arg> elements. The order is not important as far as the object type (class attribute of referred bean) is not ambiguous.

Spring also supports DI with primitive constructor arguments. Spring provides the facility to pass the primitive values in a constructor from an application context (XML) file. Let's say you want to create an object of the Camera class with a default value, as per the following snippet:

public class Camera {
  private int resolution;
  private String mode;
  private boolean smileShot;

//Constructor.
public Camera(int resolution, String mode, boolean smileShot) {
this.resolution = resolution;
this.mode = mode;
this.smileShot = smileShot;
}

//Public method
public void showSettings() {
System.out.println("Resolution:"+resolution+"px mode:"+mode+" smileShot:"+smileShot);
}
}


The Camera class has three properties: resolution, mode, and smileShot. Its constructor takes three primitive arguments to create a camera object with default values. You need to give configuration metadata in the following way so that Spring can create instances of the Camera object with default primitive values:

<bean id="camera" class="com.packet.spring.constructor.di.Camera">
      <constructor-arg type="int" value="12" />
      <constructor-arg type="java.lang.String" value="normal" />
      <constructor-arg type="boolean" value="false" />
</bean>


We pass three <constructor-arg> elements under <bean>, corresponding to each constructor argument. Since these are primitive, Spring has no idea about its type while passing the value. So, we need to explicitly pass the type attribute, which defines the type of primitive constructor argument.

In case of primitive also, there is no fixed order to pass the value of the constructor argument, as long as the type is not ambiguous. In previous cases, all three types are different, so Spring intelligently picks up the right constructor argument, no matter which orders you pass them.

Now we are adding one more attribute to the Camera class called flash, as per the following snippet:

//Constructor.
  public Camera(int resolution, String mode, boolean smileShot, boolean flash) {
    this.resolution = resolution;
    this.mode = mode;
    this.smileShot = smileShot;
    this.flash = flash;
  }


In this case, the constructor arguments smileShot and flash are of the same type (Boolean), and you pass the constructor argument value from XML configuration as per the following snippet:

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
      <constructor-arg type="java.lang.String" value="normal"/>
      <constructor-arg type="boolean" value="true" />
      <constructor-arg type="int" value="12" />
      <constructor-arg type="boolean" value="false" />


In the preceding scenario, Spring will pick up the following:

  • int value for resolution
  • The string value for mode
  • First Boolean value (true) in sequence for first Boolean argument—smileShot
  • Second Boolean value (false) in sequence for second Boolean argument—flash


In short, for similar types in constructor arguments, Spring will pick the first value that comes in the sequence. So sequence does matter in this case.

This may lead to logical errors, as you are passing wrong values to the right argument. To avoid such accidental mistakes, Spring provides the facility to define a zero-based index in the <constructor-arg> element, as per the following snippet:

      <constructor-arg type="java.lang.String" value="normal"
      index="1"/>
      <constructor-arg type="boolean" value="true" index="3"/>
      <constructor-arg type="int" value="12" index="0"/>
      <constructor-arg type="boolean" value="false" index="2"/>


This is more readable and less error-prone. Now Spring will pick up the last value (with index=2) for smileShot, and the second value (with index=3) for flash arguments. Index attributes resolve the ambiguity of two constructor arguments having the same type.

If the type you defined in <constructor-arg> is not compatible with the actual type of constructor argument in that index, then Spring will raise an error. So just make sure about this while using index attribute.


Implementing Setter-based DI


Setter-based DI is generally used for optional dependencies. In case of setter-based DI, the container first creates an instance of your bean, either by calling a no-argument constructor or static factory method. It then passes the said dependencies through each setter method. Dependencies injected through the setter method can be re-injected or changed at a later stage of application.

We will understand setter-based DI with the following code base:

public class DocumentBase {
  private DocFinder docFinder;
 //Setter method to inject dependency. 
 public void setDocFinder(DocFinder docFinder) {
    this.docFinder = docFinder;
  }
  public void performSearch() {
    this.docFinder.doFind();
  }

}

public class DocFinder {
public void doFind() {
System.out.println(" Finding in Document Base ");
}
}

public class DIWithSetterCheck {
public static void main(String[] args) {
ApplicationContext springContext = new ClassPathXmlApplicationContext("application-context.xml");
DocumentBase docBase = (DocumentBase) springContext.getBean("docBase");
docBase.performSearch();
}
}


The  DocumentBase class depends on DocFinder, and we are passing it through the setter method. You need to define the configuration metadata for Spring, as per the following snippet:

    <bean id="docBase" class="com.packet.spring.setter.di.DocumentBase">
        <property name="docFinder" ref="docFinder" /> 
    </bean>

<bean id="docFinder" class="com.packet.spring.setter.di.DocFinder">
</bean>


Setter-based DI can be defined through the <property> element under <bean>. The name attribute denotes the name of the setter name. In our case, the name attribute of the property element is docFinder, so Spring will call the setDocFinder method to inject the dependency. The pattern to find the setter method is to prepend set and make the first character capital.

The name attribute of the <property> element is case-sensitive. So, if you set the name to docfinder, Spring will try to call the setDocfinder method and will show an error.

Just like constructor DI, Setter DI also supports supplying the value for primitives, as per the following snippet:

<bean id="docBase" class="com.packet.spring.setter.di.DocumentBase">
        <property name="buildNo" value="1.2.6" />
</bean>


Since the setter method takes only one argument, there is no scope of argument ambiguity. Whatever value you are passing here, Spring will convert it to an actual primitive type of the setter method parameter. If it's not compatible, it will show an error.

We learned to implement DI with Spring and looked at different types of DI like setter-based injection and constructor-based injection.

If you found this post useful, be sure to check out the book  'Java 9 Dependency Injection' to learn about factory method in Spring and other concepts in dependency injection.

Learning Dependency Injection (DI)

Angular 2 Dependency Injection: A powerful design pattern