Spring Core - Different Types of Bean Injection

1. Overview

Dependency Injection is a very common technique in software engineering whereby an object supplies the dependencies of another object. Means that DI is about passing a dependency object to another a dependent object.
Assume we have a client and a service that would be used by the client. We pass the service to the client rather than allowing the client to build it. DI is commonly related to a wide known taxonomy which is Inversion of control aka IoC. But simply, IoC is a more general than the DI. IoC means letting the other code call you rather than insisting od doing the calling.
All of this is managed through the Spring Container which requires some sort of configurations that are presented through XML-based configuration or Annotation-based configuration. We will focus on the Annotation-based one in the below subjects.

2. Maven Configuration

We need to make sure that Spring core and JUnited dependencies exists in our pom.xml

<properties>
 <!-- Spring -->
 <spring-framework.version>4.3.4.RELEASE</spring-framework.version>
 <!-- Test -->
 <junit.version>4.12</junit.version>
</properties>
 
<dependencies>
 <!-- Spring and Transactions -->
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>${spring-framework.version}</version>
 </dependency>
 <!-- Test Artifacts -->
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>${spring-framework.version}</version>
  <scope>test</scope>
 </dependency>
 <dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>${junit.version}</version>
  <scope>test</scope>
 </dependency>
</dependencies>

3. Project Structure

Let's assume we have a requirement for building a notification service that's responsible for sending different notifications through different services like Email or SMS. Hence we will have a NotificationService class that's composed of some other services like EmailService and SMSService.

3.1. Classes Implementation

Message.java represents the model for an object that will be passed to whether the constructor or the setter method during the injection.
public class Message {

 private String body;
 private String from;
 private String to;

 public void setBody(String body) {
  this.body = body;
 }

 public String getBody() {
  return body;
 }

 public void setFrom(String from) {
  this.from = from;
 }

 public String getFrom() {
  return from;
 }

 public void setTo(String to) {
  this.to = to;
 }

 public String getTo() {
  return to;
 }
}
MessageService.java is the interface to unify the contract for two services that will create. It contains only one method signature that will be implemented later.
public interface MessageService {
 void sendMessage();
 Message getMessage();
}
We will create two beans each with unique names emailService and smsService that we will use for injection through the AppConfig class.
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "com.baeldung.spring.core.di")
public class AppConfig {
 
 @Bean
 @Qualifier("emailMessage")
 public Message emailMessage() {
  Message emailMessage = new Message();
  emailMessage.setBody("email message body");
  emailMessage.setFrom("user1");
  emailMessage.setTo("user2");
  return emailMessage;
 }
 
 @Bean
 @Qualifier("smsMessage")
 public Message smsMessage() {
  Message smsMessage = new Message();
  smsMessage.setBody("sms message body");
  smsMessage.setFrom("user2");
  smsMessage.setTo("user1");
  return smsMessage;
 }
}

4. Dependency Injection Types

Now let's talk precisely about the DI in Spring that exists in two major types: Constructor-based and Setter-based.

4.1. Constructor-based

This is achieved by invoking the constructor arguments and passing the relative arguments objects to it which we already call dependencies. Let's see how we achieve so in our example. We create a dependency for the model object Message in the AppConfig.java class configurations and set the values for its properties. We will actually create two dependencies for this dependency model.
The class EmailServiceBean.java is the first implementation of the MessageService interface. So it implements the the sendMessage() and prints to the console the values of the Message object. As you can see there are no setter method for the object of Message rather than that we have one a constructor that we will depend on for the constructor injection.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("emailService")
public class EmailServiceBean implements MessageService {
 
 private Message message;
 
 @Autowired
 public EmailServiceBean(Message emailMessage) {
  this.message = emailMessage;
 }
 
 public void sendMessage() {
  System.out.println("sending email message");
  System.out.println("from: " + this.message.getFrom());
  System.out.println("to: " + this.message.getTo());
  System.out.println("body: " + this.message.getBody());
 }

 public Message getMessage() {
  return message;
 }
}

4.2. Setter-based

On the other hand, Setter-based injection is achieved by calling a setter method in our bean which will be SMSServiceBean that has composition of also the Message model. So the Spring container injects the other reference of the Message dependency with name equals smsMessage that's why we user the @Qualifier annotation above the setMessage method.
SMSServiceBean.java is another implementation for the interface MessageService. This one is similar to the EmailServiceBean but it contains a setter method for the Message object. This method is annotated with @Autowired to point out that the Message object will be injected through the Spring container as a setter-based injection.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service("smsService")
public class SMSServiceBean implements MessageService {
 
 private Message message;

 public void sendMessage() {
  System.out.println("sending sms message");
  System.out.println("from: " + this.message.getFrom());
  System.out.println("to: " + this.message.getTo());
  System.out.println("body: " + this.message.getBody());
 }
 
 @Autowired
 @Qualifier("smsMessage")
 public void setMessage(Message message) {
  this.message = message;
 }

 public Message getMessage() {
  return message;
 }
}

5. Running the Example

