Spring Dependency Injection Tutorial with Example

In this tutorial, we will learn what is Spring Dependency Injection, advantages of using DI, types of DI with an example.

What is Spring Dependency Injection?

From the documentation, Dependency injection (DI) is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse, hence the name Inversion of Control (IoC), of the bean itself controlling the instantiation or location of its dependencies on its own by using direct construction of classes, or the Service Locator pattern.

The Spring Framework Inversion of Control (IoC) component is the nucleus of the framework. It uses dependency injection to assemble Spring-provided (also called infrastructure components) and development-provided components in order to rapidly wrap up an application.
Check out how Spring IOC Works with Example
Figure: Spring IoC purpose

Advantages of Dependency Injection

The advantages of DI are as follows:
  • Loosely coupled architecture.
  • Separation of responsibility.
  • Configuration and code are separate.
  • A different implementation can be supplied using configuration without changing the code dependent.
  • Improves testability.
  • DI allows you to replace actual objects with mock objects. This improves testability by writing simple JUnit tests that use mock objects.

Spring Dependency Injection Types

In the Spring Framework, DI is used to satisfy the dependencies between objects. It exists in two major types:
  1. Constructor-based dependency injection
  2. Setter-based dependency injection.

1. Constructor-based dependency injection

Constructor-based DI is accomplished by the container invoking a constructor with a number of arguments, each representing a dependency.

In the below diagram, the highlighted part shows the Constructor-based dependency injection.

1.1 Constructor-based dependency injection example

Let's see the complete example to demonstrate Constructor-based dependency injection.
As we know, spring java and annotation-based configurations are quite easy to use in spring based applications so I prefer to use a mix of java and annotation-based spring configurations.
Let's create a spring configuration file using java class AppConfiguration which is annotated with @Configuration annotation. This is equivalent to the spring XML configuration file without beans definition.
package com.javadevsguide.springframework.di.config;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.javadevsguide.springframework.di")
public class AppConfiguration {

}
Now create a MessageService interface and provide more than two implementations for it.
public interface MessageService {
    public void sendMsg(String message);
}
Let's implement the MessageService interface. There are many ways to send a message like an email, SMS, twitter, etc.
@Service("EmailService")
public class EmailService implements MessageService{
    public void sendMsg(String message) {
        System.out.println(message);
    }
}
@Service("SMSService")
public class SMSService implements MessageService{
    public void sendMsg(String message) {
         System.out.println(message);
    }
}
@Service("TwitterService")
public class TwitterService implements MessageService{
    public void sendMsg(String message) {
        System.out.println(message);
    }
}
Note that there are multiple implementations for the MessageService interface so to avoid ambiguity, let's use @Qualifier annotation.

It's time to demonstrate the usage of Constructor-based dependency injection. To avoid decoupling always use interfaces or abstract base classes as an instance variable and constructor arguments. In this example, we have used the 
MessageService interface.
    import org.springframework.beans.factory.annotation.Autowired;
    
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Component;
    
    import com.javadevsguide.springframework.di.service.MessageService;
    
    @Component
    public class ConstructorBasedInjection {
        private MessageService messageService;
     
        @Autowired 
        public ConstructorBasedInjection(@Qualifier("TwitterService")
            MessageService messageService) {
            super();
            this.messageService = messageService;
        }
    
        public void processMsg(String message) {
            messageService.sendMsg(message);
        }
    }
    It's time to test the usage of Constructor-based dependency injection. Let's create an IOC container object that is an ApplicationContext object and get the beans from it.
    import org.springframework.context.ApplicationContext;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    import com.javadevsguide.springframework.di.config.AppConfiguration;
    import com.javadevsguide.springframework.di.field.FieldBasedInjection;
    
    public class TestApplication {
        public static void main(String[] args) {
            ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfiguration.class);
            FieldBasedInjection  fieldBasedInjection = applicationContext.getBean(FieldBasedInjection.class);
            fieldBasedInjection.processMsg("twitter message sending ");
        }
    }
    Note that we have used the AppConfiguration class annotated with @Configuration for configurations.

    2. Setter-based dependency injection

    Setter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or no-argument static factory method to instantiate your bean.
    The following example shows a class that can only be dependency-injected using pure setter injection. This class is conventional Java.
    In the below diagram, the highlighted part shows the setter-based dependency injection.

    2.1 Setter-based dependency injection example

    Let's see the complete example to demonstrate the Setter-based dependency injection.
    As we know, spring java and annotation-based configurations are quite easy to use in spring based applications so I prefer to use a mix of java and annotation-based spring configurations.

    In this example, we have used spring Java-based container configuration.

    Let's create a spring configuration file using java class AppConfiguration and annotated with @Configuration annotation. This is equivalent to the spring XML configuration file without beans definition.
    package com.javadevsguide.springframework.di.config;
    
    import org.springframework.context.annotation.ComponentScan;
    
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan("com.javadevsguide.springframework.di")
    public class AppConfiguration {
    
    }
    Now create MessageService interface and provide more than two implementations for it.
    public interface MessageService {
        public void sendMsg(String message);
    }
    Let's implement the MessageService interface. There are many ways to send a message like through email, SMS, twitter, etc.
    @Service("EmailService")
    public class EmailService implements MessageService{
        public void sendMsg(String message) {
            System.out.println(message);
        }
    }
    @Service("SMSService")
    public class SMSService implements MessageService{
        public void sendMsg(String message) {
            System.out.println(message);
        }
    }
    @Service("TwitterService")
    public class TwitterService implements MessageService{
        public void sendMsg(String message) {
            System.out.println(message);
        }
    }
    Note that there are multiple implementations for the MessageService interface so to avoid ambiguity, let's use @Qualifier annotation.

    It's time to demonstrate the usage of Setter-based dependency injection. To avoid decoupling always use interfaces or abstract base classes as an instance variable and setter method arguments. In this example, we have used the MessageService interface.
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.annotation.Qualifier;
      import org.springframework.stereotype.Component;
      
      import com.javadevsguide.springframework.di.service.MessageService;
      
      @Component
      public class SetterBasedInjection {
          private MessageService messageService;
      
          @Autowired
          @Qualifier("TwitterService")
          public void setMessageService(MessageService messageService) {
              this.messageService = messageService;
          }
      
          public void processMsg(String message) {
              messageService.sendMsg(message);
          }
      }
      It's time to test the usage of Constructor-based dependency injection. Let's create an IOC container object that is an ApplicationContext object and get the beans from it.
      import org.springframework.context.ApplicationContext;
      
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      
      import com.javadevsguide.springframework.di.config.AppConfiguration;
      import com.javadevsguide.springframework.di.field.FieldBasedInjection;
      
      public class TestApplication {
          public static void main(String[] args) {
              ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfiguration.class);
              SetterBasedInjection  setterBasedInjection = applicationContext.getBean(SetterBasedInjection.class);
              setterBasedInjection.processMsg("twitter message sending ");
          }
      }
      Note that we have used the AppConfiguration class annotated with @Configuration for configurations.

      Conclusion

      In this example, we have seen what dependency injection in Spring, types of DI. We have demonstrated constructor-based dependency injection and setter-based dependency injection with examples. The source code of this article can be found on the GitHub project – this is an Eclipse-based project, so it should be easy to import and run as it is.
      Github Repository: Guide to Dependency Injection in Spring

      Comments

      Post a Comment