Separating Concerns and Advising Domain Objects Blog

Version 2


    Being able to "separate concerns" is a fundamental tenet of object-oriented programming. Give an object a small, well-defined set of responsibilities; and then assemble many of those small objects to provide a larger set of responsibilities. Following this pattern of keeping concerns separate enables our code to be 1) modular in the case that it needs to be reused, 2) testable because the code is separated into isolated units, and 3) agile in the case that requirements change. It is the challenge of assembling those objects that we'll explore in this article.

    Let's look at an example of a PersonServiceinterface that has a save() method. Clients will use this interface to save a Person object. The core implementation of this method persists a given Personto the underlying database. The implementation is tested and it works.

    /** * Person Service Interface */ public interface PersonService { public void save(Person person); } /** * Person Service Implementation */ public class PersonServiceImpl implements PersonService{ public void save(Person person){ doPersonSaveStuff(person); } private void doPersonSaveStuff(Person person){ // implementation details of saving a person } }

    When clients call the method, a security check is needed to enforce that the client is indeed allowed to save that Person. So aSecurityService is introduced with itsisSecure() method.SecurityService.isSecure() is tested to ensure that it properly enforces security.

    /** * Security Service Interface */ public interface SecurityService{ public boolean isSecure(); } /** * Security Service Implementation */ public class SecurityServiceImpl implements SecurityService{ public boolean isSecure(){ // returns true...this is just an illustration return true; } }

    There are now two distinct classes,PersonServiceImpl andSecurityServiceImpl, that both need to be called at runtime when a client calls the PersonServiceinterface's save() method. The simplest way to do this is to, within the save() method of thePersonService implementation, make a call out toSecurityService.isSecure().

    /** * Person Service Interface */ public class PersonServiceImpl implements PersonService{ public void save(Person person){ 
    if (securityService.isSecure()){ // if security check passes, do person save doPersonSaveStuff(person); }else{ throw new IllegalAccessException("Could not save " + " person: " + person); } } private void doPersonSaveStuff(Person person){ // implementation details of saving a person } private SecurityService securityService; public void setSecurityService(SecurityService securityService){ this.securityService = securityService; } }

    This approach, however, is at odds with object-orientation and the goal of separating concerns. By combining the code in this way, the save() method is now less modular because it cannot be used in the absence of the security check. Additionally, the save() method is less testable because thePerson-saving cannot be tested, in isolation, separate from the security-checking. The problem to be solved here is how to keep the person-saving concern separate from the security-checking concern, but combine them at runtime when appropriate.

    The theory of Aspect-Oriented Programming (AOP) formalized the problem definition laid out in the example above, and there have since been many implementations to help developers assemble their objects at runtime. A good starting point to learn more about AOP and various implementations is Wikipedia's AOP article. In AOP terms for the example above, we needed to "advise" thePersonService's save() method with the security "advice" by "weaving" it in when a client calls save(). These AOP terms will be used going forward in this article.

    There are many factors that go into choosing an approach for assembling concerns at runtime. Perhaps the biggest factor, though, is whether or not the object being advised is a singleton. In my opinion, there exist well-documented and well-implemented approaches for advising singletons. I personally enjoy Spring AOP when I need to advise singletons. Recently however, I came across the need to advise a domain object, an object that would be created frequently. I searched online for the best approach and I was pointed to AspectJ. This was unsatisfactory for me because AspectJ's learning curve and different compiler were too invasive for my need to advise just one domain object. In the remainder of this article, we will explore 1) why advising singletons is so different from advising domain objects, and 2) some alternatives to AspectJ for advising domain objects.

    Advising Singletons Versus Domain Objects

    A singleton, a class instantiated once, and a domain class, a class instantiated frequently, illustrate the opposing extremes of object-creation frequency. I have read and seen for myself that common techniques to advising singletons do not perform as well when applied to domain objects. The problem arises for domain objects due to the frequency with which they get created. The approach that Spring takes for advising singletons is to create a proxy for the singleton at runtime that will intercept its method calls. When clients make a call to the method, this proxy will configurably coordinate calls to the necessary advisors. Spring takes one of two approaches to create a proxy at runtime: either aJava dynamic proxy or a CGLIB code-generated proxy. Either way the proxy is created, the creation time is significantly slower than creating a regular object using Java's new keyword. For a singleton, one instance of the class will be created, so the time it takes to create the proxy for that object is not a large concern. For domain objects that would be created frequently, the performance of creating a runtime-generated proxy along with each object being advised may not be suitable. The following timings show the difference between creating a dynamic proxy as opposed to creating a regular object using the new keyword.

    1000000 iteration test for '
    Create dynamic proxy using 
    Proxy.newProxyInstance()' WARMED UP in 16 ms Iterations ,Total Time(ms) ,Avg(ms)/Iteration ,Transactions/sec 1000000 ,7978 ,0.007978 ,125344.71 1000000 iteration test for '
    Create regular object using new' WARMED UP in 0 ms Iterations ,Total Time(ms) ,Avg(ms)/Iteration ,Transactions/sec 1000000 ,63 ,0.000063 ,15873015

    Note that creating a CGLIB proxy is even slower than creating a Java dynamic proxy, but method invocations through the CGLIB proxy will perform better than the Java dynamic proxy.

    Advising Domain Objects

    What we need are some techniques to advise domain objects that will not significantly slow the object creation times of those advised objects and its advisors.

    Object Pool

    One option is to pool the created objects. The benefit of this approach is that we can still have the flexibility of a runtime-generated proxy for advising domain objects while eliminating much of the object-creation performance concerns. A side note is that Spring makes it very easy to pool objects and retrieve objects from that pool. The drawbacks of this approach are that we now have to deal with:

    • Returning the advised objects back to the pool when clients are done using them.
    • Clearing the state within an object before it is used again by another client.
    • Hoping that clients do not keep references to any objects that were released back to the pool. If clients do not cooperate, this could cause all sorts of hard-to-track-down data integrity issues.
    • Tuning the maximum size of the pool appropriately. The size would need to be based on the hardware, amount of memory allocated to the JVM, etc.

    So pooling is an option, but I'm not particularly fond of the external and internal complexity it adds to what should be simple objects. By having these additional considerations, the objects are all of a sudden not so simple.

    The Setup

    For the remainder of the discussion, we'll look at a simplePerson domain object with the following interface and corresponding implementation:

    /** * Interface of a Person domain object */ public interface Person { public String getName(); public void setName(String name); public long getId(); public void setId(long id); public Collection getAddresses(); public void setAddresses(Collection addresses); public boolean isModified(); void markModified(); } /** * Implementation of the Person domain object */ public class PersonImpl implements Person { private long id; private String name; private Collection addresses; private boolean modified; public Collection getAddresses() { return addresses; } public void setAddresses(Collection addresses) { this.addresses = addresses; } public long getId() { return id; } public void setId(long id) { = id; } public String getName() { return name; } public void setName(String name) { = name; } public boolean isModified(){ return modified; } public void markModified(){ modified = true; } }
    Class Extension

    A simple approach to advising Person would be to extend the core implementation using Java class extension. For example, here is an advisor for the getAddresses()method that will lazily load the addresses for aPerson:

    public class AddressLazyLoadingProxy 
    extends PersonImpl{ /** * Intercepts calls to getAddresses() and loads them * if they have not already been loaded. */ public Collection getAddresses(){ Collection addresses = super.getAddresses(); if (addresses == null){ addresses = lazyLoadAddresses(); super.setAddresses(addresses); } return addresses; } private Collection lazyLoadAddresses(){ /* * in reality, this would delegate to some DAO */ Collection addresses = new ArrayList(); Object address1 = new Object(); addresses.add(address1); Object address2 = new Object(); addresses.add(address2); return addresses; } }

    The class extension approach is straightforward and easy to implement for this single advisor. However, if additional advisors are added, this approach quickly becomes unwieldy as each advisor extends another advisor. There is hardly any flexibility. Without changing class structure, we cannot pick and choose which advisors are used with Person and cannot change the order of the advisors. Even if there is no runtime requirement to change the advice structure, the advice structure is not agile if requirements do change.

    Static Decorating Proxy

    Another option we'll explore is using the Gang of Four's Decorator pattern to decorate the domain object with any number of advisors in any order. To set this up, we would first create a base proxy class from which all our advice proxies would extend. This base proxy will accept any implementation ofPerson in its constructor and will delegate all method calls to that target person. Here's a portion of that class:

    /** * Base class for all Person proxies following * the Decorator pattern. */ public class BasePersonProxy 
    implements Person { private Person targetPerson; /** * Construct the proxy and provide the class that will be * called to proceed down chain of proxies. * * If the passed in object is not a proxy, then this will * delegate directly to the Person object. * * @param targetPerson */ 
    public BasePersonProxy(Person targetPerson){ this.targetPerson = targetPerson; } public long getId() { return targetPerson.getId(); } public void setId(long id) { targetPerson.setId(id); } public Collection getAddresses() { return targetPerson.getAddresses(); } public void setAddresses(Collection addresses) { targetPerson.setAddresses(addresses); }

    Using this pattern, our lazy-loading advice looks almost identical to how it looked in the Class Extension example; the only differences being that it now extends fromBasePersonProxy instead of fromPersonImpl and it has a constructor that takes thePerson being proxied.

    /** * Proxy that will lazily load a Person's addresses */ public class AddressLazyLoadingProxy 
    extends BasePersonProxy{ 
    public AddressLazyLoadingProxy(Person targetPerson) { super(targetPerson); } public Collection getAddresses(){ Collection addresses = super.getAddresses(); if (addresses == null){ addresses = lazyLoadAddresses(); super.setAddresses(addresses); } return addresses; } private Collection lazyLoadAddresses(){ /* * in reality, this would delegate to some DAO */ Collection addresses = new ArrayList(); Object address1 = new Object(); addresses.add(address1); Object address2 = new Object(); addresses.add(address2); return addresses; } }

    Note that because BasePersonProxy provided default implementations for every Person method, theAddressLazyLoadingProxy only needed to implement the methods it chose to proxy.

    To create a Person that is proxied with the lazy-loading advice, the code could look something like the following:

    /** * Creates Person */ public Person createPerson() { // create the target person Person person = new PersonImpl(); // pass the target person being proxied in to the new proxy person = 
    new AddressLazyLoadingProxy(person); // return the proxied person return person; }

    If we have other advisors following this static decorator pattern, they would each extend from BasePersonProxyand they would each be created in a similar manner. For example:

    /** * Creates Person */ public Person createPerson() { Person person = new PersonImpl(); person = new AddressLazyLoadingProxy(person); person = new PersonProxy_2(person); person = new PersonProxy_3(person); person = new PersonProxy_n(person); return person; }

    Taking this approach, we can have any number of advisors forPerson. We can easily pick and choose which ones we use and can easily choose the order in which they advisePerson. Also, as the Decorator pattern suggests, the class hierarchy stays shallow, which usually enables flexibility. To see an exhaustive discussion of the Decorator pattern, I refer you to the Gang of Four's book on design patterns. This advice pattern is described as "static" because the method(s) being advised, getAddresses() in this case, is statically baked into the class structure of the proxy. This is different from a dynamic proxy approach where reflection can be used to evaluate whether or not to advise the method. From an AOP perspective, this static decorating pattern becomes less attractive when a specific advisor needs to advise many methods on the class. Let's look at a person-modification advisor that will advise everysetXXX() method on the Personimplementation by calling the Person'smarkModified() method after making thesetXXX() call on the target. For example:

    /** * Proxy that will mark the target person as modified */ public class PersonModificationProxy extends BasePersonProxy { /** * Constructs an person modification proxy with * targetPerson as the proxy target * * @param targetPerson target of this proxy */ public PersonModificationProxy(Person targetPerson) { super(targetPerson); } public void setName(String name){ super.setName(name); 
    super.markModified(); } public void setId(long id){ super.setId(id); 
    super.markModified(); } public void setAddresses(Collection addresses){ super.setAddresses(addresses); 
    super.markModified(); } }

    For the AddressLazyLoadingProxy class, that proxy was all about the getAddresses() method. This person-modification proxy is markedly different in that it is about many methods; every setXXX() method to be exact. We needed to extend every setXXX() method and each method implementation has similar code. Not only that, but for setters added over time, we would need to keep this advisor up to date so that those setters would also be proxied. The duplicate code in each method and the necessary upkeep of this class both indicate that there must be a better way. Ideally, we would be able to callmarkModified() for any setXXX()call without the need to explicitly proxy eachsetXXX() method. We really need the use of a dynamic proxy so that every method call on Person can go through an InvocationHandler, like the following:

    public class PersonModificationIh implements InvocationHandler{ public Object invoke(Proxy proxy, Method method, Object[] args) throws Throwable { // call the method the client wanted to call Object returnObject = method.invoke(targetPerson, args); // call markModified() for setXXX() method calls 
    if (method.getName().startsWith("set")){ targetPerson.markModified(); } return returnObject; } }

    What's missing from this code snippet is wheretargetPerson came from. If a dynamic proxy cannot exist per-instance due to performance concerns, then thetargetPerson cannot exist as a member of thePersonModificationIh class. This next pattern will look at a mechanism to make targetPerson available to the invocation handle while still supporting the flexibility that the Decorator pattern provided for advising aPerson.

    Dynamic Decorating Proxy

    As we saw earlier, we cannot create a dynamic proxy for eachPerson instance if object creation times are critical. Instead, in this pattern we will create a singleton dynamic proxy for an interface that looks similar to a Person, but where each method takes the target Person as the first parameter. This interface is essentially a stateless version of thePerson interface:

    /** * Stateless equivalent of the Person interface. */ public interface StatelessPerson { long getId(Person targetPerson); void setId(Person targetPerson, long id); String getName(Person targetPerson); void setName(Person targetPerson, String name); Collection getAddresses(Person targetPerson); void setAddresses(Person targetPerson, Collection addresses); boolean isModified(Person targetPerson); void markModified(Person targetPerson); }

    Because every method accepts the target person to be operated on, an implementation of this interface can be stateless and a singleton. Given this, here is the singleton dynamic proxy for theStatelessPerson that does the person-modification logic we want using reflection:

    /** * Object Modification Advice for a StatelessPerson */ public class PersonModificationIh implements InvocationHandler{ public Object invoke(Proxy proxy, Method method, Object[] args) throws Throwable { // call the method the client wanted to call Object returnObject = this.proceed(method, args); // call markModified() for setXXX() method calls if (method.getName().startsWith("set")){ 
    Person targetPerson = (Person)args[0]; targetPerson.markModified(); } return returnObject; } private static final Class statefulClass = Person.class; /** * Calls the stateful equivalent of the stateless method. * This could be factored out to a base class or a reusable * utility. */ private Object proceed(Method statelessMethod, Object[] statelessArgs) throws Throwable { // statefulObject is assumed to be the first arg Object statefulObject = args[0]; // locate stateful method based on stateless one Method statefulMethod=findStatefulMethod(statelessMethod); // convert the stateless args to stateful args Object[] statefulArgs=new Object[statelessArgs.length-1]; System.arraycopy(args, 1, statefulArgs, 0, statefulArgs.length); try{ // invoke the stateful method on the stateful object return statefulMethod.invoke(statefulObject, statefulArgs); }catch(InvocationTargetException ite){ throw ite.getCause(); } } /** * Given a stateless method on a stateless class, returns * the stateful equivalent on the corresponding stateful * class. This could be factored out to a base class * or a reusable utility. */ private Method findStatefulMethod(Method statelessMethod){ // this could easily be cache'd to be more efficient Class[] statelessParmTypes = statelessMethod. getParameterTypes(); Class[] statefulParmTypes = new Class[statelessParmTypes.length - 1]; System.arraycopy(statelessParmTypes, 1, statefulParmTypes, 0, statefulParmTypes.length); Method statefulMethod = null; try { statefulMethod = statefulClass.getMethod( statelessMethod.getName(), statefulParmTypes); } catch (Exception e) { throw new RuntimeException("Could not find stateful " + " equivalent of stateless method: " + statelessMethod); } return statefulMethod; } }

    Given this, we can create a Person decorator for our original stateful Person that leverages the stateless Person. Here's a portion of that class:

    public class PersonDynamicProxy implements Person{ 
    private StatelessPerson statelessPerson; private Person targetPerson; /** * Construct a Person dynamic proxy where all method calls * are delegated to the 
    statelessPerson. * * @param targetPerson * @param statelessPerson */ public PersonDynamicProxy(Person targetPerson, StatelessPerson statelessPerson){ this.targetPerson = targetPerson; this.statelessPerson = statelessPerson; } public long getId() { 
    return statelessPerson.getId(targetPerson); } public void setId(long id) { statelessPerson.setId(targetPerson, id); } public String setName(String name) { statelessPerson.setName(targetPerson, name); }

    Figure 1 below shows the high-level runtime interaction we achieve by this design:

    Dynamic Proxy Interaction
    Figure 1. Dynamic proxy interaction

    Before the interactions in Figure 1 occurred, the client obtained a Person implementation. This implementation was decorated by a PersonDynamicProxyobject which held a reference to 1) a PersonImplinstance, targetPerson, and 2) a runtime generatedPersonModificationDynamicProxy dynamic proxy whose invocation handler was PersonModificationIh. Let's now look at the interactions shown in Figure 1:

    1. The client calls the setName(String) method on itsPerson implementation. ThesetName(String) method on thePersonDynamicProxy is invoked.

    2. PersonDynamicProxy, in turn, calls thesetName(Person, String) method on thePersonModificationDynamicProxy, passing in the targetPerson it should operate on. As a reminder, here's thePersonDynamicProxy code that made the call to the runtime generated dynamic proxy:

      public String setName(String name) { statelessPerson.setName(targetPerson, name); }
    3. The invoke() method is then invoked on thePersonModificationIh, the invocation handler for the runtime generated PersonModificationDynamicProxy. Within the invoke() method, the equivalent method,setName(String), is invoked on thetargetPerson using reflection.

    4. PersonModificationIh then determines that the name of the invoked method started with "set," so it also called themarkModified() method on targetPersonusing reflection.

    With this approach, we now have an advisor that can advise everysetXXX() method and does not have to change if moresetXXX() methods are added to the Personinterface. Because we took a decorating approach for both the static and dynamic proxy, we can mix and match our static proxies with our dynamic proxies in any order we want. Additionally, all of the frequent object creation is done with the Java newkeyword, so object creation times are not sacrificed. Here is some example code that creates a person with both the static address lazy-loading advice and the dynamic person-modification advice:

    /** * Creates a Person with two advisors: the static lazy-loading advisor * and the dynamic person-modification advisor. */ public Person createPerson() { Person person = new PersonImpl(); person = new PersonDynamicProxy(person, statelessModificationAdvice); person = new AddressLazyLoadingProxy(person); return person; } /** * Stateless Object Modification advice */ private static StatelessPerson statelessModificationAdvice=null; static{ // initialize the stateless person-modification advice singleton ClassLoader cl = PersonFactoryImpl.class.getClassLoader(); InvocationHandler ih = new PersonModificationIh(); Class[] interfacesToProxy = new Class[]{StatelessPerson.class}; statelessModificationAdvice = (StatelessPerson)Proxy. newProxyInstance(cl, interfacesToProxy, ih); }

    The drawbacks to this stateless dynamic proxy approach are the following:

    • A stateless interface must be maintained along with the stateful interface. I imagine some build-time code generation could be used to keep the two interfaces synchronized. For now, all I've done is written a JUnit test (see the sample code in the Resources section) that looks at both class definitions and fails if they are out of sync.
    • A dynamic proxy along with reflection is used at runtime so method calls will be slower than direct method calls. I imagine a CGLIB code-generated proxy could be used for the stateless advisor if you find that the method calls through the dynamic proxy are too slow for your needs.


    Advising objects to separate concerns is an extremely powerful pattern. Spring-like approaches to AOP are fantastic choices if few instances of the advised class need to be created. However, many domain objects do not fall in this category. AspectJ is a full-featured AOP implementation that is designed to advise both singletons and domain objects. However, AspectJ is not a trivial technology to bring into a development environment, so knowing alternatives is a good thing. For advising domain objects, we explored object pooling, class extension, and using the Decorator pattern, and there are undoubtedly others. Depending on the scenario, each approach enables a separation of concerns that object-oriented programming and aspect-oriented programming advocate. What I attempted to illustrate in this article were some factors that go into choosing an advice approach and some options available for advising domain objects.