Spring Context Mix-Ups

While trying to add caching to a bean in my client’s project, I ran into some strange behaviour. The project already used caching on several components and used the @Cacheable annotation with an EhCache backing store. I added a cache definition to the ehcache.xml file and put the @Cacheable annotation on the method, recompiled, tested… No caching.

Update 2015-01-26: I added a little trick to mitigate this situation if you run into it. See below for the fix.

Confused, I cleaned, recompiled again, restarted, tested. Still no caching. My first instinct was: maybe caching is improperly configured and the other beans also have no active caching, even though we think they do. So I started debugging, to see if the calls to the other beans did use caching. To my surprise, they did. Refreshing the page did not cause those methods to be called again, but mine were.

Some further debugging showed that the SpringCacheAnnotationParser did process my bean and was able to see the @Cacheable annotation. However, when debugging the method that was supposed to be cached, I noticed there were no references to any CacheInterceptor instances in the stack trace. Even though during startup my bean was replaced by a generated proxy.

This raised a suspicion that maybe I was looking at two instances of my bean. A breakpoint on my bean’s constructor revealed that indeed, it was called twice. The cause became pretty obvious when I examined the Spring configuration files:

applicationContext.xml

<beans ...>
  ...
  <context:component-scan base-package="com.our.app"/>
  ...
</beans>
servlet-context.xml

<beans ...>
  ...
  <context:component-scan base-package="com.our.app"/>
  ...
</beans>

Aha! It appears our Spring context is loading all classes annotated with @Component, @Service, etc. twice! Once on the startup of the application and again when the first request comes in for the dispatcher servlet. Now, the reason that caching worked on some, but not all beans, lied in the fact that caching was configured in the applicationContext.xml file, which applied caching wrappers to all beans in that context. There was no caching configured in servlet-context.xml, causing beans loaded there to not have caching wrappers.

Our Java EE Servlet Filters were loaded from the application-context.xml, which contained caching. Those were fine. But any requests coming from the dispatcher servlet would reach beans in the servlet-context.xml context, which did not have caching.

The solution was quite a lot of work, since we had to re-evaluate all annotated classes and decide whether they should live in the application context, or the dispatcher servlet context. The rule of thumb we used here was:

Classes annotated with @Component and @Service will be loaded in the application context. Classes annotated with @Controller and its derivatives will be loaded in the dispatcher servlet context.

I realize there may be more subtle cases where this rule does not fully apply, but it’s a good starting point. Generally you want any potentially shared beans in the application context and anything specifically tied to the dispatcher servlet in its context. At least take this advice to heart:

Never, ever use component-scan on the same package tree from different contexts

Update 2015-01-26: If you have this same problem and are unable to move your controllers to a separate package tree, you can use a little configuration option of Spring’s component scan. You can use include and exclude filters to filter the @Controller annotations out of the application context and only include them in the servlet context. The snippet below filters out the controllers, you should use this in you application context:

<beans ...>
  ...
  <context:component-scan base-package="com.our.app">
    <:context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  </context:component-scan>
  ...
</beans>

The same with annotations:

@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)})
@Configuration
public class MyConfiguration {}

Then reverse the filter on the servlet-config and you have separated your stereotypes. Note that I believe this is more of a hack than a sound application architecture, but in legacy applications you may not have much of a choice…

–JH

PS: This post talks about @Cacheable, but the same behaviour might be triggered by things like @Transaction and other bean post processing features in a context.

Connecting JBoss instances through JNDI

So here I was, cleanly splitting out the service EJB and web front of an application. We even went so far as to have the two components run in separate JBoss instances, on separate machines. But… they had to communicate to each other through a JNDI lookup. That’s where we ran into a ditch, fought with Java and JBoss settings for a few days and came out victorious. Let me help you stay out of these trenches and show how to configure this.

Continue reading

Configure JBoss WS on a multiple network interfaces

The JBoss WebServices package is a nice library to get your webservice kickstarted in no-time. One of its features is the automatic generation of a WSDL for your webservice endpoint. There is however a slight annoyance when you try to use this on a machine with two network interfaces.

On a single interface machine, JBoss automatically fills in the IP address or hostname of that interface in the <soap:address/> WSDL entry. No problems there. But, if you have a machine with two interfaces, for example one for internal and one for external access, then JBoss is likely to screw things up.

This is due to the following configuration directive in the jbossas/server/production/deploy/jbossws.sar/jbossws.beans/META-INF/jboss-beans.xml:

<property name="webServiceHost">${jboss.bind.address}</property>

This property causes JBoss to use the bind address in the WSDL rewriting/generation. Even if you start the server with -b 0.0.0.0, which binds it to all interfaces, JBoss still selects a single interface to use in this property.

The solution to this is luckily very simple: if this property is removed from the configuration file, JBoss will rewrite the WSDL with the address of the interface on which the request came in.

It does make me wonder, why is this not the default setting? Would it not be easier to drop in a server anywhere and it automatically exposes correct WSDL files on all interfaces? Then, if you want to restrict it to a single interface, add the property shown above.

SpringSource Application Platform – My Holy Grail

The SpringSource Application Platform has been in beta for some time now. In my rare free time I have been playing with it’s amazing set of features. Now that the platform is nearing its final release I want to share some of my thoughts about it.

I have been a fan of modular design even before I switched to my first Object Oriented Language. Although languages like Visual Basic, C++ and Java provide you with the means of building modular software, none ever enforce it. No matter how strict I design modules in my application, they somehow always get tangled up in each other.

Continue reading

SpringSource Application Platform

As SpringSource released its first beta version of the SpringSource Application Platform (S2AP), my attention was jerked towards it. In order to get to know more about this new project from Spring I attended a webinar last week. The platform looks very promising in terms of used technologies and the features it offers.

So what is S2AP?

The S2AP is the Spring Dynamic Modules Kernel, running on top of Equinox, hosting a Tomcat server, with a specialized management interface, with some funky new advantages. So you get a Java EE application server with OSGi dynamic modules and all the power of the Spring Framework. Awesome!

The platform aims at being a lightweight, customizable Java EE Server, with a preference for Spring-oriented applications. The platform has no trouble running applications that were not built with Spring technologies though, it accepts standard Java EE WAR-files and also standard OSGi bundles.

Continue reading