Spring can inject Servlets too!

In this article, I will show you that Spring dependency injection mechanism is not restricted solely to Spring-managed beans, that is Spring can inject its beans in objects created by the new keywords, servlets instantiated in the servlet container, and pretty anything you like. Spring classical mode is to be an object factory. That is, Spring creates anything in your application, using the provided constructor. Yet, some of the objects you use are outer Spring’s perimeter. Two simple examples:

  • servlets are instantiated by the servlet container. As such, they cannot be injected out-of-the-box
  • some business objects are not parameterized in Spring but rather created by your own code with the new keyword

Both these examples show you can’t delegate to Spring every object instantiation.

There was a time when I foolishly thought Spring was a closed container. Either your beans were managed by Spring, or they didn’t: if they were, you could inject them with other Spring-managed beans. If they weren’t, tough luck! Well, this is dead wrong. Spring can inject its beans into pretty much anything provided you’re okay to use AOP.

In order to do this, there are only 2 steps to take:

  • Use AOP
  • Configure object creation interception

Use AOP

It is done in your Spring configuration file.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd"
>

<This does the magic />
<context:spring-configured />

<-- These are for classical annotation configuration -->
<context:annotation-config />
<context:component-scan base-package="com.vaani.spring.outcontainer" />

</beans>

You need also configure which aspect engine to use to weave the compiled bytecode. In this case, it is AspectJ, which is the AOP component used by Spring. Since i’m using Maven as my build tool of choice, this is easily done in my POM. Ant users will have to do it in their build.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd"
>
...
<properties>
<spring-version>2.5.6.SEC01</spring-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<complianceLevel>1.5</complianceLevel>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

 

Configure which object creation to intercept

This is done with the @org.springframework.beans.factory.annotation.Configurable annotation on your injectable object.

@Configurable
public class DomainObject {

/** The object to be injected by Spring. */
private Injectable injectable;

public Injectable getInjectable() {

return injectable;
}

@Autowired
public void setInjectable(Injectable injectable) {

this.injectable = injectable;
}
}

Now with only these few lines of configuration (no code!), I’m able to inject Spring-managed beans into my domain object. I leave to you to implement the same with regular servlets (which are much harder to display as unit test).

You can find the Maven project used for this article here. The unit test packaged shows the process described above.

To go further:

Spring – How to pass a Date into bean property (CustomDateEditor )

Simple method may not work
Generally, Spring developer are not allow to pass a date format parameter into bean property via DI.

For example,

public class CustomerService
{
Date date;

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

}

Bean configuration file

<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-2.5.xsd">

<bean id="customerService" class="com.services.CustomerService">
<property name="date" value="2010-01-31" />
</bean>

</beans>

Run it

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mkyong.customer.services.CustomerService;

public class App
{
public static void main( String[] args )
{
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});

CustomerService cust = (CustomerService)context.getBean("customerService");
System.out.println(cust.getDate());
}
}

Error message prompt.

Caused by: org.springframework.beans.TypeMismatchException:
Failed to convert property value of type [java.lang.String] to
required type [java.util.Date] for property ‘date’;

nested exception is java.lang.IllegalArgumentException:
Cannot convert value of type [java.lang.String] to
required type [java.util.Date] for property ‘date’:
no matching editors or conversion strategy found

Solution

There are two solutions available.

1. Factory bean

Declare a dateFormat bean, and reference it as a factory bean from the date property. The factory method will call the SimpleDateFormat.parse() menthod to convert the String into Date object automatically.

<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-2.5.xsd">

<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>

<bean id="customerService" class="com.mkyong.customer.services.CustomerService">
<property name="date">
<bean factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2010-01-31" />
</bean>
</property>
</bean>

</beans>

2. Property editors (CustomEditorConfigurer + CustomDateEditor)

Declare a CustomDateEditor class to convert the String into java.util.Date properties.

<bean id="dateEditor"
class="org.springframework.beans.propertyeditors.CustomDateEditor">

<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
</constructor-arg>
<constructor-arg value="true" />

