Thursday, December 29, 2011

Accessing Spring beans from Legacy code

As I have blogged before, we have been trying to move to using the Spring framework in our web applications. We inherited a large body of working code which used a home-grown framework based on a combination of what Martin Fowler describes as the "JSP as Handler" web presentation pattern in his Enterprise Application Architecture book and Webwork action controllers. Our rationale for introducing Spring into this application is that maintenance and enhancement are very difficult and time-consuming with the existing architecture.
However, the conversion is not going to happen overnight, and neither can we mandate that all new development should stop as we move to the new architecture. It is also not possible to build and deploy the new functionality in separate web applications, because we don't have the resources to handle the deployment issues that such an approach would require. So our new Spring enabled code co-exists with the legacy code in the same web application.
One by-product of this setup is that we often end up developing non-GUI components using Spring, which need to be hooked into existing legacy code so we can reuse the legacy request flow. There are three ways we could do this:
  • Build the Spring bean manually in our legacy code using explict constructor and setter calls.
  • Scrap the legacy request flow and rebuild it using Spring.
  • Obtain a reference to the Spring bean that has been configured and built declaratively by the Spring container from the legacy code.
The first approach is feasible, but it is extra code that you don't need to write. Also, the first approach may result in strange null pointer exceptions if you missed something. It is also less efficient to construct them each time than having it be built once by Spring. The second approach is good if your long term goal is to get rid of the existing architecture altogether, but it is even more risky than the first approach because new code will generally contain new bugs. Also, because writing code takes time, you will have to build this extra time into your estimates. In my opinion, the last approach takes the minimum effort, code and poses the least risk, and can be accomplished quite simply, as I show below.
Our approach is to build a Singleton bean which is ApplicationContextAware and instantiate it in the Spring container by defining it in the spring-servlet.xml file in our web application. Because it is ApplicationContextAware, Spring would populate it with a reference to the ApplicationContext. Since we just want references to Spring beans from it, we implement a static getBean() method which would delegate to the ApplicationContext.getBean() method. Here is the code for our Singleton. The bean definition for this bean is just this one line: In order to now get a reference to a bean named "mySpringBean" that has been defined in the Spring context, we will issue from somewhere in our legacy (non Spring-enabled) code: The only caveat is that your DispatcherServlet must be loaded in web.xml before any component that needs to call the SpringApplicationContext.getBean(). This ensures that the ApplicationContext has finished loading and SpringApplicationContext has a populated reference to it. This is the second time I had a need for this kind of bridge. The last time was at my previous employer where we were embedding Jive Forums software within our Spring enabled web application. We used the standard approach there, using the Spring ContextListener to store the ApplicationContext in the ServletContext, and then calling WebApplicationContextUtils.getApplicationContext(ServletContext) to get at the Spring context. I believe the approach I have outlined is better, since it is less code and there does not have to be a web container for this functionality to be available.

http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html

No comments:

Post a Comment