Lateral Programming

Coding out of the box

Why use Spring… if you have a HashMap at hand?

Posted by eutrilla on April 7, 2008

Ok, let’s start with a disclaimer. There must be a thousand reasons to use Spring. It’s a terrific piece of work. And nobody can possibly complain about its price.

But it also has its drawbacks. Probably the first one that anybody could think of would be XML config files. Another one is, oddly enough, one of its strong points: it integrates an awful lot of functionality. Although this may be very good indeed if you’re using it all, for simple/medium apps Spring is simply too bloated.

Guice is a step in the right direction, I think. Just a DI container, no more. Google has also chosen to use annotations instead of XML config files, which helps to keep it manageable. But I still have the annoying thought that it shouldn’t be that hard to keep our software nice and clean, without the aid of a whole framework.

Why DI is not always good enough

Maybe the problem with both Spring and Guice is a flaw in the Dependency Injection pattern itself. It looks nice in the simple UML diagrams used to describe the concept, but it gets harder when the number of classes and components increases.

Let’s say that we’re developing a component, and we expect to use it in a DI container. We don’t want to expose too many implementation details, so we decide that all calls from the outside should be made using a façade. Now one of our classes needs to access a log service, and we would like it to be configurable. So we need a setter. Well, actually, we need at least two, one in the calling class and one in the façade, since the former shouldn’t be directly available as part of the public API. They could even be more if the façade doesn’t have directly a reference to the class in need of logging. The more complex the components are, the more likely is this to happen. At the end, we need some extra code to connect services and the classes where they are used.

But now, we have our shiny loosely-coupled component ready for use. So we insert it in our app, together with some tens of other modules. It turns out that all modules require access to the log service. So we have to repeat a very similar setLogger() call tens of times. No wonder DI containers require a LOT of configuration.

Isn’t there a simpler solution?

On the other hand, let’s suppose we forget for a while about Dependency Injection and try another pattern that targets exactly the same use case as DI: the Service Locator. If any of you don’t know what it looks like, I’ll let Martin Fowler introduce it. Maybe it’s not as trendy as DI at the moment, but it’s not anything really new. After all, Service Locator is the very same pattern behind J2EE.

Well, it is quite clear why DI is better, isn’t it? The Service Locator introduces a new dependency on the calling component, so it is not so loosely-coupled anymore. That’s a big problem, right? Well, maybe not.

As Martin Fowler points out in the article previously linked, a dynamic Service Locator can be implemented as just a simple HashMap with some accessors. And has quite a few interesting advantages:

  • It is generic, so it is not much a burden dependency-wise.
  • If a class inside your components requires access to a new service, you don’t need to change the other classes in the component to propagate a reference from the outside, as long as the service is registered in a static instance of the Service Locator.
  • Even if you can’t use a static instance, or you have different contexts which require different sets of services, you only need to propagate one object to access all them: the locator itself.
  • Now the configuration is reduced to create and register in the locator the different components during startup.
  • It is possible to hot-swap easily implementations of the services.
  • No extra framework is needed. Just a HashMap!

Ok, nothing is that nice or that easy

Of course I’m not trying to compare a plain HashMap with the whole Spring Framework, just with the DI-container part of it. And even so, it sure has some drawbacks:

  • Configuration (aka Creation and registration of service instances) is done in code. Some may argue that XML-based deployment is more flexible. Personally, I don’t find much harder to edit and compile an initialization manager class, and for complex projects code beats XML.
  • The dependency on the locator itself is spread through a good part of the classes that make up the application. Since it is so general, it’s not a big deal. If the Locator were part of the standard Java library, it would be almost like having a dependency to java.lang.String.
  • All components should use the same Service Locator class. Otherwise services would have to be registered several times, and design becomes messy. But since Locators can’t be that different from each other, it should be easy to transform one class into another using an adapter. Again, if such simple class was part of the standard Java library, it wouldn’t be a problem at all.
  • All service references require a cast. Annoying, but not that bad.
  • If components are not well documented, it’s hard to say which dependencies they have, whereas DI-adapted components have the list of dependencies right there in their public API.

