The ProblemCurrently, many java applications use Spring framework together with Hibernate. One of the advantages of that is that we can implement our domain and service objects as POJOs. Most of us are already convinced of all the benefits that such a type of architecture can have. In architecture like that, domain objects are managed by Hibernate and service objects are managed by Spring. Also, another advantage of using Spring specifically is Dependency Injections (DI) of services and resources.
The problem is how to retrieve/find/locate services or resources in domain objects since they are managed by Hibernate and not created through the bean factory of Spring framework?
Note: we should differentiate between domain, infrastructure and application services (Domain Driven Design book -
http://domaindrivendesign.org/book). Using infrastructure or application services in domain objects is rather not appropriate. The problem I am most concerned with here is in the case when we need to invoke domain services inside of domain objects.
Can we avoid the problem?Probably! The only way to avoid this problem is not to deal with any services/resources in domain objects. We can do this if we coordinate all domain-service cooperation from a service layer. In this case, we don’t need to bother with dependency injections, service locators, etc. This makes a lot of sense when we invoke services in an asynchronous fashion and especially in SOA /EAI types of architectures.
However, there are some disadvantages:
- We deprive ourselves from some of the benefits and power of OOP/OOD.
- Sometimes, service behavior fits very nicely into the domain model when we have a rich domain model rather than an anemic one
http://www.martinfowler.com/bliki/AnemicDomainModel.html and
http://wrschneider.blogspot.com/2005/01/avoiding-anemic-domain-models-with.htmlWhy do we get to the problem?When I start a project I always try to have very well separated service layer from domain objects (usually enforced with different compilation modules for domain objects and service layer). However, in practice (at least until now) it always turns out that at some point I will need to use some kind of service or resource in my domain objects (the simplest example is Time Service. A Time Service is usually needed to give synchronized time when the application is deployed / clustered to more than one server. Also, if you need to play with the current time in your tests, this is a perfect solution. Usually when you deal with some kind of payment/billing systems, you will definitely need something like the above). There can be numerous examples of domain objects using some kind of service. Usually, most of the applications that have more complex domains use some kind of services or resources in domain objects.
Common solution to the problemIn the past when faced with this sort of situations we have usually used some form of Service Locator within domain objects in order to retrieve/locate services or resources.
However, these days we routinely use Dependency Injection with some form of Inversion of Control lightweight container (Spring for example) to wire up practically everything else in an app - and we would like to use a consistent approach if at all possible. Unfortunately, our domain objects are constructed by Hibernate and not Spring.
The most common solution (and the only one that I have seen in practice for now) is to use Spring framework DI to inject services into the service layer and to wire up practically everything else in your app beside domain objects. The domain objects, on the other side use Spring-based service locators to find further services/collaborators they need to do their job.
This could be workable approach since both the DI and service location mechanisms use the same underlying infrastructure (Spring bean factory), so they can share the same configuration files etc. Also, this common solution to the problem has been kind of described in the javadocs for Spring’s BeanFactoryBootstrap class with the statement “one singleton to rule them all”. In other words, allow singleton access to the bean factory or application context that holds all of the service layer objects.
However, as I stated above, I would like to use a consistent approach if at all possible for retrieving services. Not to mention all problems that comes with using Service Locator pattern. I guess using Service Locator with DI injections is a little better than the old style Service Locator but at the end, this is still a singleton. At least there is only ONE singleton in the entire app instead of one for each service object.
Example implementation of the common solution with Service Locator and DIBefore I continue further, let me show brief example of Service Locator using Spring DI. ServiceManager is an implementation of Service Locator pattern in this example. Its conceptual implementation comes from the statements “one singleton to rule them all” and “another level of indirection can solve any problem in OO design” (I don’t fully agree with this statements but it is hard to argue against them). The ServiceManager class has reference to all services that are needed by domain objects. All services are injected by Spring and ServiceManager is singleton instantiated by Spring creation factory on application startup. Something like this:
public class ServiceManager { private static ServiceManager ourInstance; private IReferenceDataService referenceDataService; private ITimeService timeService; ………… //other service declarations public ServiceManager() { ourInstance = this; } public static IReferenceDataService getReferenceDataService() { return getInstance().referenceDataService; } //setter for Spring injection public void setReferenceDataService(IReferenceDataService referenceDataService) { this.referenceDataService = referenceDataService; } …… //other service setters/getters protected static final ServiceManager getInstance() { return ourInstance; } }
|
|
|
|
and the Spring mapping:
<bean id="serviceManager" class="service.impl.ServiceManager">
<property name="referenceDataService">
<ref local="referenceDataService"/>
</property>
<property name="timeService">
<ref local="timeService"/>
</property>
<property name="securityService">
<ref local="securityService"/>
</property>
.......
<!-- other service declarations -->
</bean>
Many people do consider that this is perfectly fine solution and there are not any problems with it. If you are some of these people, probably the rest would not be of such an interest for you.
Issues with using Service Locator with DII have encountered several problems with such an implementation:
1. We end up with more than one way to retrieve a service, mock or stub. In some not domain objects, we get a service through Spring injections, in others we get it through static call to ServiceManager class. I feel this approach could bring a little confusion. This inconsistent approach of retrieving services could be a problem but I guess it could be argued that this is more of a question of “Enabling Attitude”:
http://martinfowler.com/bliki/EnablingAttitude.html rather than a problem with using Service Locator together with DI. However, I found out that this could be an actual problem in many practical situations. At the end, remembering when to use what is still an indicator for a “code smell”.
2. Another major problem is that ServiceManager is very hard to be tested, mocked or stubbed.The example implementation could enable us to mock specific services provided by the ServiceLocator through sub classing the ServiceLocator class and providing methods for overriding of a particular service.
public class ServiceManagerStub extends ServiceManager { public static void overrideTimeService(ITimeService timeService) { getInstance().setTimeService(timeService); } public static void overrideSecurityService(ISecurityService securityService) { getInstance().setSecurityService(securityService); } ................. //other service overridings }
|
Before we congratulate ourselves with successfully solving infrastructural issues that already has been solved by a DI lightweight container, which by the way we already use, I will try to point out some new problems that are introduced with this solutions.
The problem comes from the fact that we still use static class methods to retrieve services. So when we set up a mock service in a single test (ServiceManagerStub.overrideTimeService(getMockedTimeService()), we have to remember to reset it in the tearDown method. Again “we should remember”. Of course many times this is not done since running a single test class in an IDE would not cause a problem. Then we run all test from the build. At some point, we have a situation when a test which passes in an IDE fails in the build. The reason is that this test could be about 10-20 test classes after the one where we set up the mocked service. Some of the objects in this particular test use ServiceManager class to retrieve the same service that we mocked previously and we forget to reset it. Of course, we don’t have even a clue that a mocked service is invoked instead of a real one and we can not even think that 10-20 tests before our test, someone else have set a mocked implementation of the service we need.
Anyway, to make the story short, if somebody has used this kind of ServiceLocator, he/she should be familiar with this type of problems.
3. Issues with dynamic class loading.Any implementation of ServiceLocator that uses calls to static class methods will have problem with releasing the static reference from the memory potentially with every dynamic class loading in a J2EE application server on hot redeploying. I have definitely had a lot of class loader issues with WebSphere 5. (Not with Jetty BTW)
4. One of the consequence of using ServiceLocator is that we hard-wire it.This makes reusing of the domain objects that have hard coded dependence on the ServiceLocator often impossible due to dependencies on the particular application’s initialization and service infrastructure. In some of the cases, we were trying to reuse our domain objects in another application that will deal mostly with integration and will not use our current service infrastructure.
5. Another more general problems- ServiceLocator cut against interfaces, by forcing you to know about specific class.
- Using ServiceLocator in the beginning could not be a big problem. However, it could turn out that ServiceLocator class is access simultaneously by many threats and it is a performance bottleneck. In cases like that we can't switch to using a pool of such objects for any of the callers that have hard-coded dependency on ServiceLocator class. Velocity and Struts frameworks, for example, have found that this initial assumption can end up being wrong and restrictive.
I guess that we can find a solution to all problems related to ServiceLocator and most of them depend on how it is implemented but should we have to deal with all these problems on the first place when we already have an implemented solution in form of DI.
Alternative Solutions1. Passing a service as a parameter in the method call.Passing a service as a parameter would remove the problem of dealing with dependency injection, service locators, etc and could be an elegant solution in some cases. However, in most of the situations, especially when we have rich domain object model this would not be a workable solution.
I suspect that following this approach for a more complicated domain would result in behavior moving itself inexorably out of the domain and into our service layer - leaving us with the ubiquitous anemic domain model. Usually, my goal is for the service layer to be very thin - in the majority of cases each service would just find the domain object(s) it needs and then call a method on the domain - all the behavior would be part of the domain.
Also, when the object behavior is not controlled by ‘Transactional Script” (
http://martinfowler.com/eaaCatalog/transactionScript.html ) but rather than the flow of control emerges from object behavior in rich domain model, we usually have situation when one object delegate to another object, which call a third object and so on. In situations like that, we would need to simply propagate the service in every method in the chain if this service happens to be needed in the last one, for example. Something like this anti-pattern description:
http://www.picocontainer.org/Propagating+Dependency .
2. Using Hibernate to set the services/resourcesThis is probably the most compelling solutions since Hibernate anyway mange our domain objects. There are a couple of ways to do this. A god solution using Spring Sandbox classes is described here:
http://jroller.com/language/taranis/20050204?language=nlAnother solution is to use the currently available hibernate interceptors:
http://forum.springframework.org/archive/index.php/t-10547.htmlExample of using AuditInterceptor to inject TimeService in domain objects can look like that:
<bean id="time-service" class="service.TimeService"/>
<bean id="audit-interceptor" class="persistence.AuditInterceptor">
<property name="timeService">
<ref bean="time-service"/>
</property>
</bean>
<bean id="hibernate-session-factory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="jdbc-data-source"/>
</property>
<property name="entityInterceptor">
<ref local=" audit-interceptor"/>
</property>
<property name="mappingResources">
<list>
<value>
/somepackage/SomeDomainObject.hbm.xml
</value>
... ... ... ... ...
</list>
</property>
</bean>
The problem with using hibernate interceptors is that they will be fired up only when the domain object is either saved or retrieved from the database. Of course by the point you need to save a domain objects, you don’t need the service any more. So, if you need to inject services or resources in objects that are only retrieved from a database (never create new objects and then persist them) this approach will be very elegant solution.
However, when we create a new domain object, this interceptor is not going to be fired and we won’t have the resources or services injected in the newly created object.
Needles to say, that this is the most common scenario in practice. We will definitely have many places where we need to create a new object, perform some business operation on it and then persist it to a database. In situation like that we need to have/inject/retrieve any services/resources before we push it to Hibernate through session.save() for example. As some of the people from Spring framework suggest (
http://opensource2.atlassian.com/projects/spring/browse/SPR-431) we can use Spring via the ApplicationContext to create the domain object instance, populate it into our system via a lookup-method (to keep coupling low), and then push it into Hibernate.
3. Using Srping Bean factory to create your domain objectsIn order to inject a service during creation of a domain object, we can use the Spring factories BeanNameAutoProxyCreator and ProxyFactoryBean:
http://www.springframework.org/docs/reference/aop.html#aop-pfbAnd some opinion about the difference between ProxyFactoryBean and
BeanNameAutoProxyCreator http://erik.jteam.nl/?p=8 As the name suggests (although they use AOP) they are still factories. This means that you can’t create an object just with “new”, but you have to use some kind of factory (in this case Spring bean factory). The other problem is that in order to use these Spring bean factories or Spring AOP for that matter, the lifecycle of a domain objects should be managed by the Spring container. If this is not a concern for you, then these bean factories together with Spring AOP will do the job.
So, if we don’t have problem with Spring container managing the life cycle of our domain objects, we have the ability to intercept the creation of a domain object despite the fact that the creation of this object is managed by Hibernate as well.
One problem with this approach is that we have to create all of our domain objects via
factory and our domain objects will become dependent on Spring framework. Since I usually try to keep all business logic in pure POJO, having domain objects dependent on Spring is somewhat problematic. Another problem will be unit testing our domain objects. We should initialize Spring application context before running any test. This can slow a great deal our unit tests and we can loose one of the biggest benefits of unit testing – very fast feedbacks. Not to mention that the task of refactoring the creation of all domain object from using “new” to using factory is almost impossible to be done in respects of agile iterative approach.
Also, many people don’t think that this is very efficient solution either. Some of the arguments are about performance issues of Spring AOP implementation:
http://www.theserverside.com/news/thread.tss?thread_id=30681 .
So, if the biggest problem in this approach is the dependency on Spring bean factory, then we can work around it through using directly AOP in order to inject services in our domain objects.
4. Using AOP (AspectJ) to inject services/resources in domain objects during their instantiation. Finding resources or services (Dependency Location/ Look Up) should not be a concern of a domain object to deal with. One of the basic principles of OOP is that one object should have only one responsibility and should do it well. Looking up for resources or services is clearly a cross-cutting problem. This should be a very good candidate for AOP. We can use AspectJ in order to inject services/resources in DO both when they are loaded and when new ones are constructed.
One issue with this approach is that the use of Spring DI for everything else and AspectJ for DO is not a consistent approach. Still, in my opinion it is better that a static call in DO to class method in Service Locator object. Also, you can integrate very easily AspectJ with Spring:
http://static.springframework.org/spring/docs/1.2.x/reference/aspectj.html#d0e4554It looks like finally we have some feasible solution to the problem. Not so fast! According to my experience in dealing with customer enterprise applications and also according to many other opinions on AOP (one of them:
http://beust.com/weblog/archives/000180.html) most of developer community (as well as IT as a whole) remains very skeptical about a direct adoption of AOP. The idea of using open source aspect oriented compiler could be very problematic on many enterprise projects.
As a whole, I think that this is the least popular solution and the hardest one to sell it out to other developers, architects and especially to customers.
5. Using Hibernate to set the services/resources when retrieving DO and setting them directly when a new DO is instantiated. We can inject services/locators as with Hibernate interceptors when we retrieve objects from a database. When we create a new object, we can have the needed services/resources as a constructor parameter or just to set a property to the newly created DO.
Again we have at least two places that will deal with injecting services/resources – Hibernate interceptors as well as every place in the code where we create a new DO, which needs services. This probably will make us use a factory for creating DO, which brings us back to the solution with Spring bean factory managing our domain objects. Very informative discussion about this approach could be found here:
http://forum.springframework.org/showthread.php?t=12221ConclusionThis is the first time I feel that there is some inconsistency of using Spring framework for DI. To me, all this seems to beg the question - If Spring framework doesn’t provide effective way for DI in the domain model - and we want the majority of behavior to be in our domain model – then how we have to deal with this problem?
Anyway I still think that Spring framework is a great framework. In my opinion using AOP directly with AspectJ is the best approach for DI in the domain model. However, since AOP is not even close to wide spread adoption, probably the alternative solution to AOP in java5 – annotations could have the potential to solve the problem in less powerful but still elegant way (
http://weblogs.java.net/blog/crazybob/archive/2004/09/where_is_aop.html).
What approach are you using in your projects?