</bean>

Register the CustomDateEditor in CustomEditorConfigurer, so that the Spring will convert the properties whose type is java.util.Date.

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<ref local="dateEditor" />
</entry>
</map>
</property>
</bean>

Bean configuration file.

<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-2.5.xsd">

<bean id="dateEditor"
class="org.springframework.beans.propertyeditors.CustomDateEditor">

<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
</constructor-arg>
<constructor-arg value="true" />

</bean>

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<ref local="dateEditor" />
</entry>
</map>
</property>
</bean>

<bean id="customerService" class="com.mkyong.customer.services.CustomerService">
<property name="date" value="2010-02-31" />
</bean>

</beans>

Spring 3.0 with EL

Spring 3.0 introduces support for expression language, which is similar to Unified EL support in jsp. The intention was to further provide different ways of setting bean properties.
The advantage of EL is that it can support different kinds of expressions like Boolean, literal ,regular , method invocation, etc.

It is also called spEL or spring EL.
Now again there are 2 methods of using EL notation – xml and annotations.

Example :

public class ErrorHandler {

private String defaultLocale;

public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}

public void handleError() {
//some error handling here which is locale specific
System.out.println(defaultLocale);
}
}

Using EL in xml  config :

<bean id="errorHandler" class="xxxx.ErrorHandler">
<property name="defaultLocate" value="#{systemProperties['user.region']}" />
</bean>

Annotation style config:

import org.springframework.beans.factory.annotation.Value;

public class ErrorHandler {

@Value("#{ systemProperties['user.region'] }")
private String defaultLocale;

public void handleError() {
//some error handling here which is locale specific
System.out.println(defaultLocale);
}
}

Prior to Spring 3.0 , the only way to provide configuration metadata was XML.

Spring : Different ways of DI

There can be multiple ways of doing dependency injections, like :

Spring : DisposableBean Interface and InitializingBean

The InitializingBean and DisposableBean are two marker interfaces which call the  afterPropertiesSet() for the begining and destroy() for the last action of initialization and    destruction to be performed.

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class StudentService implements InitializingBean, DisposableBean {
String message;

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public void afterPropertiesSet() throws Exception {
System.out.println(" After properties has been set : " + message);
}

public void destroy() throws Exception {
System.out.println("Cleaned everything!!");
}

}

In context.xml bean is created in usual style.

Spring List Property Example

The Spring Framework has bean support for the Collections. It provide list, set, map and props elements. Here in this tutorial you will see about the list elements which is used to set values inside the list.

Example

Consider this list bean :

import java.util.List;

public class CollegeBean {
private List<Object> lists;

public List<Object> getLists() {
return lists;
}

public void setLists(List<Object> lists) {
this.lists = lists;
}

@Override
public String toString() {
return "College [lists=" + lists + "]";
}
}

Simplebean

public class StudentBean {
private String name;
private String address;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

@Override
public String toString() {
return "Student [address=" + address + ", name=" + name + "]";
}
}

context.xml

<!-- Spring List Property Example  -->

<bean id="studentBean" class="com.xxx.StudentBean">
<property name="name" value="satya" />
<property name="address" value="Delhi" />
</bean>

<bean id="collegeBean" class="com.xxx.CollegeBean">

<property name="lists">
<list>
<value>1</value>
<ref bean="studentBean" />
<bean class="com.xxx.StudentBean">
<property name="name" value="ankit" />
<property name="address" value="delhi" />
</bean>
</list>
</property>
</bean>

<!-- End -->

Spring : Lifecycle interface

Lifecycle interface is basically meant for managing startup and shutdown callbacks. For eg., on startup we would like to load data into the cache and on shutdown just clear the cache or start the process at startup and end it when exiting.

So SmartLifecycle is extension of Lifecycle Interface.

Example :

import org.springframework.context.SmartLifecycle;

