Domain Driven Design with Spring and AspectJ
Let’s see what he has to say:
(NOTE: The original post has been slightly edited to improve readability)
Before I start discussing our main topic, I would like you to think for a while about the best Java EE application design you can imagine. It does not matter whether you use Spring or EJB3, as they are very similar, probably you would suggest an approach similar to the following. Starting from the back-end you have:
- domain objects, which are simple POJOs mapped directly to database relations. POJOs are great because JavaBean-style properties are well understood be many frameworks.
- data access layer – typically stateless services, which wrap up database access code (JDBC, Hibernate, JPA, iBatis or whatever you want) hiding its complexity and providing some level of (leaky) abstraction. DAOs are great because they hide nasty and awkward JDBC logic (that is why some question the need for DAOs when using JPA), serving as a, more-or-less, translator between database and objects.
- business services layer – another set of stateless services, which operate on domain objects. Typical design introduces a graph of objects that take or return domain objects and perform some logic on them, again, typically accessing database via data access layer. Service layer is great because it focuses on business logic, delegating technical details to DAO layer.
- user interface – nowadays, typically via web browser. User interface is great because… just the fact it is.
Beautiful, isn’t it? Now open your eyes, it is time for a cold shower.
Both services and DAOs are stateless, because Spring and EJB3 favors such classes – so we learnt to live with it. On the other hand, POJOs are “logicless” – they only contain data, maintain their state without operating on it and introducing no logic. If we think about introducing “reservation” domain object to our application, we immediately think of Reservation POJOs mapped to RESERVATIONS database table, ReservationDao, ReservationService, ReservationController, etc.
Still don’t see the problem? How would you describe “object”? It is some virtual being having internal (encapsulation) state and some public operations, which have explicit access to that state. Most fundamental concept of object-based programming is to take data and procedures operating on that data together and close them tightly. Now take a look at your best design ever, do you really need objects? This is the dark secret of Spring, EJB3, Hibernate and other well established frameworks. The secret, which all of us subconsciously try to forget: we are not OOP programmers anymore!
POJOs are not objects, they are simply data structures, collections of data. Getters and setters are not true methods, actually, when was the last time you wrote them by hand? In fact, the need to autogenerate them (and refactor, add and remove when attributes change) sometimes happen to be very frustrating. Wouldn’t it be simpler just to use structures with public fields by default?
On the other hand, look at all those great stateless services. They do not have any state. Although they operate on domain objects, they are not part of them or not even aggregate them (low cohesion). All the data is passed explicitly through the method parameters. They aren’t objects as well – they are simply collection of procedures arbitrary gathered together on a common namespace, corresponding to class name. In contracts, methods in OOP are also procedures behind the scenes, but having implicit access to this reference, which points to the object instance. Whenever we call ReservationService or ReservationDao providing a Reservation POJO reference explicitly as one of the arguments, we actually reinvent OOP and code it manually.
Let’s face it, we are not OOP programmers, as everything we need are structures and procedures, invented fifty years ago. How many Java programmers are using inheritance and polymorphism in a day-to-day basis? When was the last time you wrote an object having private state without getters/setters with only few method having access to it? When was the last time you created an object with non-default constructor?
Luckily, what Spring has taken, it brings back with even more power. That power is called AspectJ.
In my last post I created a Reservation entity having three business methods: accept(), charge() and cancel(). It looks really good to have business methods concerning domain object placed directly in that object. Instead of calling reservationService.accept(reservation), we simply run reservation.accept(), which is much more intuitive and less noisy. Even better, what about writing:
Reservation res = new Reservation() //... res.persist()
instead of calling a DAO or using the EntityManager directly? I don’t know much about domain-driven design, but I found this fundamental refactoring to be the first gate you must walk through to enter the DDD world (and go back to OOP as well).
Reservations’ accept() method will eventually need to delegate some logic to external services, like accounting or sending e-mails. Naturally, this logic is not part of Reservation domain object and should be implemented elsewhere (high cohesion). The thing is how to inject other services to domain objects. When all services are managed by Spring, everything is simple. But when Hibernate creates domain objects itself or the object is created using new operator, Spring has no knowledge of this instance and cannot handle dependency injection. So how would Reservation POJO obtain Spring beans or EntityManager encapsulating necessary logic?
First, add the @Configurable annotation to your domain object:
@Configurable @Entity public class Reservation implements Serializable { //... }
This tells Spring that Reservation POJO should be managed by Spring. But, as mentioned above, Spring has no knowledge of Reservation instances being created, so it has no occasion to autowire and inject dependencies. This is where AspectJ comes in. All you need to do is to add:
<context:load-time-weaver/>
to your Spring XML descriptor. This extremely short XML snippet tells Spring that it should use AspectJ load-time weaving (LTW). Now, when you run you application:
java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an ‘addTransformer(ClassFileTransformer)’ method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring’s agent: -javaagent:spring-agent.jar
at org.springframework.context.weaving.DefaultContextLoadTimeWeaver.
setBeanClassLoader(DefaultContextLoadTimeWeaver.java:82)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.
initializeBean(AbstractAutowireCapableBeanFactory.java:1322)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.
doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
… 59 more
It will fail… Java is not magic, so before we proceed, a few words of explanation. Adding the XML snippet above does not solve anything. It simply tells Spring that we are using AspectJ LTW. But when application starts up, it does not find an AspectJ agent and tells us about it decently. What happens if we add -javaagent:spring-agent.jar to our JVM command line parameters as suggested? This Java agent is simply a plugin to JVM that overrides loading of every class. When Reservation class is loaded for the first time, agent discovers @Configurable annotation and applies some special AspectJ aspect to this class.
To be more precise: bytecode of Reservation class is being modified, overriding all constructors and deserialization routines. Thanks to this modification, whenever new Reservation class is being instantiated, apart from normal initialization, those additional routines added by the Spring-provided aspect perform dependency injection. So since now enhanced Reservation class is Spring-aware. It does not matter whether reservation has been created by Hibernate, Struts2 or using new operator. Hidden aspect code always takes care of calling Spring ApplicationContext and ask it to inject all dependencies to domain object. Let us take it for a test drive:
@Configurable @Entity public class Reservation implements Serializable { @PersistenceContext private transient EntityManager em; @Transactional public void persist() { em.persist(this); } //... }
This is not a mistake – I injected EntityManger from JPA specification directly to domain object. I also put @Transactional annotation over persist() method. This is not possible in ordinary Spring, but since we used @Configurable annotation and AspectJ LTW, code below is completely valid and works as expected, issuing SQL and committing transaction against the database:
Reservation res = new Reservation() //... res.persist()
Of course, you can also inject regular dependencies (other Spring beans) to your domain objects. You have choice of using autowiring (@Autowire or even better @Resource annotations) or setting properties manually. The latter approach gives you more control, but forces you to add setter for Spring bean in domain object and define another bean corresponding to domain object:
<bean class=" com.blogspot.nurkiewicz.reservations.Reservation "> <!-- ... --> </bean>
Please note that I haven’t provided a name/id for this bean. If I would, the same name should be passed to the @Configurable annotation.
Everything works like a charm, but how do we use this amazing feature in our real life work? First of all, we must setup your unit tests to use Java agent. In IntelliJ IDEA I simply added:
-javaagent:D:/my/maven/repository/org/springframework/spring-agent/2.5.6/spring-agent-2.5.6.jar
to VM parameters text field in JUnit run configuration. If you add this to default (“Edit defaults” button), this parameter will be applied to every new unit test you run. But configuring your IDE is not as much important as configuring your build tool (hopefully maven). First of all you must ensure that the Spring Java agent is downloaded and available. Thanks to Maven’s dependency resolution, this can be easily achieved by adding the following dependency:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-agent</artifactId> <version>2.5.6</version> <scope>test</scope> </dependency>
The JAR is not actually needed by the test code, but by adding this dependency we guarantee that it is downloaded before tests run. Then, a simple tweak in surefire plugin configuration:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <forkMode>always</forkMode> <argLine> -javaagent:${settings.localRepository}/org/springframework/spring-agent/2.5.6/spring-agent-2.5.6.jar </argLine> </configuration> </plugin>
Really simple – the location of spring-agent.jar can be safely constructed using maven repository path. Also forkMode must be set in order to reload classes (and cause LTW to happen) before each test is executed. I think configuring your app server and/or startup scripts does not need any further explanation.
That is all about Spring and AspectJ integration via load-time weaving. Few simple configuration steps and a whole new world of domain-driven design appears. Our domain model is no longer weak, entities are “smart” and business code is more intuitive. And last but not least – your code would be object-oriented, not procedural.
Of course, you might not like load-time weaving, as it interferes with JVM class loading. There is another approach, called compile-time weaving, which weaves aspects on compile time rather than class loading time. Both methods have pros and cons, I will try to compare both of them in the future.
Very interesting approach, indeed. That’s it guys, a compact guide on how to inject dependencies to your domain objects using Spring and AspectJ’s load time weaving by our our JCG partner Tomasz Nurkiewicz. If you liked this, don’t forget to share. Happy coding!
Related Articles:
Wow! Really good!!! I’ve been struggling with how to inject dependencies on entitys for ages… That was making impossible to use DDD on the real world. Thanks a lot!