February 20, 2007

Spring and the golden XML hammer

Writing about web page http://www.theserverside.com/tt/articles/article.tss?l=SpringLoadedObserverPattern

This article describes as best practice, one of the things that I’m really coming to dislike about the Spring Framework – the tendency to use XML for object construction for no better reason than ‘because I can’.

Now, I love spring; It’s revolutionised the way I, and many others, write code, and for the better. But it does have a tendency to produce reams of XML. As a data format, I think XML is OK. It’s precise, and the tooling is good, though it’s a good deal more verbose than something like JSON or YAML, which, IMO, have 80% of the functionality with 20% of the overhead.

For aspects of an application which are genuinely configuration, such as the mapping of URLs to controllers, or configuration of persistence contexts, XML is better than code; no doubt about it. For the construction of object graphs, XML is sometimes better than code. But this example is just pushing it too far. It describes setting up an observer/observable pair, using the side-effects of spring’s MethodInvokingFactoryBean to call the addListener() method, rather than doing it in code.

Now, this is just clunky. Instead of one line of code that says

townCrier.addListener(townResident);

we have this

<bean id="registerTownResident1" 
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject"><ref local="townCrier"/></property>
    <property name="targetMethod"><value>addListener</value></property>
    <property name="arguments">
    <list>
      <ref bean="townResident1"/>
    </list>
    </property>
</bean>

Ten lines of XML. No static type-checking (I hope you’ve got a bunch of tests that verify your contexts…) The addListener invocation, the thing we’re trying to achieve here, is kind of buried; the bean that’s actually generated is never used, the whole thing is far from obvious in it’s intent.

The only notional advantage I can see is that you can add and remove listeners without touching the code. But how much of an advantage is that? In most situations, where you’re using a method-invoking synchronous observer/subject pattern like this, listeners are part of the application, and not part of the configuration; you wouldn’t remove one without first consulting a developer anyway. When you’ve got genuinely replaceable listeners, then it’s more common IME to have some kind of an abstraction like a JMS queue or a message bus in between subject and listener, so that the listeners are registered with the queue, not the subject itself.

If it were up to me, I’d probably have a class called when the context is built (via an ApplicationListener maybe), which explicitly built up the subject/observer relations. If I had some configurable relationships, I might pass in a list of observers, but that’s about as far as it would go;

\\ set by IOC
setChangeEventListeners(List<ChangeEventListener> listeners){
   this.changeListenersToRegister = listeners;
}
onContextRefreshed(){

  \\ configure a subject with a list of observers
  \\\
   for (ChangeEventListener listener : this.changeListenersToRegister){
       this.changeEventBroadcaster.addListener(listener);
   }

   \\ now hard-code a subject that won't need to change frequently
   auditLog.addListener(new log4j.Category("AUDIT_LOG");

  \\ ... and so on  
}

- this object starts to look a bit vague and ill-defined, doing a little with lots of objects, but that’s because really it’s just a part of the context/configuration; it’s not a part of the domain per se.

There are a few other options that, in some situations, might be better than this;

  • Give the subject a constructor that takes a list of observers, and let it wire them at construction time – then pass the list from within your XML context
  • If you can’t modify the subject itself, make a custom FactoryBean that takes the list of observers, constructs the subject and adds all the observers to it
  • One that requires a bit of divergence from the standard Spring usage. Have a context that’s defined by a bit of scripting code – JRuby, or BSH, or javascript/rhino, rather than by XML. That way you make your method calls more explicit, and allow developers to easily see what relationships are being built up , whilst still keeping some clear separation between the configuration and the java code. If you had loads of Observer/subject configuration to maintain, you could define a little DSL for it (or store it in a database) and have a custom context to parse the DSL and configure the beans.

- One comment Not publicly viewable

  1. I’m a fan of the way Tapestry does things, I started looking at it in preparation for a job interview and it seems like a very tidy approach to web development. The downside is that it’s not too great with Hibernate, but this can be resolved by going through Spring. Each page requires an html file, an xml file and a java class which might end up being a bit overkill for simple things but it keeps things neat.

    20 Feb 2007, 15:10


Add a comment

You are not allowed to comment on this entry as it has restricted commenting permissions.

Most recent entries

Loading…

Search this blog

on twitter...


    Tags

    Not signed in
    Sign in

    Powered by BlogBuilder
    © MMXXI