public class LifecycleImpl implements SmartLifecycle {

public LifecycleImpl() {
System.out.println("LifecycleImpl class instantiated..");
}

@Override
public boolean isAutoStartup() {
System.out.println("isAutoStartup method our LifecyleImpl class called..");
return true;
}

@Override
public void stop(Runnable r) {
System.out.println("stop(Runnable) method of our LifecycleImpl class called..");
r.run();
}

@Override
public boolean isRunning() {
System.out.println("isRunning method of our LifecycleImpl class called..");
return true;
}

@Override
public void start() {
System.out.println("start method of our LifecycleImpl class called..");
}

@Override
public void stop() {
System.out.println("stop method of our LifecycleImpl class called..");
}

@Override
public int getPhase() {
System.out.println("getPhase method of our LifecycleImpl class called..");
return 1;
}
}

Create the bean in simple way in context.xml.

Spring Map Example

In this example you will see how bean is prepared for injecting Map collection type key and its values.

import java.util.Iterator;
import java.util.Map;

public class MapBean {
private Map<String, Integer> student;
public void setDetails(Map<String, Integer> student) {
this.student = student;
}
public void showDetails() {
Iterator it = student.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
System.out.println(pairs.getKey() + " = " + pairs.getValue());
}
}
}

In the config file :

<bean id="mapbean" class="com.xxxx.MapBean">
<property name="details">
<map>
<entry key="Satya" value="101"/>
<entry key="Rohit" value="102"/>
<entry key="Aniket" value="103"/>
</map>
</property>
</bean>

BeanFactoryPostProcessor interface

The semantics of this interface is similar to BeanPostProcessor but with one major difference : BeanFactoryPostProcessor operate on bean configuration metadata; So spring IoC container allow BeanFactoryPostProcessor to read the configuration metadata and potentially change it before the container instantiates any bean other than BeanFactoryPostProcessor .

But if you want to change the actual bean instances( the objects that are created from the configuration metadata), then use BeanPostProcessor.

Example …

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class BeanFactoryPostProcessorImpl implements BeanFactoryPostProcessor {

public BeanFactoryPostProcessorImpl() {
System.out.println("BeanFactoryPostProcessorImpl class instantiated..");
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory)
throws BeansException {
System.out.println("postProcessBeanFactory method of our BeanFactoryPostProcessorImpl class called..");

//dynamically registering a new bean in the context. you can try this later on.
//similar to @Configuration and @Bean we saw in previous section.
//factory.registerSingleton("myBean", new SampleBean());
}
}

Again one of the commonly used BeanFactoryPostProcessor is PropertyPlaceHolderConfigurer class. We already have seen the usage of this class before. This replaces the config of any bean containing ${}  with the actual property value so by the time the bean is instantiated, the correct values are already in the container.

@Required annotation

BeanPostProcessor is used by the framework heavily. One of the best example is RequiredAnnotationBeanPostProcessor class. In spring we require @Required annotation to make it a mandatory dependency, that thas to be injected.

Just by using annotation in the code will not work, since someone has to check whether the requirement has been met or not and reposrt an error it not.

Example

//The service
public interface BankService {

public BillPaymentService getBillPaymentService();
public CustomerService getCustomerService();
}

//The impl class
public class BankServiceImpl implements BankService {

private CustomerService customerService;
private BillPaymentService billPaymentService;

@Required
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}

@Required
public void setBillPaymentService(BillPaymentService billPaymentService) {
this.billPaymentService = billPaymentService;
}

public BillPaymentService getBillPaymentService() {
return billPaymentService;
}

public CustomerService getCustomerService() {
return customerService;
}
}

Now here we have mentioned what is required, but we need RequiredAnnotationBeanPostProcessor to check whether these required dependency are injected or not.

The configuration

<!--  According the code, we need to set both the dependencies.
Comment out one or both the property tag and see the error -->
<bean id="bankService" class="com.xxxx.BankServiceImpl">
<property name="billPaymentService" ref="billPaymentService" />
<property name="customerService" ref="customerService" />
</bean>

<!-- Just by using @Required will not work. Someone has to parse it
and that's the role of this class -->
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />