Dec
31

Domain Driven Design with Spring and Hibernate

I’ve been playing around with Domain Driven Design (DDD) and trying to write a small web application without implementing an anemic domain model.  I have found that it is more difficult than it ought to be and I want to share some of my experiences.

An anaemic domain is something that happens in an enterprise application when your domain objects don’t really contain any real logic.  Instead the logic nearly all resides in a secondary “service” component.  This is an example of badly encapsulated code and will lead to messy, difficult to maintain applications.

One of the reasons why an anaemic domain comes into existence is through the use of frameworks.  For a domain entity to be “rich” i.e. to contain real and significant logic, we almost certainly require dependencies to other objects and services.  These dependencies need to be added (or injected to maintain loose coupling) to that object when it is created for the first time.  These dependencies also need adding to the entity when it is retrieved from the database.  This is made difficult because we often rely upon ORM frameworks to do the persistence for us.  It seems that one one hand, the framework makes life much easier, but on the other, we may find that we are limited in some way by using them.

DDD strongly encourages us to create all domain objects from factories.  That means that when you create a new “User” bean, that it comes from a “UserFactory”.  When we save an object for later use, it goes to a “UserRepository”.  So far, so good…. This is all just part of the object’s life cycle.

What happens when we retrieve an existing object from one of those repositories?  What we are actually doing is creating a new object (if we are dealing with a database), which has the same properties of one which was saved previously.  The repository is in a sense reconstituting an old object, which is actually very similar to what the factory does.  If the repository is implemented using an ORM framework then we are just given a new instance of our domain object from the result of performing a query, but the dependencies that we were injecting when creating objects from factories are just not set.  Somehow, we need to get our dependencies set before the object is returned from the repository.

When using Hibernate and Spring, I have found several solutions to this problem, some less satisfactory than others.

Solution 1: Manual injection

After completing a query using Hibernate, we can “dependency inject” the result set by passing it to the factory before being passed out of the repository.

This is not a good solution.  It requires post processing of all query results after every query.  If at any point any developer forgets to perform this post processing step, NullPointerExceptions will be thrown left, right and centre.

Solution 2: Static dependencies

This solution seems to be more of a work around than a real solution.  But it is possible to have all dependencies as static variables instead of instance variables.  This solution has been discussed here, but the result is not very flexible.  It may be the case that for most classes, all instances can share the same dependency, but this is not very object oriented.  What happens in the future when we want to wire one entity to a different implementation of a service?

Solution 3: AOP Injection

The Spring framework has very good AOP (Aspect Oriented Programming) integration.  We can use AspectJ to intercept the call to the entity constructor.

How it works is as follows:

  1. Repository performs a Hibernate query (either directly or via a DAO).
  2. The query result set is calculated by your database and returned to Hibernate.
  3. Hibernate instantiates your bean (or beans depending on the query) and fills it with the data from the result set row(s).
  4. (But wait!) AspectJ has intercepted the call to the constructor of your bean and with the help of Spring sets all the required dependencies.
  5. The results that comes out of the Hibernate query have all the dependencies already injected (as if by magic).

I will now explain how to configure AOP injection in Spring:

Step 1:

Add the following to your application context to inform Spring to activate the AOP injection.

<context:spring-configured/>

Step 2:

Add the @Configurable annotation to your entity (I am assuming that you are using annotations to do your persistence mappings.)