But would it work well enough in *real* projects?

I can say that I’ve used this approach in several projects and found it really easy to implement and use. We even made some improvements over Martin Fowler’s initial implementation, though. The keys to store and retrieve the Service instances are no longer Strings, but the class of the desired interface itself. In that way, we avoid typing errors in the identifier and we can place an assert in the service registration method so we can be sure that the instance registered is indeed an implementation of the interface.

Quoting Martin Fowler’s article:

The choice between Service Locator and Dependency Injection is less important than the principle of separating service configuration from the use of services within an application.

To finish, I’d like to mention Netbean’s Lookup class and Java 6′s ServiceLoader class. A very interesting article by John O’Conner (Creating Extensible Applications with the Java Platform) explains the differences between both and how to use them. Again, this is Service Locator in action, but now these classes try to find the services in the classpath instead of needing to be configured during startup. So they are very convenient for plugin-style development, but provide less control over which/how many implementations of the services are used, and therefore target a slightly different use case. But seems to confirm that there are other, simpler options out there to get rid of spaguetti code.

About these ads

14 Responses to “Why use Spring… if you have a HashMap at hand?”

  1. Chris said

    We even made some improvements over Martin Fowler’s initial implementation, though. The keys to store and retrieve the Service instances are no longer Strings, but the class of the desired interface itself.

    So, when you have to provide multiple implementations of the desired interface that are exactly the same except for their configuration state, then what? For example, you have two different implementations of Hibernate’s SessionFactory because you have two different databases you want to point to. Same interface (and in fact class) that just has different configuration data. Looking them up by interface or class name should be…interesting. Using annotations for the same thing should also prove entertaining.

    Excellent article but I find the “XML hell” tact against Spring’s configuration a bit old and tired. They’ve made several steps at improving the situation and if you intelligently break up the configuration files themselves it doesn’t become a cognitive load problem on the developers.

  2. “So we have to repeat a very similar setLogger() call tens of times. No wonder DI containers require a LOT of configuration…. ”

    You have to do exactly the same thing if you are using service locator. i.e.

    this.logger = ServiceLocator.getInstance().get(Logger.class);

    For each class that needs to use the logger. And given that the spring equivalent is this:

    I'm not sure what exactly your argument is.

  3. Sorry my spring config got swallowed by its html tags…

    (property name=”sellerService”)(ref bean=”sellerService” /)(/property)

  4. eutrilla said

    @Shannon I think you left out all the bits where you tell Spring whether your sellerService is a Singleton or not, the scope, and so on. Oh, yes, and you’ll probably have to put several lines like that for each component. The more components in the app, the more fun.

    Ok, how much could it be? 40 lines? 200 lines? 1000 lines? It may be not that much, but it just isn’t really needed, and doesn’t follow the KISS principle. Use it at your own risk.

    Regarding the line about getting the service instance, the difference is that it is in the class that uses the service, not in the initialization. That means if that class is in another component, wherever I reuse it I don’t have to explicitly provide that reference, whereas in DI I have to. And by the way, if I’m not mistaken, the Spring equivalent is:

    public void setLogger(Logger logger){
    this.logger = logger;
    }

  5. eutrilla said

    @Chris I mentioned the class-as-key as improvement because that helps keep things neat in the initialization and avoids potential problems related to bad typing of the labels.
    Actually, our ServiceLocator implementation has two HashMaps, one for services (i.e. identified by their class) and another one for general Objects (i.e. identified by a String). We found that useful to store global variables such as the current user name, the language to be used in the GUI and so on. You just have to be careful about what you store inside of it (you know, Global Variables Are Evil).

    In the case you mention I’d think of two different approaches. The first one would be to store as a service a generic Factory that allows you to obtain the specific Factory you want. The second option is to store it just as named objects. The point is that the ServiceLocator implementation is that easy that you can adapt it to whichever your needs are quite easily.

    Just as a sidenote, yes, I agree that XML hell of Spring has already throughfully discussed, but since I was talking about the complexity of Spring I couldn’t avoid to mention the most classic one ;D. But, indeed, I use the word “XML” just four times in a 90-ish line post. I devoted much more time to describe why it was harder to design components for use in DI than to nag about how much configuration I had to write. The whole point of the article is to compare the Service Locator pattern with the Dependency Injection patttern, and the popularity it has got due to Spring. But sadly, most of the comments (both here and at dzone) seems to be aimed at those four appearances of “XML”.

  6. B Repko said

    OSGi is a service locator-based architecture btw so that is out there. And DI uses SL in a sense that it looks up the dependency and then injects it. The difference is that it does the lookup rather than the caller. An extra level is put in there. Both SL and DI can be mocked for testing so that’s not a big deal. I prefer SL when the object is remote or its availability may change because I like to know when it fails. Otherwise, for component configuration, I’ll use DI.

  7. Chris said

    Actually, our ServiceLocator implementation has two HashMaps, one for services (i.e. identified by their class) and another one for general Objects (i.e. identified by a String).

    Well, if the Maps contain the same configuration (different keys) you’re beating DRY to death. If they don’t then a dev is going to have to know which one to go get or know to pass in a String this time and a class name the next to locate dependencies or use both in one class if one is by class the other by name.

    In the case you mention I’d think of two different approaches. The first one would be to store as a service a generic Factory that allows you to obtain the specific Factory you want.

    Agreed that is a solution but you would now be introducing artificial object just get to around the configuration. That factory would have no reason to be except as a workaround.

    The second option is to store it just as named objects.

    Now you’re back to your bad typing of labels problem….

    I think you left out all the bits where you tell Spring whether your sellerService is a Singleton or not, the scope, and so on.

    Wow. In my version of Spring I usually need an id and a class attribute only for the bean definition itself. Now I can use those other things if I want – but I don’t have to:

    I only ended with a comment about the 4 lines containing "XML". ;) The majority of my comment is aimed at pointing out that when you approach the edge cases of usage the ServiceLocator will get "ugly" too.

  8. Chris said

    Boo! My example didn’t work:

    Bean + one dependency on some DAO somewhere in the app context. Write a simple test class that spins up the Spring app context like you want and you can verify before you do anything else that the bad label problem doesn’t appear.

  9. eutrilla said

    You’re right, the named objects HashMap is rarely used, so it’s not usually a problem for the dev to know where to look for something.

    By the way, there is a third option for the SessionFactory problem. ServiceLocators don’t need to be accessed statically. So if you have two objects that require different Factories, you can pass different instances of the ServiceLocator to each object, each of which has a different instance for a given interface. Yes, that’s DI, so what? I just need to pass one object. I’ve never said that DI is bad, just that sometimes SL may be simpler. And the mix of both can be pretty good, too;D

    Everything looks ugly in the corner cases. That’s why they’re corner cases, isn’t it?

  10. KiLVaiDeN said

    Just would like to point that obviously, the DI part of Spring is *NOT* the reason that makes it that popular.

    The main advantage, is it’s integration with different technologies and frameworks out there, and it’s AOP oriented configuration which makes it very powerful.

    K

  11. Igor said

    If you want simple (but not simpler) container, you might want to try petite:
    http://jodd.sourceforge.net/doc/petite.html
    just two annotations, has auto-configuration, can work with proxies, it is aware of scopes.. and it is small;)

  12. Nice article.

    I think with the rise of Java 5+/JEE 5 there is less and less a need for spring. I like the simplicity of Guice, and while DI is just another way of doing something developers have always done, it does have its drawbacks which i think you have accurately captured.

    Here is a comment i left on Kevin’s (Guice co-creator) blog which talks along the same lines, and why i don’t mind the Guice way!

    http://smallwig.blogspot.com/2007/06/coupling.html#c347596939873173442

  13. Interesting issue, I didn’t thought reading this was going to be so great when I read the link!!

  14. Data Transformation
    Your blog site is pretty cool! How was it made Data Transformation

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: