Wednesday, October 14, 2009

How to make your Spring wirings more manageable

When Spring first came along it was a breath of fresh air - a clever way to wire up applications which did not rely on the use of all sorts of singletons all over the place. (I still remember what it was like working that way, and shudder at the thought.) The idea was simple: let classes in the application just do their own job, but leave the business of figuring out how to get collaborators to the IoC container, with the help of some XML configuration. No longer did your application code did not have to deal the messy business of having to resolve their own dependencies.

OK, we've solved the problem with the code, but the job isn't completely done. Actually, the problem has shifted onto managing Spring wirings.

The problem with managing Spring wirings

Applications necessarily get big. You end up having to write a lot of XML. So while your code may stay nice and clean, you end up with some tricky questions about how to manage this part of your application. Of course, here you try to be as "modular" as you can, putting DAOs together, infrastructure related beans together, etc. You try to identify vertical slices for your application and put beans relating to particular vertical slices together.

The problem is that for all the bean definitions that exist in your application, some groups are inherently coupled, while others are inherently free of coupling. In a vanilla Spring application, there is no way to express these dependencies at a system level. So it is very easy for your application wiring to become an unnecessarily fragile collection of invisible dependencies, liable to break in unexpected ways when any rearrangement takes place.

Autowiring, namespaces and class path scanners don't necessarily help

Then of course there is the drudgery of editing XML configuration files by hand. Personally, I think that is less of a problem, but Spring has gone to great lengths to free developers from some of this pain over the years, through the introduction of autowiring, class path scanners, and XML namespaces. I happily embrace all of the above as they reduce the amount of code I need to write, but they don't address the fundamental problem. They don't enhance one's ability to express dependencies between parts of your application at a system level, and where possible, to reduce these dependencies.

So how does Impala help?

Remember how easy Spring seemed when we were working with just small applications? Impala allows you to keep your applications small, or at least keep them feeling small. This is done through modules. You can think of a module as a mini-application which is able to communicate with other mini-applications in the system through well defined mechanisms and through sharing common interfaces.

The Spring configuration for each module remains pretty small. If it starts getting too big, then its a good sign that some of it's functionality needs to be split off into another module. So within the module, you only need to deal with small configurations - bite size chunks.

You can configure beans within a module however you like - through plain Spring XML, custom namespaces or through annotations. If your module needs to use functionality from other parts of the system (as most will), then you can import services directly from the shared service registry (as long as the service has been exported using an interface or class visible to the current module). If necessary, you can allow your module to depend directly on another module, either as a dependent or as a direct child.

If you need to compose your application in different ways according to environment or customer, that's easy too. Simply change which modules your deploy, or you can even vary the configuration of within a module according to requirements.

You no longer need to wait ages for integration tests to load, because you can easily create integration tests which consist simply of the modules you need to use.

And you get the benefits of much more productive, responsive development environment because each of these modules can be reloaded on the fly, either individually, in groups, or as a whole - and this applies whether you are running integration tests or running your application on a web container.

Tuesday, October 6, 2009

Talk at the Server Side Europe in Prague

I am doing a talk on Impala at The Server Side Europe's conference in Prague, which is taking place on October the 27th and 28th. Really looking forward to it, especially as I used to be a regular visitor of Prague in the early 90s when I was living in Germany.

Saturday, October 3, 2009

Why web.xml makes it hard to write modular web applications

In a typical Java enterprise application, the web.xml is used to define servlets and filters, which are among the main entry points into your application from the outside world. Since web.xml cannot be reloaded, added to or modified without reloading the entire application, it is not a very convenient place to host application configuration and definitions in a dynamic module applications.

Another related problem is the limitations of the request mapping capability of web containers as defined by the current servlet specification. Currently, these make it possible to map requests to servlets and filters using an exact match (e.g. /myservlet/myresource) or either a prefix and wildcard match (e.g /myservlet/*) or using a suffix wildcard match (e.g. *.do). It doesn't allow you to use a combination of prefix and suffix wildcard matches. This means that you cannot, for example, use the path (/myprefix/*) to match application URLs, and at the same time allow your application's CSS files to be accessible in a resource such as /myprefix/styles.css.

Multi-module web applications in Impala

One of biggest changes in the recent 1.0 RC1 release of Impala is the ability to write web applications which are less reliant on web.xml, allowing both dynamic registration of modules containing servlets and filters, and at the same time solving the path mapping limitation described in the previous paragraph.

In an Impala application, you cannot do away with the web.xml altogether. However, you can reduce the request handlers defined in web.xml to the following:


In the example above, the ModuleProxyFilter captures requests and routes them into Impala modules. The mapping rules which determine which modules service which requests are contained within modules. Here's an example from the URL mapping sample:

<web:to-module prefix = "/webview" setServletPath="true"/>
<web:to-handler extension = "htm" servletName="urlmapping-webview" filterNames = "characterEncodingFilter,sysoutLoggingFilter"/>
<web:to-handler extension = "css" servletName="urlmapping-resources"/>

<web:servlet id = "urlmapping-webview"
servletClass = "org.impalaframework.web.spring.servlet.InternalModuleServlet"/>

<web:servlet id = "urlmapping-resources"
servletClass = "org.springframework.js.resource.ResourceServlet"
initParameters = "cacheTimeout=10"/>

<web:filter id = "characterEncodingFilter"
filterClass = "org.springframework.web.filter.CharacterEncodingFilter"
initParameters = "forceEncoding=true,encoding=utf8">

<web:filter id = "sysoutLoggingFilter"
filterClass = "org.impalaframework.urlmapping.webview.SysoutLoggingFilter">

This module defines a number of servlets and filters who's life cycles are tied to that of the module, rather than that of web.xml. They can be dynamically registered and removed, and don't require an application restart. The modules can contain all the classes and resources necessary to service requests, without relying on the presence, for example, or resources such as JavaScript files on the context path (e.g. in the WEB-INF directory).

What about Servlet 3.0?

The changes described above are very much in line with the changes in the forthcoming Servlet 3 specification which allow servlets and filters to be added via web.xml fragments, and via annotations. It will also allows you to add Servlet and Filter instances programmatically. I expect that Impala will be able to take advantage of this mechanism when it becomes available, perhaps by wrapping the Servlet or Filter to ensure that it is associated with the originating module's class loader, and not the web application class loader. This will have the advantage of allowing Impala to make use of the web container's invocation infrastructure while still supporting dynamic servlet or filter registration.