Inversion of Control [IOC]
In this tutorial, we are going to discuss the Inversion of control in the spring framework. In general, in enterprise applications, if we need any service in our application, we have to request the service provider, where the service provider has to create the required service. The service provider has to send that service to the respective application.
In enterprise applications, Inversion of Control is a design pattern or a design principle, and it will make the service provider to identify the required services of the enterprise applications. It will make the service provider to create and inject the necessary services to the application without expecting any request from the application. IOC is available in the following two forms.
- Dependency Lookup
- Dependency Injection
1. Dependency Lookup
In Dependency Lookup, Service Provider will create the services and maintain that services either in the registry software or in the containers. We have to perform lookup operations to get the required services. There are two ways to get achieve Dependency lookup.
- Dependency Pull
- Contextualized Dependency Lookup
1. Dependency Pull
In Dependency Pull, Service Provider will create services. It will keep that services in any registry software’s, where we have to perform a lookup operation to get the required services, that is, pull the required services from registry software’s.
E.g.
When we start application Servers like WebLogic, JBOSS, WebSphere and Glassfish, Application Servers will automatically create a Datasource object, and Application Servers will keep that Datasource object in JNDI Server as per the server settings which we made in the Application Server. In this context, we have to perform a lookup(–) operation over the JNDI server based on the logical name to get the required Datasource object.
In RMI Applications, the User-defined Registry Application will create a Remote object. It will keep that Remote object in RMIRegistry with a particular logical name to get the required Remote object in the Client Application. We have to perform a lookup operation over RMIRegistry based on the logical name.
2. Contextualized Dependency Lookup
In this mechanism, Service Provider will create the services and manage services. In this context, we have to perform a lookup operation to get the required services from Service Provider.
E.g.
In general, in web applications, when we start the application Server, the Container will recognize all the web applications, and Container will deploy all the web applications into the server. When web applications are deployed in the server, the Container will automatically create the ServletContext object, and the Container will manage the ServletContext object. To get the ServletContext object, we have to use the getServletContext() method from GenericServlet directly without using any reference variable from ServletConfig object reference from ServletRequest object reference, that is, performing a lookup operation in Container to get ServletContext object.
2. Dependency Injection
Dependency Injection is the main functionality provided by Spring IOC(Inversion of Control). Dependency Injection (DI) is a design pattern that removes the dependency from the programming code so that it can be easy to manage and test the application. Dependency Injection makes our programming code loosely coupled.
In this mechanism, the Service Provider will create the services and inject the required services to the application directly without performing lookup operations and getting requests from the client.
E.g.
In web applications, when we submit request to a particular Servlet, Container will execute the requested Servlet by performing the Servlet life cycle actions like Servlet Loading, Servlet Instantiation, Servlet Initialization, Request Processing and Servlet Deinstantiation. In Servlet initialization phase, container will create ServletConfig object and Container will inject ServletConfig object to the Servlet program through init(–) method, in Request Processing phase, Container has to create request and response objects and Container has to inject request and response objects to the Servlet program through service() method. There are two ways to achieve dependency injection.
- Constructor Dependency Injection
- Setter Method Dependency Injection
1. Constructor Dependency Injection
If we inject dependent values to the Bean object through Constructor, this type of Dependency Injection is called “Constructor Dependency Injection”.
If we want to use constructor dependency injection in Spring applications, first we have to declare the respective parameterized constructor in the corresponding bean class, then we have to declare those constructor arguments in the spring configuration file by using the tags.
E.g
package com.ashok.spring.core.bean.dependencyinjection.constructor.beans;
/**
*
* @author Ashok Kumar
*
*/
public class Employee {
private String empName;
private String empId;
private String empAddress;
private double salary;
public Employee(String empName, String empId, String empAddress, double salary) {
super();
this.empName = empName;
this.empId = empId;
this.empAddress = empAddress;
this.salary = salary;
}
@Override
public String toString() {
return "Employee [empName=" + empName + ", empId=" + empId + ", empAddress=" + empAddress + ", salary=" + salary
+ "]";
}
}
<?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-3.0.xsd">
<bean id = "emp" class = "com.ashok.spring.core.bean.dependencyinjection.constructor.beans.Employee">
<constructor-arg value = "Ashok Kumar"/>
<constructor-arg value = "Emp0087"/>
<constructor-arg value = "Bhimavaram"/>
<constructor-arg value = "50000"/>
</bean>
</beans>
package com.ashok.spring.core.bean.dependencyinjection.constructor.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ashok.spring.core.bean.dependencyinjection.constructor.beans.Employee;
/**
*
* @author Ashok Kumar
*
*/
public class TestSpringApplication {
@SuppressWarnings("resource")
public static void main(String[] args) {
String configFile = "/com/ashok/spring/core/bean/dependencyinjection/constructor/config/applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(configFile);
Employee emp = (Employee) context.getBean("emp");
System.out.println(emp);
}
}
Output
Employee [empName=Ashok Kumar, empId=Emp0087, empAddress=Bhimavaram, salary=50000.0]
2. Setter Method Dependency Injection
If we inject dependent values to the Bean through setXXX() methods, then it is called “Setter Method Dependency Injection”.
To inject primitive values and String values to the bean object, then we have to use “value” attributes in or tags in the beans configuration file, but, If we want to inject User-defined data types, that is, Object reference values then we have to use “ref” attribute in tag or tag.
E.g
package com.ashok.spring.core.bean.dependencyinjection.setter.beans;
/**
*
* @author Ashok Kumar
*
*/
public class Employee {
private String empName;
private String empId;
private String empAddress;
private double salary;
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getEmpAddress() {
return empAddress;
}
public void setEmpAddress(String empAddress) {
this.empAddress = empAddress;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee [empName=" + empName + ", empId=" + empId + ", empAddress=" + empAddress + ", salary=" + salary
+ "]";
}
}
<?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-3.0.xsd">
<bean id = "emp" class = "com.ashok.spring.core.bean.dependencyinjection.setter.beans.Employee">
<property name = "empName" value = "Ashok Kumar"/>
<property name = "empId" value = "Emp0087"/>
<property name = "empAddress" value = "Bhimavaram"/>
<property name = "salary" value = "45000"/>
</bean>
</beans>
package com.ashok.spring.core.bean.dependencyinjection.setter.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ashok.spring.core.bean.dependencyinjection.setter.beans.Employee;
/**
*
* @author Ashok Kumar
*
*/
public class TestSpringApplication {
@SuppressWarnings("resource")
public static void main(String[] args) {
String configFile = "/com/ashok/spring/core/bean/dependencyinjection/setter/config/applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(configFile);
Employee emp = (Employee) context.getBean("emp");
System.out.println(emp);
}
}
Output
Employee [empName=Ashok Kumar, empId=Emp0087, empAddress=Bhimavaram, salary=45000.0]
Different Types of Elements Injection
- In Spring applications, if we want to inject User defined data types then we have to use either “ref” attribute in and tags or we have to use nested tag under and tags.
- In spring applications, if we want to inject a List of elements in beans, we have to declare the corresponding property as java.util.List and we have to provide values in configuration file by using tag in tag or in tag.
- In Spring applications, if we want to inject Set of elements in the Bean object, we must declare the corresponding property as java.util.Set and we have to provide values in configuration file by using tag under tag or tag.
- In Spring applications, if we want to inject Map of elements in Bean object, we have to declare the corresponding property as java.util.Map and we have to provide Key-Value pairs in configuration file by using and tags under tag or tag.
- In Spring applications, if we want to inject Properties of elements in the Bean object, we have to declare the corresponding property as java.util.Properties and we have to provide Key-Value pairs in configuration file by using and tags under tag or tag.
E.g
package com.ashok.spring.core.bean.dependencyinjection.collections.beans;
/**
*
* @author Ashok Kumar
*
*/
public class Address {
private String street;
private String city;
private String country;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
@Override
public String toString() {
return "Address [street=" + street + ", city=" + city + ", country=" + country + "]";
}
}
package com.ashok.spring.core.bean.dependencyinjection.collections.beans;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
*
* @author Ashok Kumar
*
*/
public class Student {
private String sid;
private String sname;
private Address saddress;
private List<String> squal;
private Set<String> scourses;
private Map<String, String> scoursesAndFaculty;
private Properties scourseAndCost;
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Address getSaddress() {
return saddress;
}
public void setSaddress(Address saddress) {
this.saddress = saddress;
}
public List<String> getSqual() {
return squal;
}
public void setSqual(List<String> squal) {
this.squal = squal;
}
public Set<String> getScourses() {
return scourses;
}
public void setScourses(Set<String> scourses) {
this.scourses = scourses;
}
public Map<String, String> getScoursesAndFaculty() {
return scoursesAndFaculty;
}
public void setScoursesAndFaculty(Map<String, String> scoursesAndFaculty) {
this.scoursesAndFaculty = scoursesAndFaculty;
}
public Properties getScourseAndCost() {
return scourseAndCost;
}
public void setScourseAndCost(Properties scourseAndCost) {
this.scourseAndCost = scourseAndCost;
}
@Override
public String toString() {
return "Student [sid=" + sid + ", sname=" + sname + ", saddress=" + saddress + ", squal=" + squal
+ ", scourses=" + scourses + ", scoursesAndFaculty=" + scoursesAndFaculty + ", scourseAndCost="
+ scourseAndCost + "]";
}
}
<?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-3.0.xsd">
<bean id="address"
class="com.ashok.spring.core.bean.dependencyinjection.collections.beans.Address">
<property name="street" value="APHB Colony" />
<property name="city" value="Bhimavaram" />
<property name="country" value="India" />
</bean>
<bean id="student"
class="com.ashok.spring.core.bean.dependencyinjection.collections.beans.Student">
<property name="sid" value="12345" />
<property name="sname" value="Ashok Kumar" />
<property name="saddress">
<ref bean="address" />
</property>
<property name="squal">
<list>
<value>BSc Computers</value>
<value>MCA</value>
</list>
</property>
<property name="scourses">
<set>
<value>Core Java</value>
<value>Adv Java</value>
<value>Spring</value>
<value>Hibernate</value>
</set>
</property>
<property name="scoursesAndFaculty">
<map>
<entry key="Core Java" value="Ratan" />
<entry key="Adv Java" value="Durga" />
<entry key="Spring" value="Sriman" />
<entry key="Hibernate" value="Naveen" />
</map>
</property>
<property name="scourseAndCost">
<props>
<prop key="Core Java">1500</prop>
<prop key="Adv Java">2000</prop>
<prop key="Spring">3000</prop>
<prop key="Hibernate">3000</prop>
</props>
</property>
</bean>
</beans>
package com.ashok.spring.core.bean.dependencyinjection.collections.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ashok.spring.core.bean.dependencyinjection.collections.beans.Student;
/**
*
* @author Ashok Kumar
*
*/
public class TestSpringApplication {
@SuppressWarnings("resource")
public static void main(String[] args) {
String configFile = "/com/ashok/spring/core/bean/dependencyinjection/collections/config/applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(configFile);
Student emp = (Student) context.getBean("student");
System.out.println(emp);
}
}
Output
Student [sid=12345, sname=Ashok Kumar, saddress=Address [street=APHB Colony, city=Bhimavaram, country=India], squal=[BSc Computers, MCA], scourses=[Core Java, Adv Java, Spring, Hibernate], scoursesAndFaculty={Core Java=Ratan, Adv Java=Durga, Spring=Sriman, Hibernate=Naveen}, scourseAndCost={Spring=3000, Adv Java=2000, Hibernate=3000, Core Java=1500}]
Circular Dependency Injection
In Spring applications, if more than one bean object depends on each other through constructor dependency injection, then it is called Circular Dependency Injection, which is not supported by the Spring framework. It can raise an exception like “org.springframework. beans.factory.BeanCurrentlyInCreationException”.
package com.ashok.spring.core.bean.dependencyinjection.circular.constructor.beans;
/**
*
* @author Ashok Kumar
*
*/
public class Branch {
Student student;
public Branch(Student student) {
this.student = student;
}
public String getBranchName() {
return "Bhimavaram";
}
}
package com.ashok.spring.core.bean.dependencyinjection.circular.constructor.beans;
/**
*
* @author Ashok Kumar
*
*/
public class Student {
Branch branch;
public Student(Branch branch) {
this.branch = branch;
}
public String getStudentName() {
return "Ashok Kumar";
}
}
<?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-3.0.xsd">
<bean id="student"
class="com.ashok.spring.core.bean.dependencyinjection.circular.constructor.beans.Student">
<constructor-arg ref="branch" />
</bean>
<bean id="branch" class="com.ashok.spring.core.bean.dependencyinjection.circular.constructor.beans.Branch">
<constructor-arg ref="student" />
</bean>
</beans>
package com.ashok.spring.core.bean.dependencyinjection.circular.constructor.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ashok.spring.core.bean.dependencyinjection.circular.constructor.beans.Branch;
import com.ashok.spring.core.bean.dependencyinjection.circular.constructor.beans.Student;
/**
*
* @author Ashok Kumar
*
*/
public class TestSpringApplication {
@SuppressWarnings("resource")
public static void main(String[] args) {
String configFile = "/com/ashok/spring/core/bean/dependencyinjection/circular/constructor/config/applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(configFile);
Student student = (Student) context.getBean("student");
System.out.println(student);
Branch branch = (Branch) context.getBean("branch");
System.out.println(branch);
}
}
Output
org.springframework.beans.factory.BeanCurrentlyInCreationException"
In Spring applications, if we want to resolve Circular Dependency Injection, we have to use Setter Method dependency Injection instead of Constructor Dependency Injection.
E.g
package com.ashok.spring.core.bean.dependencyinjection.circular.setter.beans;
/**
*
* @author Ashok Kumar
*
*/
public class Branch {
Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
package com.ashok.spring.core.bean.dependencyinjection.circular.setter.beans;
/**
*
* @author Ashok Kumar
*
*/
public class Student {
Branch branch;
public Branch getBranch() {
return branch;
}
public void setBranch(Branch branch) {
this.branch = branch;
}
}
<?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-3.0.xsd">
<bean id="student"
class="com.ashok.spring.core.bean.dependencyinjection.circular.setter.beans.Student">
<property name="branch" ref="branch" />
</bean>
<bean id="branch"
class="com.ashok.spring.core.bean.dependencyinjection.circular.setter.beans.Branch">
<property name="student" ref="student" />
</bean>
</beans>
package com.ashok.spring.core.bean.dependencyinjection.circular.setter.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ashok.spring.core.bean.dependencyinjection.circular.setter.beans.Branch;
import com.ashok.spring.core.bean.dependencyinjection.circular.setter.beans.Student;
/**
*
* @author Ashok Kumar
*
*/
public class TestSpringApplication {
@SuppressWarnings("resource")
public static void main(String[] args) {
String configFile = "/com/ashok/spring/core/bean/dependencyinjection/circular/setter/config/applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(configFile);
Student student = (Student) context.getBean("student");
System.out.println(student);
Branch branch = (Branch) context.getBean("branch");
System.out.println(branch);
}
}
Output
com.ashok.spring.core.bean.dependencyinjection.circular.setter.beans.Student@3224f60b
com.ashok.spring.core.bean.dependencyinjection.circular.setter.beans.Branch@63e2203c
Note
Suppose we provide both Constructor dependency injection and Setter method dependency injection to a single bean. In that case, IOC Container will perform constructor dependency injection first when creating the Bean object. After that, IOC Container will perform a Setter method dependency injection, that is, Constructor Dependency Injection provided values are overridden with setter method dependency injection provided values. Finally, the Bean object can manage the Setter method dependency Injection provided values.
Difference between Constructor and Setter Dependency Injection
1. In Constructor dependency injection, dependent values are injected through a particular constructor.
In the Setter method dependency injection, dependent values are injected through properties respective setXXX() methods.
2. In Constructor Dependency Injection, readability is not good because, in Constructor dependency injection, we cannot identify to which property we are injecting dependent values.
In the setter method, Dependency injection Readability is very good because, in the Setter method Dependency injection, we can identify that to property we can inject the dependent values.
3. In Constructor Dependency injection, dependency injection is possible when all dependent objects are getting ready. If dependent objects are not ready, then Constructor dependency injection is not possible.
In Setter method dependency injection, even though dependent values are not ready, Setter method dependency injection will be performed.
4. In the case of constructor dependency injection, partial dependency injection is impossible because we have to access the constructor bypassing the required number of parameter values.
In the case of setter method dependency injection, partial dependency injection is possible because we can access the setXXX() method individually.
5. In the case of constructor dependency injection, it is not simple to change the values in the bean object.
In the case of the Setter method dependency injection, it is very simple to change the values in the bean object.
6. In Constructor dependency injection, for every change on values, a new bean object is created because, for every change, we have to call the constructor explicitly.
In the Setter method dependency injection, for every change on values, a new object is not created because, for every change, we can access the setXXX() method explicitly.
7. Constructor dependency injection will make the bean object as “Immutable Object”.
Setter method dependency injection will make the bean object as “mutable Object”.
8. Suppose we provide both Constructor and setter method dependency injection to a single bean object. In that case, setter method dependency injection overrides constructor dependency injection, but constructor dependency injection is not overriding setter method dependency injection.
9. Constructor dependency injection does not support circular dependency injection.
Setter method dependency injection support circular dependency injection.
10. Constructor dependency injection will give a guarantee for dependency injection.
Setter method dependency injection will not give a guarantee for dependency injection.
11. In Spring applications, if we have more elements to inject, it is suggestible to use Constructor dependency injection instead of setter method dependency injection.