As per Martin Fowler, “In Java community there's been a rush of lightweight containers that help to assemble components from different projects into a cohesive application. Underlying these containers is a common pattern to how they perform the wiring, a concept they refer under the very generic name - Inversion of Control”.
Inversion of Control/Dependency Injection pattern:
• Inversion of Control (IoC) container is a light weight container that helps assembling components into a cohesive application. Examples of such containers are Spring IoC Container, Pico Container etc.
• Dependency Injection (DI) pattern is a design pattern for the IoC containers for wiring components.
• In simple words, generally in Java programming we have a scenario where one object creates object instances of other dependant classes using the “new” keyword thus tightly coupling the dependant object with the actual object. To arrive at an loosely coupled model, rather than creating the dependant objects from the main object, we have assemblers/containers which assembles these dependant objects with the main object. This inverse process of creating the dependant object and injecting it to the main object is termed as DI.
• There are three different styles of DI namely Constructor Injection, Setter Injection and Interface Injection which we will discuss further in this article.
Spring: The Core Technologies:
Spring framework is an implementation of the Inversion of Control (IoC) design pattern and uses the org.springframework.beans and org.springframework.context as the core base packages. Now we will see using the two underlying interfaces as part of the above packages namely org.springframework.beans.factory.BeanFactory and org.springframework.context.ApplicationContext. They apply the Dependency Injection (DI) pattern to separate application’s configuration and dependency specification from actual code just behaving like the assembler briefed earlier.
The BeanFactory interface:
• BeanFactory interface is an implementation of factory design pattern allowing an object to be created and retrieved by name through advanced configuration mechanism.
• In short, it just instantiates and configure beans.
• It lazily loads all singleton beans. That is, it does not create bean instances when Bean Factory is created.
The ApplicationContext interface:
• ApplicationContext interface is a superset of BeanFactory that will include all functionalities that BeanFactory provides apart from other additional enterprise functionalities.
• In short, it instantiates, configures and provides supporting infrastructure to enable enterprise features like transactions, AOP, i18N, etc and is preferable over BeanFactory.
• It pre-loads all singleton beans. That is, it creates bean instances when Application Context is created.
Spring IoC Container:
• A light weight container for assembling components.
• BeanFactory and ApplicationFactory are the actual representation of the Spring IoC Container.
• In Spring context, objects (POJO) are referred as beans and are managed by the bean container also termed as IoC container. This means that IoC container provides a run-time environment for all your beans just like the Web Container providing run-time environment for all server-side scripting like Java Servlets, JSP managing its life cycle.
• Spring IoC Container manages the beans based on the bean definitions specified inside a XML based configuration metadata. This configuration file should be created by the developer and serves as a input to the container.
Instantiating the IoC Container:
IoC Container can be instantiated by creating instance of either object of type BeanFactory or ApplicationContext.
Using BeanFactory: This is the basic container for simple applications. There are several implementations of the BeanFactory, but most widely used implementation is the org.springframework.beans.factory.xml.XmlBeanFactory class which takes up object of type org.springframework.core.io.Resource. Some of the commonly used resource implementations are ByteArrayResource, ClassPathResource, FileSystemResource, InputStreamResource, PortletContextResource, ServletContextResource, UrlResource.
Using ApplicationContext: This is an advanced container and is preferred over BeanFactory. Most widely used implementation of the ApplicationContext are ClassPathXmlApplicationContext, FileSystemXmlApplicationContext.
Example#1: Instantiating a bean using Spring
Typical step-by-step example in creating a simple bean instance through Spring is as follows
• Create a simple java (bean) program.
package workspace.samples.springdemo.beancreation;
public class SimpleBean
{
public SimpleBean()
{
System.out.println("SimpleBean Instance created using Spring");
}
}
• Create a Spring configuration file.
• Create a simple client program where we instantiating the IoC Container and access the bean configured in the XML meta data file through the container
package workspace.samples.springdemo.beancreation;
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.ClassPathResource;
public class SimpleBeanClient
{
public SimpleBeanClient()
{
// To create the IoC Container using BeanFactory and retrieve bean instance from factory
BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("beanCreationContext.xml"));
SimpleBean simpleBeanObj1=(SimpleBean) beanFactory.getBean("simpleBean");
// To create the IoC Container using ApplicationContext and retrieve bean instance from context
ApplicationContext context=new ClassPathXmlApplicationContext("beanCreationContext.xml");
SimpleBean simpleBeanObj2=(SimpleBean) beanFactory.getBean("simpleBean");
}
public static void main(String args[])
{
SimpleBeanClient beanClient=new SimpleBeanClient();
}
}
Example#2: Spring DI: Setter Injection
Typical step-by-step example in injecting dependent objects through Spring DI is as follows
• Create two simple java program of which one is dependent on another.
EngineBean.java:
package workspace.samples.springdemo.beaninjection;
public class EngineBean
{
public EngineBean()
{
System.out.println("[EngineBean] [instance created]");
}
public void checkEngine()
{
System.out.println("[EngineBean] [checkEngine] ...");
}
}
CarBean.java:
package workspace.samples.springdemo.beaninjection;
public class CarBean
{
public CarBean()
{
System.out.println("[CarBean] [instance created]");
}
// This is required for the Spring Container to inject the bean EngineBean into this CarBean object
public EngineBean engineBean;
public void setEngineBean(EngineBean engineBean)
{
System.out.println("[CarBean] [EngineBean instance injected into CarBean]");
this.engineBean=engineBean;
}
public void startEngine()
{
engineBean.checkEngine();
System.out.println("[CarBean] [startEngine]...");
}
}
• Create a Spring configuration file
• Create a java client program which creates instances of the two java beans and then injects the dependent bean into the other bean through Spring DI.
package workspace.samples.springdemo.beaninjection;
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.ClassPathResource;
public class CarDriverClient
{
public CarDriverClient()
{
System.out.println("[CarDriverClient]");
// To create the IoC Container using BeanFactory and retrieve bean instance from factory
BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("carBeanInjectionContext.xml"));
CarBean carBeanObj1=(CarBean) beanFactory.getBean("carBean");
carBeanObj1.startEngine();
// To create the IoC Container using ApplicationContext and retrieve bean instance from context
ApplicationContext context=new ClassPathXmlApplicationContext("carBeanInjectionContext.xml");
CarBean carBeanObj2=(CarBean) beanFactory.getBean("carBean");
carBeanObj2.startEngine();
}
public static void main(String args[])
{
CarDriverClient carDriverClient=new CarDriverClient();
}
}