Regular dependency injection works well when you are injecting dependencies into static components such as services and repositories/DAOs, which are created by Spring. But what about objects that are not created by Spring? Quite often these objects also have dependencies. For example, in the POJOs in Action domain model, the PendingOrder domain entity uses the RestaurantRepository. It calls RestaurantRepository.isRestaurantAvailable(deliveryInformation) to verify that the the supplied delivery information is served by at least one restaurant. In this example, I solved the problem by having the PlaceOrderService, which is created by Spring and can use dependency injection, pass the RestaurantRepository as an argument to the PendingOrder.updateDeliveryInfo() method:
public class PlaceOrderServiceImpl
public PlaceOrderServiceResult updateDeliveryInfo(String pendingOrderId,
Address deliveryAddress, Date deliveryTime) {
PendingOrder pendingOrder = findOrCreatePendingOrder(pendingOrderId);
int result = pendingOrder.updateDeliveryInfo(restaurantRepository,
deliveryAddress, deliveryTime, false);
...
}
...
}
Unfortunately, passing dependencies as parameters is not always this simple because the method that uses the dependency can be many methods calls away from the service. Either we need to pass the dependencies as extra parameters, which clutters the code, or the methods must access them via statics, which have their own drawbacks. Neither solution is ideal. This is where Spring 2 comes to the rescue.
One of the more interesting features of Spring 2 is its support for injecting dependencies into entities. Spring 2 uses AspectJ to intercept calls to an entity's constructor and initializes it with setter injection. To use this feature with PendingOrder we need to do three things. First, we replace the method parameter with a restaurantRepository property and add the @Configurable annotation to the class:
@Configurable("pendingOrder")
public class PendingOrder {
private RestaurantRepository restaurantRepository;
public void setRestaurantRepository(RestaurantRepository restaurantRepository) {
this.restaurantRepository = restaurantRepository;
}
public int updateDeliveryInfo(
Address deliveryAddress,
Date deliveryTime,
boolean force) { ... }
...
}
The @Configurable attribute tells Spring to inject dependencies into instances of the PendingOrder class using the bean definition named "pendingOrder".
Second, we need the following XML in the Spring application context:
<aop:spring-configured />
<bean id="pendingOrder" lazy-init="true">
<property name="restaurantRepository" ref="RestaurantRepositoryImpl" />
</bean>
The <aop:spring-configured/> element enables dependency injection into entities. The <bean id="pendingOrder"> definition specifies the values to inject into the PendingOrder using setter injection. The id of the <bean> matches the name specified in the @Configured element.
Third, we need to use AspectJ to weave into the PendingOrder class's bytecodes the Spring-supplied aspect that is triggered by the @Configurable annotation . There are a couple of ways to do this. One option is to use the AspectJ compiler to compile the domain model with the Spring aspect library. The second option, which is the one I chose, is to use AspectJ's load-time weaving feature, which weaves the aspects into the application's classes when they are loaded. Load-time weaving is enabled using the "-javaagent:aspectjweaver-1.5.0.jar" command line option and including this META-INF/aop.xml file in the class path
<aspectj>
<weaver options="-verbose">
<include within="net.chrisrichardson.foodToGo.domain.*" />
<exclude within="*..*CGLIB*" />
</weaver>
</aspectj>
The <include> and <exclude> elements restrict load-time weaving to only classes in the net.chrisrichardson.foodToGo.domain package that are not Hibernate's cglib generated proxies. This speeds up class loading.
After making these changes, Spring injects the RestaurantRepository into any instances of PendingOrder that are created by either the application or by Hibernate. The PlaceOrderService no longer needs to pass the RestaurantRepository to the PendingOrder as a method parameter.
Injecting dependencies into entities eliminates the clutter caused by passing them around as method parameters. However, there are some issues to consider. It requires using AspectJ byte-code weaving either via the the AspectJ compiler, which can impact your build mechanism, or via load-time weaving, which can slow down program startup. Also, you probably want to continue unit testing the domain model without Spring, which requires changing the code to manually inject dependencies. For example, code that instantiates and invokes methods on the PendingOrder must inject the RestaurantRepository. This will be the topic of a future post.
Good blog Chris.
We've been doing something similar on my current project (http://www.danhay
wood.com/blog/default/?permalink=A-word-from-our-sponsor.html), although
since we're not using AspectJ the way we do it is to create our domain
objects through a container, and then it inspects them to see what they are
aware of. So, your PendingOrder would implement RestaurantRepositoryAware,
which in turn would define a method setRestuarantRepository(). In this way
our container which is instantiated by Spring, propogates its dependencies
into the domain entities that it creates.
Hi, Chris! I do not want to bother you too much but I was curious about
what you think on having pojo's in the presentation layer of an
application. As you know, JSF enables you to work with simple POJO as
managed beans. But as Tapestry proves it, it is possible to also have clean
xhtml templates for the pages. But then, Tapestry impose an unnatural
programming paradigm as it requires pages to be abstract and to extend a
framework class. I think it would be great if it were possible to have both
java code and xhtml templates cleanly separated (tapestry or wicket style
of separation) from each other and to also have a free object hierarchy on
the java side.
Hi Chris, I have a question about the use of dependency injection. There
certainly seems to be a lot of declarative 'coding' required to set up
injection for any POJO that uses a repository and the POJO objects
themselves need to have a property added to store the dependency (eg.,
RestaurantRepository in the PendingOrder POJO) whereas a ThreadLocal
solution uses just a simple static call to retrieve an repository. I have
seen a few examples using ThreadLocal to tackle this issue and it seems to
work fine. I can understand the code "smell" associated with singletons but
a ThreadLocal solution avoids the multithreaded problems and (I'm guessing
here!) with a smart approach you could apply the Template pattern to the
ThreadLocal's reference allowing the solution to be more testable.
Thanks so much! Until I read your entry, I was unaware that dependency
injection of domain objects instantiated outside the Spring container would
be officially supported in the upcoming release of Spring 2.