James Law’s Joint

Injecting Spring Beans into Domain Model

June 18, 2008 · 2 Comments

I’ve had this challenge on my tasklist as a developer for some time now. If you are inclined to do “Domain model” programing and avoid the “Anemic Domain” model and you use Spring and HIbernate than hopefully this may help.

Problem:

Spring is great at doing DI with all your service and DAO classes, but in its standard usage which uses proxies provided by the JDK or by CGLib, it has no control over creation of Domain Model objects. In a typical J2ee application Domain Objects are, of course, loaded via Hibernate, IBatis, or perhaps even JDBC.

I have found that to a large degree, I can eliminate a huge amount of code in “service” classes by depending largely Hibernate’s ability to lazily load parts of the object graph (assuming good DB design, and well mapped entity relations), as well as its “tranparent persistence” features. In other words, when I need to make changes, just change the domain objects by loading a single domain object, and change related objects via navigation. For example:

Order.addItem(Item item)
{
//bus logic here
items.add(item);
}

This works well, assuming everything comes out of a database, but here are some cases where something else is needed:

  • You’d like transient summary total information in domain objects (Perhaps a “Account” object with a sum total generated manually via a DAO and JDBC
  • There’s a vendor API that needs to be linked in as part of your domain model is being outsourced or SASSed
  • Other infrastructure services (Email, notification come to mind)
  • Maybe you just like RAILS approach of having finders on the domain object

While I am not inclined to use this for 3,4, I do think the other cases result in some kludgy workarounds.

HOW-TO

First, you’ll need some background from the spring folks. Read this section:

http://static.springframework.org/spring/docs/2.0.x/reference/aop.html#aop-atconfigurable

After reading this you should realize there are 2 options. Use the load time weaver, or an ant task. I have tried the loadtimeweaver (LTW) in the past, and while it works, I have ruled it out for a few reasons mainly:

1. For automated “integration” type of tests, adding javaagent stuff everytime I need to run a test inside eclipse seems like a serious pain

2. Coordination with the folks that run with the application servers

3. And it seemed slow when I tried it many months ago (added 20 or so seconds to tomcat load time for our project)

So, IF youre still with me and want to use the ant task to achieve this goal, here’s my list:

Set-up your bean container with the magic:

Add the following to your spring xml files:

<!--  allows domain objects to get configured via @Configurable -->
<context:spring-configured/>

My understanding is that this causes a reference to the spring container to be made available to the ASPECTS provided by spring.

Add spring-aspects-2.5.x to your project

If you haven’t already, the buildpath must include this jar, as it contains the Aspect that is needed. In particular, the Aspect is an “AnnotationBeanConfigurerAspect”. This aspect will get applied to the Domain Objects.

Grab aspectJ anttools

Download these, then run the jar to extract the package (I used v1.53)

From the installed aspectJ Tools, take note of the jar inside it: aspectjtools.jar. This has the ant task. Put it whever you put your ant tasks.

Make sure aspectjrt-xx is in your buildpath

I am fairly certain this is a required jar for spring so its probably already on the project classpath. If you don’t, then add it

Make an ant build for aspectj

Now the hard part. It took some time for me to figure this out, as IMO it has way too many options and should have more tasks with less options, but thats probably my lack of aspectj knowledge …

Anyway, here’s my ant build (stripped down some)

<project name="aspectBuild" >
<!-- need to tell ant where the aspectj tooling jar is -->
  <taskdef
      resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
    <classpath>
      <pathelement location="aspectjtools.jar"/>
    </classpath>
  </taskdef>
<!-- the path to the aspects already created by the Spring dudes -->
<path id="aspect.path">
		<pathelement location ="spring-aspects-2.5.jar" />
</path>
<!-- the projects buildpath -->
<path id="classpath.path">
<fileset dir="build/lib">
<include name="**/*.jar" />
</fileset>
</path>
<!-- here, I'm using the output dir as both the input (where are the .class files)
but also where to put the instrumeneted files as well -->
<path id="output.path" >
	<pathelement location="../classes"/>
</path>

<target name="compile" >
    <iajc verbose="true"
    inpathref="output.path"
    	aspectpathref="aspect.path"
    	classpathRef ="classpath.path"
    	destdir="../classes"
    />
  </target>
</project>

For further info on the ant task, try here.

After creation of the ant task, if you’re using eclipse, you can automate the running of the ant task

with every complile via project properties- “builders”. Very handy

If for some reason you don’t need to automate builds, and you use eclipse, the ant stuff can be eliminated by using aspectj eclipse tooling. Pretty easy so I’ll just summarize quickly:

  • “aspectJ” enable the eclipse project after installing ajdt tooling
  • under project-aspectjbuild, go to “aspectpath” and give it the spring-aspects.xx jar
  • Done!

TODO:

Find out how to do incremental instrumentation

Next week:

Instrumentation tasks for HIbernate and Terracotta

Categories: Uncategorized
Tagged: , , ,

2 responses so far ↓

Leave a Comment