@Entity
@Configurable("user")
@Table(name="users")
public class User implements IUser {
...

The value of the @Configurable annotation is the name of a Spring bean defined in your application context.

Step 3:

Define your bean in your application context, wiring all external dependencies that you want to inject just as you would a normal Spring bean.

<bean id="user" class="com.mycompany.domain.impl.User">
    <property name="myExternalService" ref="myExternalService"/>
</bean>

Step 4:

Now we have to tell Spring/AspectJ which domain objects are going to be “woven”.  Create a new directory “META-INF” in a directory which is included on the classpath.  Add inside this directory a new file called “aop.xml”.  Add the following to that file:

<aspectj>
    <weaver>
        <include within="com.mycompany.domain..*"/>
    </weaver>
    <aspects>
        <aspect name="org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect"/>
    </aspects>
</aspectj>

This adds the @Configurable support to those beans included in any sub package of the “com.mycompany.domain” package.

Step 5:

Finally, you must tell the JVM to use the AspectJ “Java Agent”.  A Java agent is able to manipulate the raw byte code in the JVM.  This is needed for AspectJ to intercept method calls.

This can be enabled when starting the JVM using the following argument:

-javaagent:/path/to/jarfiles/aspectjweaver.jar

Note: If you are using Eclipse and are deploying to a web server environment, please do the following: Right click on the web project to deploy, Select “Run As” and then “Run Configurations”.  In the following dialog, go to “Arguments” and add the java agent argument to the end of the “VM arguments” section.  Now this will be used whenever the web server is started.

Summary:

Well, that will do the trick, but to me, I get annoyed every time I delete my server configuration in Eclipse and I have to re-enter the java agent argument.  The argument may also be required when running unit tests if you are testing using Spring wired beans.

I want my factories to bear responsibility for dependency injection because it seems elegant and more in line with the principles of DDD.  Using AspectJ a programmer is no longer forced to use the factories and could (if sloppy) just call the constructor from within the domain.  The factory doesn’t need to do any dependency injection at all and feels redundant.

These problems are purely logistical (and fairly trivial), but there are deeper problems:

One concern is that @Configurable and @Transactional do not work together.  I cannot declare method in my domain to be transactional while having that bean also being @Configurable.  This may or may not be a problem for you depending on whether or not you are implementing transactions purely in your application layer or not.

We also lose the potential to dependency inject different objects depending on the situation.  A factory allows such versatility, whereas using @Configurable we lose this possibility.

Solution 4: Hibernate Interceptor

For some, solution 4 may seem like a step backwards, but it may be a more suitable solution for some situations.  Why can’t I just tell Hibernate to inject my dependencies when it instantiates a new bean?  Well, you can and quite easily.  You can even enjoy the benefits of having Spring find and wire the beans for you.

Step 1: Create an interceptor

First thing to do is to write a Hibernate interceptor and make it ApplicationContextAware.  Interceptors are used by Hibernate users to implement advanced functionality such as auditing.  User defined logic can be added to various “extension points” provided by the Hibernate framework.

Extend the EmptyInterceptor so that you don’t need to implement all of the methods.   ApplicationContextAware will cause the interceptor to get a reference to the application context.

public class ObjectFactoryHibernateInterceptor extends EmptyInterceptor
        implements ApplicationContextAware {
    private Map<String, String> factories = new HashMap<String, String>();
    private ApplicationContext applicationContext;

    ....

    public void setFactories(final Map<String, String> factories) {
        this.factories = factories;
    }

    @Override
    public void setApplicationContext(final ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext=applicationContext;
    }
}

We will now override the “onLoad” method to add additional logic to when Hibernate has loaded a new object.

@Override
public boolean onLoad(final Object entity, final Serializable id, final Object[] state,
        final String[] propertyNames, final Type[] types) {

    String factoryName = this.factories.get(entity.getClass().getCanonicalName());
    if (factoryName!=null) {
        IObjectFactory factory = (IObjectFactory)this.applicationContext
            .getBean(factoryName);
        if (factory!=null) {
            factory.injectDependencies(entity);
        }
    }
    return super.onLoad(entity, id, state, propertyNames, types);
}

We must now make sure that all of our factories implement the IObjectFactory interface and implement the “injectDependencies” method.  The factory itself can first check to ensure that the class belongs to the aggregate (for this factory) and do the dependency injection as required:

public class UserFactory implements IObjectFactory {

    ....

    @Override
    public void injectDependencies(Object entity) {
	if (entity instanceof User) {
		injectUserDependencies((User) entity);
	} else {
		throw new IllegalArgumentException("Unsupported type: "
                    + entity.getClass());
        }
    }

    ....
}

The factory (which is a normal Spring bean) injects the dependencies into the class both when it creates a new object or when one is being reconstituted.

Step 2:  Wiring the interceptor

Now we must configure the interceptor and make sure that it is used globally by Hibernate.  First we must create a bean definition for our interceptor:

<bean id="objectFactoryHibernateInterceptor" scope="singleton"
        class="com.mycompany.domain.impl.ObjectFactoryHibernateInterceptor" >
    <property name="factories">
        <map>
            <entry key="com.mycompany.domain.impl.User" value="userFactory"/>
        </map>
    </property>
</bean>

Notice, that we are mapping the class name to the name or the factory and not to the bean reference.  This is very important as otherwise we will be wiring the factories directly to the interceptor.  This will cause cyclic dependencies if we ever want to inject a repository into a domain bean (try it and see for yourself).

The final step is to connect this interceptor to the session factory so that Hibernate uses it globally.  Add the “objectFactoryHibernateInterceptor” to your session factory as follows:

<bean id="sessionFactory" scope="singleton"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="entityInterceptor" ref="objectFactoryHibernateInterceptor"/>
    ...
</bean>

Summary:

Lets take a look at what is happening.  Hibernate will execute a query and get the result set.  It will instantiate the beans as before, but the interceptor will add an additional step once the objects have been loaded by Hibernate.

The interceptor will check to see if it has a reference to a factory for the entity and if so, get a reference to that factory from the application context and then use that factory to inject the needed dependencies.

It would perhaps be even nicer if we could override the “instantiate” method instead and get Hibernate to use our factories when instantiating beans.  I’d be interested to hear if anybody tries this.

Finally

I hope that you have enjoyed my post.  I am enjoying learning about DDD and the Spring framework (and Hibernate).  Please consider reading Eric Evans’ excellent book “Domain Driven Design”.  I would consider it essential reading for anybody involved in enterprise application development.

Most information on DDD seems fairly theoretical and actually trying to implement a real application using these techniques is quite challenging.

If anybody else has any (better) solutions for dependency injection in the domain layer, I would be very interested to hear about it.  Also, regarding performance of AOP injection, if anybody has any experience in this area please get in contact.

Tags: , , , , , , ,

6 Responses to “Domain Driven Design with Spring and Hibernate”

