Modular Web-Applications based on Spring

Many of the Web-Applications we develop for our customers are based upon our small Framework on top of Spring / Spring MVC. This framework basically brings often used components ready-to-use (or ready to customize) and – of course – makes things even simpler than Spring already does.
Modular design of applications brings a lot of advantages but – as always – also some disadvantages. A modular structure can help to increase cohesion and let developers focus on the function their concrete module has. Another big thing is reusability. So the core framework already brings functionality that is used in all projects that depend on the framework so far: user management for example. On the other hand modular design also brings complexity. I think its business of a framework to hide this complexity from the user (developer in this case). Nevertheless its good when the developer knows (and understands) what goes on under the hood and (even more important) can easily extend the framework where he needs to.
As I mentioned we use Spring / Spring MVC as a base for many projects. Spring provides a lot of points where you can extend the framework by implementing interfaces and defining or injecting these implementations to the classes that do the real work (like interceptors in AnnotationHandlerMapping). In most cases this is enough. If you start to develop a modular application it is not. At least it was not for our case.
Our Web-Applications based on the mentioned Framework always use at least two “modules”: The core-module (that brings user management and some nice features to make coders happy) and the application itself. Each of these modules brings its own bean-configurations which are loaded all together using a wildcard resource like the following that reads all beans.xml files within any subfolder of META-INF in the applications classpath: classpath*:META-INF/**/beans.xml
This is a really simple way how the modules can interact since one module can provide a Service another depends on.
Now, the big problem is, that each module often brings its own components that have to be registered to Springs “services”. Let me explain the problem to you by talking about internationalization again. Each module brings its own resource bundle containing the internationalization for its web-interface components. Spring provides a simple way to register a MessageSource by defining one bean with id messageSource in your context. And that is exactly the problem. It is one bean. So you need a way where each module can register its own MessageSource, even if Spring only supports one. So our framework has to handle this, because it also introduces the modular structure.
The “out of the box” way that would work is that the application, that assembles all these modules together defines the MessageSource with all basenames (of the properties-files) the application uses. But this would be part of the mentioned complexity that should be kept away from the daily business and brings some other problems in (what, if one module wants to store its internationalization within the database?…).
So what did we do? We use a Simple plugin-mechanism a colleague developed and Synyx publishes OpenSource: Hera
We use a bean that gets registered as MessageSource to Spring that takes care of dispatching the message-resolving requests to the real MessageSources implementations spread all over the modules.

<bean id="messageSource">
    <property name="sources">
        <plugin:list class="org.synyx.minos.message.ModuleMessageSource"/>
    </property>
    <property name="useCodeAsDefaultMessage" value="true" />
</bean>

So this registers our DispatchingMessageSource that gets injected into all beans within the context, implementing ModuleMessageSource by Hera. This pretty much does the trick. The reason that we use ModuleMessageSource instead of Springs built-in MessageSource-interface is on the one hand so that we can do some performance-tweaks and on the other hand so that we dont get any “unwanted” implementations, which get to the context somehow.
With some simple dispatching logic within DispatchingMessageSource we found a powerful way to conquer the insufficiency of Spring, in conjunction with our modular system.

List candidates = sources.getPluginsFor(getPrefixFromCode(code));
for (MessageSourcePlugin source : candidates) {
    MessageFormat format = resolveMessageWithSource(source, code, locale);
    if (null != format) {
        return format;
    }
}

By the way, we use this mechanism a lot when it comes to easily extending functionality of the framework-core including HandlerInterceptor,PropertyEditorRegistrar and our Modules itself.

Kommentare

  1. Thanks! I will try to implement my own MessageSource in spring.