Spring core - Dependency Injection

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

Did you find this article valuable?

Support Java Blogs By Hemant by becoming a sponsor. Any amount is appreciated!