  1. Allard says:

    Hi James, nice article, as you know I am also investigating the DDD with Spring area, and have to agree with you that it is not as easy as I would like it to be. However, your solution #3 is, as far as I know, more complicated than is absolutely necessary to use AspectJ with Spring.

    Furthermore, when using the factory and hibernate interceptor you have described, you miss one event where injection is required: deserialization. Especially when placing (rich) domain objects on the session or in a cache, you do not want these dependencies to be serialized with the object. When the object is deserialized, you want those dependencies to be re-injected. The spring aspects will do that for you.

    And lastly, @Configurable and @Transaction can work together, as long as you use AspectJ to advise the @Transactional classes, and not a Proxy, which is default Spring behavior.

    That brings me to the major problem of DDD and Spring: default don’t work.

    Anyway, thanks for sharing your DDD+Spring views!

  2. jim says:

    Hi Allard,
    Thanks for the comment, it was very nice to get some feedback.

    Yes, you are completely right about the serialization problem. This is probably less of an issue for non web based applications, but it is certainly a serious consideration for my own web based application.
    Perhaps I was a little premature in trying for a different DI solution when I encountered the @Configurable/@Transactional clash.

    I’m sure that a work around for the serialization problem could be achieved for the Hibernate interceptor solution. It seems now somewhat redundant however if we can in fact use @Transactional and @Configurable together.

    Thanks again for the comment.

  3. Arthur Ronald F D Garcia says:

    Hi James and Allard,

    I have heard a lot about domain-driven design. It suggest we use domain objects with states and behaviors, which interacts with other ones, as we, in fact, learned from our first lessons about OOP. That’s true, don’t ? it happens our first lessons about OOP did not include data access. After we have learned about data access, we have to include another feature in our world of programming: Repository’s or DAO’s in non domain-driven design.

    Now, would be a repository UserRepository a user’s state, as suggests the following:

    public class User {

    private UserRepository userRepository;
    // getter and setter

    }

    Simply because some user’s behaviors needs them. I have seen another approach where repository are arguments instead as following:

    public class User {

    public void active(UserRepository userRepository) { … }

    }

    when, in fact, from our first lessons about OOP, would be

    public class User {

    public void active() { … }

    }

    You see that because a feature - data access - WE HAVE TO ADAPT our OOP model to them.

    In my opinion, AOP should be used to adapt our, in fact, OOP model to data access.

    Some examples:

    Save a customer:

    Trigger a AOP that saves a User when a required constructor would be called

    int age = 10;

    User user = new User(”OOP”, age); // Trigger AOP to save our user

    user.active(); // Trigger AOP to update our user

    Now, you can see that, in fact, our original OOP was preserved by using AOP.

    AOP could use Repository to add, remove, find etc

    Regards
    Arthur Ronald F D Garcia

  4. smallufo says:

    Hi , I tried Solution 3(AOP Injection ) , but cannot work.

    I define almost identical architecture with yours. I notice that the serviceImpl is injected correctly BEFORE hibernate select. But after hibernate select (and returned to DAO) , the serviceImpl is null again.

    I observe this situation by System.out.println(serviceImpl) in setServiceImpl(IService serviceImpl), and indeed , a non-null serviceImpl is injected. But in getServiceImpl() it is null again !

    I tried to annotate @Transient serviceImpl , or transient serviceImpl , but the results are the same .

    Do you know why ?

    Environment : Hibernate-3.5.5 , Spring 3.0.4 , aspectjweaver-1.6.8 , hibernate-jpa-2.0-api , javaee-6.0

  5. jim says:

    This sounds quite odd. If the setter is correctly getting called with the correct parameter then the mechanism would appear to work correctly.

    I would use a debugger to assert the following:

    1. Is the setter actually setting the field in the object (maybe the parameter is not changing the state of the object).

    2. Check that the getter returns the correct value immediately after the object state is updated.

    2. If the getter is only returning null at a later point in time you should check to ensure that this object really is the same instance (check the id in the debugger).

    3. Finally I would place a break point on the field in the object. This should cause the program to be suspended when ever the field is accessed or modified. This should help you see at what point the field is set to null. I’m assuming an Eclipse environment.

    Sorry if any of these seem obvious. Its always best to check these things first though in my experience :-)
    Best of luck!

  6. Yep we know that DDD Domain Driven Design can be applied to SPRING 3 and HIBERNATE 3.5.1 project. Very interesting concept. You are buidling CRM SCM ERP system and financial integration system. Work on your domain designs and modules and use Domain Specific Langauges like XTEXT in ECLIPSE 2009-2010 Suites. Things work like a charm.
    Maneesh Innani
    Enterprise Architect
    Dec 22 2010