What is Inversion of Control?
Inversion of Control is a principle in software engineering by which the control of objects or portions of a program is transferred to a container or framework. It’s most often used in the context of object-oriented programming.
The advantages of this architecture are:
- decoupling the execution of a task from its implementation
- making it easier to switch between different implementations
- greater modularity of a program
- greater ease in testing a program by isolating a component or mocking its dependencies and allowing components to communicate through contracts
Inversion of Control can be achieved through various mechanisms such as: Strategy design pattern, Service Locator pattern, Factory pattern, and Dependency Injection (DI).
What is Dependency Injection?
Dependency injection is a pattern through which to implement IoC, where the control being inverted is the setting of object’s dependencies.
The act of connecting objects with other objects, or “injecting” objects into other objects, is done by an assembler rather than by the objects themselves.
In Spring Framework, the Inversion of Control (IoC) principle is implemented using the Dependency Injection (DI) design pattern.
Dependency Injection in Spring can be done through constructors, setters or fields.
Constructor-Based Dependency Injection
Person.java
package com.spring.example.bean;
public class Person {
private Address address;
public Person(Address address) {
this.address = address;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address.java
package com.spring.example.bean;
public class Address {
private String city;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
TestBeanLifeCycle.java
package com.spring.example.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.example.bean.Person;
public class TestBeanLifeCycle {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
“beanConfig.xml”);
Person person = (Person) context.getBean(“person”);
System.out.println(person.getAddress().getCity());
context.close();
}
}
Output
Mumbai
Setter-Based Dependency Injection
Person.java
package com.spring.example.bean;
public class Person {
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address.java
package com.spring.example.bean;
public class Address {
private String city;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
TestBeanLifeCycle.java
package com.spring.example.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.example.bean.Person;
public class TestBeanLifeCycle {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
“beanConfig.xml”);
Person person = (Person) context.getBean(“person”);
System.out.println(person.getAddress().getCity());
context.close();
}
}
Output
Mumbai
Field-Based Dependency Injection using @Autowired
Person.java
package com.spring.example.bean;
public class Person {
@Autowired
private Address address;
public Address getAddress() {
return address;
}
}
Address.java
package com.spring.example.bean;
public class Address {
private String city;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
TestBeanLifeCycle.java
package com.spring.example.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.example.bean.Person;
public class TestBeanLifeCycle {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
“beanConfig.xml”);
Person person = (Person) context.getBean(“person”);
System.out.println(person.getAddress().getCity());
context.close();
}
}
Output
Mumbai
Using Java Based Configuration(No Xml stuff :))
Person.java
package com.spring.example.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Person {
@Autowired
private Address address;
public Address getAddress() {
return address;
}
}
Address.java
package com.spring.example.bean;
public class Address {
private String city;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
BeanConfiguration.java
package com.spring.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.spring.example.bean.Address;
@ComponentScan(basePackages = “com.spring.example.bean”)
@Configuration
public class BeanConfiguration {
@Bean
public Address address() {
Address address = new Address();
address.setCity(“Mumbai”);
return address;
}
}
TestBeanLifeCycle.java
package com.spring.example.test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.spring.example.bean.Person;
import com.spring.example.config.BeanConfiguration;
public class TestBeanLifeCycle {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(BeanConfiguration.class);
Person person = context.getBean(Person.class);
System.out.println(person.getAddress().getCity());
context.close();
}
}
Output
Mumbai