Now, we reach out the class Application.java that contains the main method. It should look like so:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {

 public static void main(String[] args) {
  ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
  
  EmailServiceBean emailServiceBean = (EmailServiceBean) context.getBean("emailService");
  emailServiceBean.sendMessage();
  
  System.out.println();
  
  SMSServiceBean smsServiceBean = (SMSServiceBean) context.getBean("smsService");
  smsServiceBean.sendMessage();
 }
}
We can also use the JUnit case ApplicationTest.java for initiating the Spring container and testing both services (EmailServiceBean and SMSServiceBean).
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.baeldung.spring.core.di.service.MessageService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { AppConfig.class })
public class ApplicationTest {

 @Autowired
 @Qualifier("emailService")
 MessageService emailServiceBean;

 @Autowired
 @Qualifier("smsService")
 MessageService smsServiceBean;

 @Test
 public void testSendEmailMessage() {
  smsServiceBean.sendMessage();
  
  assertEquals(emailServiceBean.getMessage().getBody(), "email message body");
  assertEquals(emailServiceBean.getMessage().getFrom(), "user1");
  assertEquals(emailServiceBean.getMessage().getTo(), "user2");
 }
 
 @Test
 public void testSendSMSMessage() {
  smsServiceBean.sendMessage();

  assertEquals(smsServiceBean.getMessage().getBody(), "sms message body");
  assertEquals(smsServiceBean.getMessage().getFrom(), "user2");
  assertEquals(smsServiceBean.getMessage().getTo(), "user1");
 }
}
Running both classes will create the below output:
sending email message
from: user1
to: user2
body: email message body

sending sms message
from: user2
to: user1
body: sms message body

6. Conclusion

When to use what?. Actually we can mix using both but Spring encourages using the constructor-based injection for the mandatory dependencies and the setter-based injection in the optional ones.Despite of we can use @Required annotation on the setter method to make the property a mandatory dependency. Also, it's recommended to use the constructor-based to implement application components as immutable objects and to ensure that required dependencies are not null.
Now that we went through the basics of the injection types in Spring. I urge to get your hands and try running that examples and explore more annotations and configurations that can be applied. Happy coding :)

Comments

  1. AWS Training in Bangalore - Live Online & Classroom
    myTectra Amazon Web Services (AWS) certification training helps you to gain real time hands on experience on AWS. myTectra offers AWS training in Bangalore using classroom and AWS Online Training globally. AWS Training at myTectra delivered by the experienced professional who has atleast 4 years of relavent AWS experince and overall 8-15 years of IT experience. myTectra Offers AWS Training since 2013 and retained the positions of Top AWS Training Company in Bangalore and India.


    IOT Training in Bangalore - Live Online & Classroom
    IOT Training course observes iot as the platform for networking of different devices on the internet and their inter related communication. Reading data through the sensors and processing it with applications sitting in the cloud and thereafter passing the processed data to generate different kind of output is the motive of the complete curricula. Students are made to understand the type of input devices and communications among the devices in a wireless media.

    ReplyDelete
  2. I would like to say thank you for the amazing details and concepts you are sharing in this.

    Oracle Performance Tunning Training in Chennai
    Oracle Performance Tunning Training

    ReplyDelete
  3. Superb. I really enjoyed very much with this article here. Really it is an amazing article I had ever read. I hope it will help a lot for all. Thank you so much for this amazing posts and please keep update like this excellent article. thank you for sharing such a great blog with us.

    python interview questions and answers
    python tutorials
    python course institute in electronic city

    ReplyDelete
  4. Superb. I really enjoyed very much with this article here. Really it is an amazing article I had ever read. I hope it will help a lot for all. Thank you so much for this amazing posts and please keep update like this excellent article. thank you for sharing such a great blog with us.
    Java training in Chennai | Java training institute in Chennai | Java course in Chennai

    Java training in Bangalore | Java training in Electronic city

    Java training in Bangalore | Java training in Marathahalli

    Java training in Bangalore | Java training in Btm layout

    ReplyDelete
  5. Really you have done great job,There are may person searching about that now they will find enough resources by your post
    Devops Training courses
    Devops Training in Bangalore
    Best Devops Training in pune
    Devops interview questions and answers

    ReplyDelete
  6. Thank you for sharing such a nice and interesting blog with us. Hope it might be much useful for us. keep on updating...!!

    Article submission sites
    Technology

    ReplyDelete
  7. Some us know all relating to the compelling medium you present powerful steps on this blog and therefore strongly encourage contribution from other ones on this subject while our own child is truly discovering a great deal. Have fun with the remaining portion of the year.
    angularjs-Training in sholinganallur

    angularjs-Training in velachery

    angularjs-Training in pune

    angularjs Training in bangalore

    angularjs Training in bangalore

    angularjs Training in btm

    angularjs Training in electronic-city

    ReplyDelete

Post a Comment

Popular posts from this blog

PrimeFaces Push with Atmosphere

Creating JSF/CDI Maven project on Eclipse

Adding MyBatis mapper files dynamically