Aspects of Spring on a monolithic codebase

September 18th, 2007 by Oscar Huseyin

I remember reading about Spring two years ago, and although Dependency Injection has been in my bag-of-tricks for a while now, l was excited about the semantics Spring provided when defining Java beans. It was simple, a few XML files scattered with a number of beans, and you were well on your way to making your application more testable, configurable and all the other wonderful things that using Spring provides.

Id been using it for about a year on small to medium sized projects with lots of success. Then came the monolith. I joined a large scale internet banking project which made such heavy use of Spring that the Application Context files had become a large aspect of the system. Sure, each component of the system was Spring wired to provide all the benefits of using DI, but overall, as each component depended on another, the Spring aspect became more and more pervasive. This made life very difficult for a lot of developers on the team. Let me explain why in a little more detail.

Each project in the Eclipse workspace was, loosely speaking, a component in the application. Typically, each project exposed some beans for other projects to consume. Each project had, on average, 5 spring XML files which defined the beans implemented in the component (project). If you wanted to use another bean from another project, you would; (a) add the project as a dependency in the ivy.xml file (we used Ivy as the dependency management tool), (b) import the specific spring application context xml files from the project you just added to the ivy.xml file and (c) wire up the imported bean to your component. Simple right?

Well, let me tell you, it wasn’t. The best way to describe this pattern is by giving an example of something thats familiar to all Java developers; JAR files. A single JAR file contains many classes. When you need a class or set of classes from a library, do you unzip the JAR and import a single class file into your project? The answer to this question (for all those Java newbies out there) is NO. You import the whole JAR and use what you need. What we were effectively doing was exactly that; picking a spring XML file(s) from a JAR file and importing only the ones we selected; trying to ignore all the other spring xml files in the library. As you can imagine, trying to determine the dependency of the spring file (even within the same JAR) is very difficult and error prone, especially when there is a complex dependency relationships in the bean definitions. This was a monolithic abstraction leakage; a leakage comparable to the Great Mississippi Flood of 1927.

After some time thinking about the problem, l realised that the answer to the problem was in the fundamentals of Object Oriented Principles; Abstraction. The solution turned out to be very simple. Each project was to present a single set of standard spring application contexts to the bean factory for loading. I named these standard files the “Public Interface Context”.

The solution was to create two files, the componets.xml and resources.xml files. The components.xml file contained all spring beans that are loosely defined as components of the project, e.g. services, helpers, processors etc. The resources.xml file contained beans for resource related objects, e.g. Hibernate Session Factories, JMS Connection Factories etc. Each of the projects that compiled to a JAR must have a /META-INF/components directory where the public interface context files are to be saved. These public interface context files imported referenced all the other spring xml files in the project; this time, through the public interface context xml files.

After the magic of Ivy, when all EAR’s are build, all the assembled JAR’s contain the public interface contexts are saved and available for import in a standard location: META-INF/components . Therefore, when constructing your bean factory, the application contexts are loaded like:

pubic class FooSingleton {
    private XmlBeanFactory beanFactory = null;
    private FooSingleton() {
        Enumeration compCtxtCfg =
            getClass().getClassLoader().getResources("META-INF/components/components.xml");

        Enumeration resrcCtxCfg =
            getClass().getClassLoader().getResources("META-INF/components/resources.xml");
            /* Loop through all the spring xml files and load bean factory. */

          }
}

Now, once you have build all your EAR’s, WAR’s and JAR’s, your application classapath will determine which spring application contexts will be loaded! The elegance of abstraction.

Lesson learned: Always question patterns that seem overly complicated and cumbersome.

One Response to “Aspects of Spring on a monolithic codebase”

  1. odecee blogs » Blog Archive » Is Spring only useful for Unit Testing? Says:

    [...] messy; so much so that it can become a real development impedance. How is this possible? Read my Aspects of Spring on a Monolithic Codebase blog; it sums up my growing [...]

Leave a Reply