Please read my previous vlog to understand it in a better way.
What is dependency injection in spring ?
In our java projects, the java classes are dependent on each other. So spring container creates those dependent objects and assign/inject them to the appropriate classes based on the configuration provided by programmer. This phenomena is called dependency injection.
I will be explaining below DI methods in this blog
setter injection
constructor injection
static factory method injection
instance factory method injection
Setter Injection
When we configure to do DI using Setter method then it is called setter injection. We configure setter injection using <property> tag.
name is the variable-name, value is what we inject and ref is used if we want to inject another configured bean bean.
<!-- setter injection -->
<property name="user" value="hemant" />
<property name="date" ref="date" />
Constructor Injection
When we configure to do DI using parameterized constructor then it is called constructor injection. we configure constructor injection using <constructor-arg> tag.
if we have 3 <constructor-arg> tag inside bean tag, then spring will look for constructor which has 3 parameters.
name is the variable-name, value is what we inject and ref is used if we want to inject another configured bean bean.
<!-- constructor injection -->
<constructor-arg name="user" value="hemant" />
<constructor-arg name="date" ref="date" />
Example on setter and constructor injection
Folder structure
applicationContext.xml
<?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">
<bean id="date" class="java.util.Date" />
<!-- Spring beans cfgs -->
<bean id="wmg" class="com.hk.beans.WishMessageGenerator">
<!-- constructor injection -->
<constructor-arg name="message" value="Good Morning...! " />
<!-- <constructor-arg ref="anotherBeanID"/> -->
<!-- setter injection -->
<property name="user" value="hemant" />
<property name="date" ref="date" />
</bean>
<!-- more bean definitions go here -->
</beans>
WishMessageGenerator.java
//Spring Bean class (POJO class)
package com.hk.beans;
import java.util.Date;
public class WishMessageGenerator {
private String message;
private String user;
private Date date;
public WishMessageGenerator(String message) {
System.out.println("WishMessageGenerator.WishMessageGenerator(-)");
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
System.out.println("WishMessageGenerator.setMessage(-)");
this.message = message;
}
public String getUser() {
return user;
}
public void setUser(String user) {
System.out.println("WishMessageGenerator.setUser(-)");
this.user = user;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
System.out.println("WishMessageGenerator.setDate()");
this.date = date;
}
public String sayHello() {
return getMessage() + getUser() + ". Time is : " + getDate();
}
}
BeanManagementTest.java
package com.hk.test;
import java.util.Date;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import com.hk.beans.WishMessageGenerator;
public class BeanManagementTest {
public static void main(String[] args) {
System.out.println("stat of main(-) method");
// Declare the ApplicationContext reference outside the try block to ensure its accessibility in the finally block.
ApplicationContext applicationContext = null;
try {
applicationContext = new ClassPathXmlApplicationContext("com/hk/cfgs/applicationContext.xml");
WishMessageGenerator wmg = applicationContext.getBean("wmg", WishMessageGenerator.class);
System.out.println(wmg.sayHello());
} finally {
// Close the applicationContext in the finally block to ensure it gets closed regardless of exceptions.
if (applicationContext != null) {
((ClassPathXmlApplicationContext) applicationContext).close();
}
}
System.out.println("end of main(-) method");
}
}
console output after running the BeanManagementTest class
Static factory method injection
when we configure to create object using static factory method then it is called, static factory method injection.
Below is the configuration to create own class object using static factory method. In Service class there is a static factory method "createInstance" which returns its own object
<bean id="service" class="com.hk.beans.Service" factory-method="createInstance">
</bean>
now lets see the configuration where we will create an object of java.util.Class class using its own static factory method "forName" which will have meta data of java.util.Date. As "forName" methods takes one parameter, we can use <constructor-arg> tag to send that parameter.
<!-- Bean instatation using static factory method creating its own bean
class obj -->
<bean id="c1" class="java.lang.Class" factory-method="forName">
<constructor-arg value="java.util.Date" />
</bean>
now lets see the configuration where we will use static factory method to create object of other class object. We all know "getInstance" method of java.util.Calender class returns an object of GregorianCalendar class object.
<!-- Bean instatation using static factory method creating its other class
class obj -->
<bean id="cal" class="java.util.Calendar" factory-method="getInstance" />
Instance factory method injection
when we configure to create object using instance factory method then it is called, instance factory method injection.
We have a class com.hk.beans.InstanceFactory which has a non-static method "getMessageService" which returns an object of com.hk.beans.Service. To use this instance factory method we need to do below configuration.
<bean id="instanceFactory" class="com.hk.beans.InstanceFactory">
</bean>
<bean id="messageService" factory-bean="instanceFactory"
factory-method="getMessageService">
</bean>
Below is the configuration where we will create a String object using using constructor, then we will create another String object using "concat" method of the String class. We will create a string object "hello", then using that object we will call a non-static method "concat" to create new string "hello Dear".
<!-- Bean instatation using instance factory method creating its own bean
class obj -->
<bean id="s1" class="java.lang.String">
<constructor-arg value="hello" />
</bean>
<bean id="s2" factory-bean="s1" factory-method="concat">
<constructor-arg value=" Dear" />
</bean>
In Below configuration, we create an object of java.lang.StringBuffer class and then we use the "substring" method of java.lang.StringBuffer class to create a java.lang.String object.
<!-- Bean instatation using instance factory method creating its other bean
class obj -->
<bean id="s3" class="java.lang.StringBuffer">
<constructor-arg value="hello how are u?" />
</bean>
<bean id="s4" factory-bean="s3" factory-method="substring">
<constructor-arg value="0" />
<constructor-arg value="5" />
</bean>
<!-- more bean definitions go here -->
Example on factory method injections
folder structure
applicationContext.xml
<?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">
<!-- Spring beans cfgs -->
<bean id="service"
class="com.hk.beans.Service"
factory-method="createInstance">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="instanceFactory" class="com.hk.beans.InstanceFactory">
</bean>
<bean id="messageService" factory-bean="instanceFactory"
factory-method="getMessageService">
</bean>
<!-- Bean instatation using static factory method creating its own bean
class obj -->
<bean id="c1" class="java.lang.Class" factory-method="forName">
<constructor-arg value="java.util.Date" />
</bean>
<!-- Bean instatation using static factory method creating its other class
class obj -->
<bean id="cal" class="java.util.Calendar" factory-method="getInstance" />
<!-- Bean instatation using instance factory method creating its own bean
class obj -->
<bean id="s1" class="java.lang.String">
<constructor-arg value="hello" />
</bean>
<bean id="s2" factory-bean="s1" factory-method="concat">
<constructor-arg value=" Dear" />
</bean>
<!-- Bean instatation using instance factory method creating its other bean
class obj -->
<bean id="s3" class="java.lang.StringBuffer">
<constructor-arg value="hello how are u?" />
</bean>
<bean id="s4" factory-bean="s3" factory-method="substring">
<constructor-arg value="0" />
<constructor-arg value="5" />
</bean>
<!-- more bean definitions go here -->
</beans>
InstanceFactory.java
package com.hk.beans;
public class InstanceFactory {
//One factory class can also hold more than one factory method
private static MessageService messageService = new MessageService();
public MessageService getMessageService() {
return messageService;
}
}
MessageService.java
package com.hk.beans;
public class MessageService {
public String getMessage() {
return "Good Morning...!";
}
}
Service.java
package com.hk.beans;
import java.util.Date;
public class Service {
private static Service service = new Service();
private Service() {
}
public Date getCurrentDateTime() {
return new Date();
}
public static Service createInstance() {
return service;
}
}
BeanManagementTest.java
package com.hk.test;
import java.util.Calendar;
import java.util.Date;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hk.beans.MessageService;
import com.hk.beans.Service;
public class BeanManagementTest {
// spring 5.0.x doc
// https://docs.spring.io/spring-framework/docs/5.0.x/spring-framework-reference/
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
System.out.println("stat of main(-) method");
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"com/hk/cfgs/applicationContext.xml");
// Static Factory Method
System.out.println("...........................................");
Service service = applicationContext.getBean("service", Service.class);
System.out.println(service.getCurrentDateTime());
//Instance Factory Method
System.out.println("...........................................");
MessageService messageService = applicationContext.getBean("messageService", MessageService.class);
System.out.println(messageService.getMessage());
//Static and Instance Factory methods with arguments
System.out.println("...........................................");
Class c1=applicationContext.getBean("c1",Class.class);
System.out.println("c1 obj class: "+c1.getClass()+" c1 obj data::"+c1);
Date dt = (Date)c1.newInstance();
System.out.println(dt);
System.out.println("...........................................");
Calendar cal =applicationContext.getBean("cal",Calendar.class);
System.out.println("cal obj calss name:"+cal.getClass()+" cal obj data::"+cal);
System.out.println("..............................................");
String s2=applicationContext.getBean("s2",String.class);
System.out.println("s2 obj class :"+s2.getClass()+" s2 obj data::"+s2);
System.out.println("........................................");
String s4=applicationContext.getBean("s4",String.class);
System.out.println("s4 obj class :"+s4.getClass()+" s4 obj data::"+s4);
System.out.println("end of main(-) method");
}
}
console output after running the BeanManagementTest class
Java Based Configuration of DI (No XML at all)
Below is the java project which has 100% java based dependency injection.
Folder structure
Lets create a config class which will have all the spring bean configuration. We should annotate the class with @Configuration annotation and each bean will be configured in methods and will return the desired objects, these methods will be annotated with @Bean annotation.
if we give name parameter value in @Bean annotation then the value will be the bean id, else the method name will be the bean id.
ApplicationContextBeanConfiguration.java
package com.hk.cfgs;
import java.util.Calendar;
import java.util.Date;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.hk.beans.InstanceFactory;
import com.hk.beans.MessageService;
import com.hk.beans.Service;
import com.hk.beans.WishMessageGenerator;
@Configuration
public class ApplicationContextBeanConfiguration {
@Bean(name = "date")
public Date date() {
return new Date();
}
@Bean(name = "wmg")
public WishMessageGenerator wishMessageGenerator() {
WishMessageGenerator wmg = new WishMessageGenerator("Good Morning...!");//constructor injection
wmg.setUser("hemant");
wmg.setDate(date()); // setter injection
return wmg;
}
@Bean
public Service service() {
return Service.createInstance();//static factory method injection
}
@Bean
public InstanceFactory instanceFactory() {
return new InstanceFactory();
}
@Bean
public MessageService messageService(InstanceFactory instanceFactory) {
return instanceFactory.getMessageService();//instance factory method injection
}
@Bean
public Class<?> c1() throws ClassNotFoundException {
return Class.forName("java.util.Date");
}
@Bean
public Calendar cal() {
return Calendar.getInstance();
}
@Bean
public String s1() {
return new String("hello");
}
@Bean
public String s2(String s1) {
return s1.concat(" Dear");
}
@Bean
public StringBuffer s3() {
return new StringBuffer("hello how are u?");
}
@Bean
public String s4(StringBuffer s3) {
return s3.substring(0, 5);
}
}
InstanceFactory.java
package com.hk.beans;
public class InstanceFactory {
//One factory class can also hold more than one factory method
private static MessageService messageService = new MessageService();
public MessageService getMessageService() {
return messageService;
}
}
MessageService.java
package com.hk.beans;
public class MessageService {
public String getMessage() {
return "Good Morning...!";
}
}
Service.java
package com.hk.beans;
import java.util.Date;
public class Service {
private static Service service = new Service();
private Service() {
}
public Date getCurrentDateTime() {
return new Date();
}
public static Service createInstance() {
return service;
}
}
WishMessageGenerator.java
//Spring Bean class (POJO class)
package com.hk.beans;
import java.util.Date;
public class WishMessageGenerator {
private String message;
private String user;
private Date date;
public WishMessageGenerator(String message) {
System.out.println("WishMessageGenerator.WishMessageGenerator(-)");
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
System.out.println("WishMessageGenerator.setMessage(-)");
this.message = message;
}
public String getUser() {
return user;
}
public void setUser(String user) {
System.out.println("WishMessageGenerator.setUser(-)");
this.user = user;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
System.out.println("WishMessageGenerator.setDate()");
this.date = date;
}
public String sayHello() {
return getMessage() + getUser() + ". Time is : " + getDate();
}
}
BeanManagementTest.java
package com.hk.test;
import java.util.Calendar;
import java.util.Date;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.hk.beans.MessageService;
import com.hk.beans.Service;
import com.hk.beans.WishMessageGenerator;
public class BeanManagementTest {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
System.out.println("Start of main method");
// Create the Spring application context with the configuration class
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.hk.cfgs");
// Retrieve the bean from the context
WishMessageGenerator wmg = context.getBean("wmg", WishMessageGenerator.class);
System.out.println("Message: " + wmg.sayHello());
// Static Factory Method
System.out.println("...........................................");
Service service = context.getBean("service", Service.class);
System.out.println(service.getCurrentDateTime());
// Instance Factory Method
System.out.println("...........................................");
MessageService messageService = context.getBean("messageService", MessageService.class);
System.out.println(messageService.getMessage());
// Static and Instance Factory methods with arguments
System.out.println("...........................................");
Class c1 = context.getBean("c1", Class.class);
System.out.println("c1 obj class: " + c1.getClass() + " c1 obj data::" + c1);
Date dt = (Date) c1.newInstance();
System.out.println(dt);
System.out.println("...........................................");
Calendar cal = context.getBean("cal", Calendar.class);
System.out.println("cal obj calss name:" + cal.getClass() + " cal obj data::" + cal);
System.out.println("..............................................");
String s2 = context.getBean("s2", String.class);
System.out.println("s2 obj class :" + s2.getClass() + " s2 obj data::" + s2);
System.out.println("........................................");
String s4 = context.getBean("s4", String.class);
System.out.println("s4 obj class :" + s4.getClass() + " s4 obj data::" + s4);
// Close the context
context.close();
System.out.println("End of main method");
}
}
console output after running BeanManagementTest class