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:
- Aspect-oriented programming
- Aspect Oriented Programming with Spring
- The AspectJ™ Programming Guide
- Using AspectJ to dependency inject domain objects with Spring
- org.springframework.beans.factory.annotation.Configurable API
No comments:
Post a Comment