Blogs

SpringSource Blog

Using a shared parent application context in a multi-war Spring application

Joris Kuipers

Last month I gave a Core Spring training in Turkey. At the end of the course I discussed the architecture for an application that some of the participants were going to build after completing the course. This application would consist of an ear file with several war files inside, and the question came up if it was possible to define a single ApplicationContext that could be used as a shared parent to the WebApplicationContexts of all war files. This context would hold bean definitions for services, DAOs and other beans that were not specific to a single web module.

Actually, Spring makes it very easy to do this, but neither the course nor the reference manual explain in detail how to use this feature from your web application. I therefore wrote a short sample app that illustrates how this works, which I will discuss here in my first blog entry.

The ContextLoader and SingletonBeanFactoryLocator classes

In a typical Spring web application, you use a ContextLoaderListener (or, if you're using a Servlet 2.2 / 2.3 container, a ContextLoaderServlet) to bootstrap a WebApplicationContext. You configure the ContextLoader used by this class through context parameters in your web.xml. If you've used this, you're probably familiar with the contextConfigLocation parameter, that let's you specify which files make up the WebApplicationContext to construct.

As it turns out, there is another parameter that you can use to get the desired functionality in a declaritive fashion: parentContextKey. Using this, you instruct the ContextLoader to use another class called ContextSingletonBeanFactoryLocator to search for a bean named by the value of parentContextKey, defined in a configuration file whose name matches a certain pattern. By default, this pattern is 'classpath*:beanRefContext.xml', meaning all files called beanRefContext on the classpath. (For a plain SingletonBeanFactoryLocator it's 'classpath*:beanRefFactory.xml')
This bean must be an ApplicationContext itself, and this context will become the parent context for the WebApplicationContext created by the ContextLoader. However, if this context already exists then that one will be used and no new context will be created (hence the name SingletonBeanFactoryLocator).

Let's see what this means: first, we need a separate jar in our ear that holds the code for the services, DAOs, etc. Inside this jar we place a beanRefContext.xml file that holds a single bean-definition for an ApplicationContext. Typically, this will be a ClassPathXmlApplicationContext. Then that bean definition will refer to one or more 'regular' bean configuration files that contain the service beans and other stuff to be used by the code from your war files; something like this:

<!-- contents of beanRefContext.xml:
       notice that the bean id is the value specified by the parentContextKey param -->
<bean id="ear.context" class="org.springframework.context.support.ClassPathXmlApplicationContext">
    <constructor-arg>
        <list>
            <value>services-context.xml</value>
        </list>
    </constructor-arg>
</bean>

Finally, we need to make this jar available on the classpath of the war files using the Class-Path entry in the MANIFEST.MF file of each war.

Why would you want to use this?

A simpler solution is to skip the parentContextKey and to load the shared bean definition files from each war using the contextConfigLocation parameter. This way, each war will have its own instance of each shared bean. For simple stateless beans, such as typical services, this is actually a fine solution.

However, instantiating a new instance of each shared bean for each war can have several drawbacks: a common example is creating a Hibernate SessionFactory. This is often an expensive process, so to prevent your startup time getting out of hand the described solution will ensure that this is done only once. Another advantage of having a single instance of your SessionFactory is that it can safely act as a second level cache: you don't want multiple copies of that hanging around in a single application!
In general, if you have stateful beans that should really be used as a singleton (in the Spring sense, i.e. one instance per application as opposed to per JVM) you should define them in a single context accessed by the other contexts.

The sample

I've included the sample, both as an ear file and as source. In order to upload the ear, I had to give it a .zip extension: please rename the file to .ear before deploying it!. The source is actually an Eclipse workspace, so you can easily import and review it (it requires WTP and is configured for Spring IDE). All Spring jars needed are included. After you've deployed the app, go to the URLs /web1 and /web2 to see the output of a servlet in the first and the second war file. The toString() of the service will prove that the wars really use the same instance of the shared service.

More info

The best info on this feature is in Spring's excellent API documentation: have a look at the JavaDoc for the ContextLoader.loadParentContext method and the SingletonBeanFactoryLocator class. These docs contain further info on how to configure your web.xml and how to write the beanRefFactory.xml.

Similar Posts

Share this Post
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Slashdot
  • Technorati
  • TwitThis
 

99 responses


  1. Nice entry. I wondered about this, but never actually looked it up.


  2. I'm wondering how session-scoped beans would fit into this scenario. Since the shared context is not a web context, I assume that you can't use session-scoped beans there. Right?


  3. [quote comment="26827"]I'm wondering how session-scoped beans would fit into this scenario. Since the shared context is not a web context, I assume that you can't use session-scoped beans there. Right?[/quote]
    Right; even if you would make the shared context a WebApplicationContext somehow, it still wouldn't make any sense: the Session is scoped to the ServletContext (which corresponds to a war file), so I'd say that session scope is meaningless outside the web application context of the war itself.
    That doesn't prevent you to place shared session-scoped bean definitions inside a single configuration file, of course: it only means that this file should be used to construct the WebApplicationContexts of each war by adding it to the list of files in the contextConfigLocation parameter in each war's web.xml. Still DRY, but these beans will not become part of the shared parent context.


  4. "Instantiating a new instance of each shared bean for each war can have several drawbacks…"

    Maybe so, but it also has one distinct advantage: predicatable, repeatable behaviour.

    Maybe the implementation of ContextSingletonBeanFactoryLocator has been overhauled in Spring 2.0, but if not, I would strongly discourage its use unless you really know what you are doing.

    When I used ContextSingletonBeanFactoryLocator, it operated very much at the mercy of the Classloader implementation of my server environment. When the classloader implementation was flaky, you ended up with singletons-that-are-not-really-singletons. For stateful components, this means that predicting the result of a method call has all the surprise and adventure of unwrapping a present on Christmas morning.


  5. [quote comment=\"26846\"]When the classloader implementation was flaky, you ended up with singletons-that-are-not-really-singletons.[/quote]
    Absolutely, but with flaky classloaders that would also be the case if you implemented your own singleton, right?
    In the setup that I described (multiple wars and a jar in the root of the ear, referenced from the Class-Path entry in the MANIFEST.MF as opposed to placed in WEB-INF/lib), most if not all containers will by default create a ClassLoader per war and a parent ClassLoader for the jar(s). This ensures that the wars can't see each other's classes and that the jar can't see the wars. Thus, the singleton beans will be loaded by that parent CL. I've never experienced problems with this setup myself, but I can imagine other scenario's, like using the (Context)SingletonBeanFactoryLocator programatically without having a parent CL in place, that can lead to the problems you descibe (there's actually a warning in the JavaDoc of the BeanFactoryLocator about this sort of usage).
    So I agree that a SingletonBeanFactoryLocator should only be used (a) if really needed and (b) if you understand how it interacts with your server environment. Then again, I feel the same about most technologies :)


  6. Very, very interesting article. In fact, that's exactely what I was looking for for months ! And, as always with Spring, there's a simple and staightforward solution :-)

    Thanks !

    Benoit.


  7. Also good to make clear, the ContextLoader uses the ContextSingletonBeanFactoryLocator not the SingletonBeanFactoryLocator and in the JavaDoc for the former, it specifically says: "It is not possible nor legal to share definitions with SingletonBeanFactoryLocator". So if other components of your system are using that Locator (for instance a JbossAcegiLoginModule) you might end up creating 2 copies of every bean anyways.


  8. If you are not in an EJB container, but only use a servlet container, you have to deploy your classes for the global application context also into a global class loader, don't you? This gets a lot of stuff if you think of the domain model which you need for the mentioned SessionFactory.

    My use case would be a portal web app a portlet web app which I have running both on plain Tomcat only, but I need to integrate them somehow: http://www.liferay.com/web/guest/devzone/forums/message_boards/message/35365. With the global context I'd need to deploy everything of the portlet web app except the MVC stuff to Tomcat's common class loader (common/lib, http://tomcat.apache.org/tomcat-5.5-doc/class-loader-howto.html). At some point you maybe have to switch to an EJB container – and if it's only for the class loader/ deployment stuff.

    Joerg


  9. Hi Joris,

    Did you remember me? I'm one of guys who gave Spring course in Turkey… Thanks for your reply. We're gonna use the solution you suggest.

    Burak ARIK


  10. [quote comment="31619"]
    Did you remember me? I'm one of guys who gave Spring course in Turkey… Thanks for your reply. We're gonna use the solution you suggest.[/quote]
    Hi,

    yes, sure I remember you. I hope you'll have a successful project and that you can apply what you've learned!

    Joris


  11. Hello,

    nice approach to share a context across multiple web apps. One problem occurs for me: If I put jars into my EAR file and insert them into the MANIFEST.MF they are not found.

    Manifest-Version: 1.0
    Ant-Version: Apache Ant 1.6.5
    Created-By: 1.5.0_11-b03 (Sun Microsystems Inc.)
    Class-Path: ojdbc14.jar

    For me it is "ClassNotFoundException: oracle.jdbc.driver.OracleDriver" when initializing the EAR parent application context. Is there a possibility to tell Spring to use the classpath as mentioned in MANIFEST.MF?


  12. I think I misunderstood something about your approach. What I did was putting my shared classes into a seperate jar file and provide it via Tomcat's shared lib folder. Then I assumed another webapp should have access to the jar and load its context as parent. While the parent context was initialized, I got the ClassNotFoundExceptions as described above.

    Is there no way to do it the way I described here? I do not want to use an application server hence I do want to avoid EAR-files.


  13. [quote comment="32368"]I think I misunderstood something about your approach. What I did was putting my shared classes into a seperate jar file and provide it via Tomcat's shared lib folder. Then I assumed another webapp should have access to the jar and load its context as parent. While the parent context was initialized, I got the ClassNotFoundExceptions as described above.

    Is there no way to do it the way I described here? I do not want to use an application server hence I do want to avoid EAR-files.[/quote]
    You have indeed misunderstood my original description, since it only descibes a solution for ear-files with multiple war-files inside.
    However, what you want is certainly possible: I've just tried it out, and it works perfectly. Just make sure that not only the shared parent jar is placed inside the shared/lib directory, but also the the spring jar that holds the ContextSingletonBeanFactoryLocator class (and other jars that your application might need). This way, there can be an actual singleton in the shared classloader visible to both web applications that each have their own classloader.

    This should work using my original example:
    - download the multiple-contexts-sample.zip linked to from the blog entry
    - put all jars from that zip in Tomcat's shared/lib folder
    - (re)start Tomcar
    - deploy the 2 war-files from that zip under /web1 and /web2
    - go to http://localhost:8080/web1 and …/web2 and ensure that the same instance of the shared service is now used (refresh a couple of times to see the shared counter being incremented)

    I guess this also answers Jörg's question. BTW, don't use the common dir, use the shared dir: the common is for libraries that should also be seen by Tomcat itself, these jars are loaded by a parent classloader of the shared classloader. The classes in the shared classloader are only visible to deployed applications, which is exactly what we want in this case.


  14. I put the all spring applicaitonContext.xml to myapp.ear/APP-INF/classes


  15. Hello,

    I deployed the .ear file on WebLogic server 9.2, and the sample code doesn't work: each Webapp has its own instance of the service bean.

    Is this problem known with other application servers?

    Thanks,

    Dimitri


  16. [quote comment="45676"]
    I deployed the .ear file on WebLogic server 9.2, and the sample code doesn't work: each Webapp has its own instance of the service bean.
    [/quote]

    That's because WebLogic by default doesn't put regular jar files from the root of the ear in a parent classloader like with EJB jars, but in the classloader of the WARs. See http://edocs.bea.com/wls/docs92/programming/classloading.html for more info and possible solutions. In your case, moving al jars from the root of the ear in /APP-INF/lib seems like the easiest solution.


  17. Hello,

    Indeed, moving all utility .jar files from the root to /APP-INF/lib is the solution.

    So, not only the SampleJava.jar file, but also spring-*.jar.

    Thank you for the tip! :-)


  18. Unfortunately, similar mechanism is missing for EJBs in current ContextJndiBeanFactoryLocator implementation. It would be nice if it can take also "parentContextKey" parameter similar to org.springframework.web.context.ContextLoaderListener to have one shared root context among EJB JARs as well as WARs.


  19. Hi People,
    Can anyone advise me on the following issue. I trying to define seperate context names using the same .war file.

    For example: I have a war file abc.war and I want to configure it so that it can be accessed using http://localhost/abc1 and http://localhost/abc2. Is it possible with tomcat and if so what will I have to do to achieve it?

    Thank you.
    -jee


  20. [quote post="184"]I trying to define seperate context names using the same .war file.[/quote]
    This blog entry has nothing to do with that. Please use this page only for relevant comments or questions. For non-related questions, consult a forum or read some documentation. You could start here: http://en.wikipedia.org/wiki/Rewrite_engine


  21. Indeed Joris, this is not related. But I thought it is some what related and after reading this block I felt it could be valuable to get your input on that.


  22. Thanks for the great article and example. It works very well.

    One problem we are having is that we dynamically load our application context, selecting the configuration files in Java. This also works well, but we how can we connect the two approaches? We created a custom listener and loader for a web application that creates and loads the context. As a result, it is not defined as a Spring bean in a configuration file. We would now like our dynamically created context to become the parent context for other web modules. Is there some way that we can "name" this context so that we can reference it in the web.xml of other web modules? I searched for a solution, but didn't find anything. Here is our custom ContextLoader code:

    public class JeeContextLoader extends ContextLoader {
    protected ApplicationContext loadParentContext(ServletContext servletContext) throws BeansException {
    String moduleReferences = servletContext.getInitParameter("ModuleReferences") ;
    if ( moduleReferences == null ) {
    System.out.println("ModuleReferences is null");
    } else {
    System.out.println("ModuleReferences:" moduleReferences);
    }
    BootStrapper bootStrapper = new BootStrapper() ;
    bootStrapper.setModuleReferences(moduleReferences);
    Globals.Init(bootStrapper, FactoryInitAction.StartFactory);
    ApplicationContext parentContext = Globals.getFactory() ;
    return parentContext;}}


  23. [quote comment="56980"]One problem we are having is that we dynamically load our application context, selecting the configuration files in Java. This also works well, but we how can we connect the two approaches? We created a custom listener and loader for a web application that creates and loads the context. As a result, it is not defined as a Spring bean in a configuration file. We would now like our dynamically created context to become the parent context for other web modules. Is there some way that we can "name" this context so that we can reference it in the web.xml of other web modules? [/quote]

    Since you've already created your own ContextLoader and have overridden the loadParentContext method, why would you still want to name that root context? That name is normally only used by the default loadParentContext method, since it delegates to a ContextSingletonBeanFactoryLocator and looks up the context named by the parentContextKey parameter. You're not using that in your ContextLoader implementation…

    In your case, I'd say that all you need is to instruct the ContextLoaderListener to use your JeeContextLoader instead of the default ContextLoader. To do that, all you need to do is to subclass ContextLoaderListener, override createContextLoader to create a JeeContextLoader and register that subclass as a listener in your web.xml. You mentioned that you have also created a custom listener already, so I'm not sure if I fully understand your problem: if your code always returns the same ApplicationContext when the same ModuleReferences value is passed to it, then it looks like you have already created a working solution… The code that does this isn't too clear, however.


  24. Thanks Joris, for your help. We are basically trying to do what you have done in your sample application without defining the application context in a Spring xml configuration file. We are doing this to support dynamic configuration for testing, shared Acegi security accross WARs, etc. Our same bootstrapper works for everything.

    You were right in that we already had a solution. I just needed to add the functionality in our custom loader to point to a parent context, and it worked. I copied the following code right out of the Spring context loader.

    BeanFactoryLocator bfLocator = ContextSingletonBeanFactoryLocator.getInstance();
    BeanFactoryReference bfReference = bfLocator.useBeanFactory(parentContextKey);
    parentContext = (ApplicationContext) bfReference.getFactory();


  25. Actually, this did not solve my problem. I apologize for the premature response. I still can't get my programmatically created ApplicationContext to have a beanId that I can reference (as a parentContextKey) from other parts of my EAR.


  26. [quote comment="57175"]Actually, this did not solve my problem. I apologize for the premature response. I still can't get my programmatically created ApplicationContext to have a beanId that I can reference (as a parentContextKey) from other parts of my EAR.[/quote]
    That's not how it works: if you use your JeeContextLoader, it will just ignore the parentContextKey since you've overridden the loadParentContext method to create the parent context in a different way. I didn't understand your previous post, but given that it doesn't work that probably makes sense ;)
    What you need to do is to create a singleton (in the GoF sense) that holds the parent ApplicationContext that you then return from the loadParentContext method. Also, make sure that all your WAR files use your JeeContextLoader and not the default ContextLoader.


  27. [quote post="184"]What you need to do is to create a singleton (in the GoF sense) that holds the parent ApplicationContext that you then return from the loadParentContext method. Also, make sure that all your WAR files use your JeeContextLoader and not the default ContextLoader. [/quote]

    Thank you! This worked perfectly.


  28. I have a client with the following issue…. They have a baseline non-branded WAR that works for most of their clients. However some clients (lets call them partners) are more demanding and would like something more configurable. My idea is to have a thin set of overriding/extension code for just the changes that are necessary for each partner. That partner override code will be in a separate WAR so that it can be tested and deployed separately. By using your solution I can have the child context replace the bean definitions for the parent context thereby injecting the partner code instead of the baseline code with no effect on the baseline. Is this correct? Is this the most effective way to gain this flexibility? Thanks.


  29. [quote comment=\\\"59619\\\"]… That partner override code will be in a separate WAR so that it can be tested and deployed separately. By using your solution I can have the child context replace the bean definitions for the parent context thereby injecting the partner code instead of the baseline code with no effect on the baseline. Is this correct? Is this the most effective way to gain this flexibility?[/quote]Do you mean that the partners will use both the base WAR and a seperate WAR, or that the seperate WAR will contain the base plus overriding/extension code? In the last case, you don\'t need multiple contexts: you can simply override base bean definitions by adding extra configuration files to the list of files that make up the application context. Wildcarding would work here probably, maybe something like this as the context-param value in your web.xml:
    classpath*:*-context.xml,classpath*:*-override.xml

    I didn\'t try this, but it seems like this would enable you to simply put the extra code under /WEB-INF/lib or /WEB-INF/classes in the base WAR and create one or more extra configuration files called something-override.xml that you also place on the classpath, which can then override existing base bean definitions.

    If you meant using multiple WAR files then I\'m not really getting your deployment scheme here: how would deploying an extra WAR file change the behavior of an already deployed base WAR file? My sample only talks about a shared parent context for multiple WAR files in a single EAR file: the base WAR file presumably doesn\'t use a parent context for the context created by the ContextLoaderListener.


  30. Thanks for the quick response. Sorry it took a few days to get back. You actually bring up a separate point. I am trying to keep the WARs separate, but I don't know if I can.

    Option 1: Keeping the WARs separate… This may not be possible because they are using Struts with JSP and Velocity. I am in the process of researching online if those files will be accessible in a separate WAR. In this case, I believe you are saying the parent context is the way to go.

    Option 2: Merging the baseline and override… So are you saying that if the override defines a bean later in the initialization than the baseline it will replace the bean that was originally defined with that id? If so, that's much easier, but I couldn't see that documented anywhere. For some reason, I was thinking it might output a BeanAlreadyDefinedException (or something of the sort).


  31. [quote comment="60928"]… So are you saying that if the override defines a bean later in the initialization than the baseline it will replace the bean that was originally defined with that id?[/quote]
    Yes, Spring has no problem with multiple bean definitions with the same id, as long as they're not in the same file. This definitely seems like the easiest thing to do, and is supported just for this use case. The latest bean definition that's loaded simply 'wins' and masks other definitions with the same id.


  32. Hi,

    many thanks for the very useful article. Like Dimitri Hautot, I've been trying this on WebLogic 9 and it works well. There's a slight difference in what I'm doing in that I want a bean at the managed server (i.e. JVM) level but that works fine with the bean code and required Spring jars at the server level (versus app-inf/lib at the ear level).

    However, most of my web apps run with the WebLogic prefer-web-inf-classes setting changed to true (i.e. look first for code in the web app's web-inf/lib rather than first looking in the higher classloaders). When I turn this on, I get two instances of the SampleService class. I _think_ I understand why – the ContextSingletonBeanFactoryLocator is running from the web app's classloader and, although the SimpleService class is created by the server level classloader (it is not deployed to web-inf/lib), the ContextSingletonBeanFactoryLocator in each web app know nothing about the ApplicationContexts each other have created.

    Does the above sound right? If so, do you know if there is an easy way round this i.e. so I can continue to run with prefer-web-inf-classes but am still able to pull in a single instance of an ApplicationContext created in a higher classloader as a parent into different web app's ApplicationContexts.

    Thanks in advance if you have any pointers. I realise what I'm trying to do might sound strange i.e. turn on prefer-web-inf-classes to increase segregation between web apps while then wanting to also also put something on the server classpath but I would claim to have a valid use case for this!


  33. [quote comment="75127"]…
    Does the above sound right? If so, do you know if there is an easy way round this i.e. so I can continue to run with prefer-web-inf-classes but am still able to pull in a single instance of an ApplicationContext created in a higher classloader as a parent into different web app's ApplicationContexts.

    Thanks in advance if you have any pointers. I realise what I'm trying to do might sound strange i.e. turn on prefer-web-inf-classes to increase segregation between web apps while then wanting to also also put something on the server classpath but I would claim to have a valid use case for this![/quote]

    I'd say that you only have to move the spring.jar out of WEB-INF/lib: if you want to share the ApplicationContext through a singleton, then that's required. The rest of your code can probably stay in WEB-INF/lib. The reason that I say 'probably' is that code that's in a higher classloader that needs to access classes loaded by the web classloader will need to properly use the context classloader in that case.

    Maybe you should go for another solution instead, for instance registering your shared ApplicationContext in the JNDI registry and perform a lookup from the WAR. You'd need to ensure that the shared context would have been created and registered before the lookup occurs, of course.


  34. Hi Joris,

    thanks for the ultra speedy response! I am a little reluctant to change the existing web apps to move out the spring jar to the higher classloader. So I guess I'll need to think about alternative solutions – sharing an application context via JNDI sounds like fun to try!

    Thanks again – appreciated.


  35. Just a note to everyone out there who is using Weblogic, ehcache (in a parent context) and multiple wars:

    There are some problems with parent context distributed caching in Weblogic (see the below stacktrace). To get around this, make sure you have the ehcache included in your web application's pom file/classpath (as opposed to the ear classpath) so that it can be referenced by the classloader.

    2007-12-04 09:12:16,549 WARN – Unable to send message to remote peer. Message was: RemoteException occurred in server thread; nested exception is:
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
    java.lang.ClassNotFoundException: net.sf.ehcache.distribution.EventMessage (no security manager: RMI class loader disabled)
    java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
    java.lang.ClassNotFoundException: net.sf.ehcache.distribution.EventMessage (no security manager: RMI class loader disabled)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:325)
    at sun.rmi.transport.Transport$1.run(Transport.java:153)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:149)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:466)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:707)
    at java.lang.Thread.run(Thread.java:595)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:247)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:223)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:126)
    at net.sf.ehcache.distribution.RMICachePeer_Stub.send(Unknown Source)
    at net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator.flushReplicationQueue(RMIAsynchronousCacheReplicator.java:313)
    at net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator.replicationThreadMain(RMIAsynchronousCacheReplicator.java:122)
    at net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator.access$100(RMIAsynchronousCacheReplicator.java:55)
    at net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator$ReplicationThread.run(RMIAsynchronousCacheReplicator.java:372)
    Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
    java.lang.ClassNotFoundException: net.sf.ehcache.distribution.EventMessage (no security manager: RMI class loader disabled)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:285)
    at sun.rmi.transport.Transport$1.run(Transport.java:153)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:149)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:466)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:707)
    at java.lang.Thread.run(Thread.java:595)
    Caused by: java.lang.ClassNotFoundException: net.sf.ehcache.distribution.EventMessage (no security manager: RMI class loader disabled)
    at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:371)
    at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:165)
    at java.rmi.server.RMIClassLoader$2.loadClass(RMIClassLoader.java:620)
    at java.rmi.server.RMIClassLoader.loadClass(RMIClassLoader.java:247)
    at sun.rmi.server.MarshalInputStream.resolveClass(MarshalInputStream.java:197)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1544)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1699)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
    at java.util.ArrayList.readObject(ArrayList.java:591)
    at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:946)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1809)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1719)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
    at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:290)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:279)
    … 6 more


  36. Joris,

    I'm using the shared context approach not for sharing my context between wars but between my war module and my ejb module.
    More specifically I have one EAR with one ejb-jar module and one war module.
    My EJBs (MDB's and SLSBs) extend from Spring's convenience classes and call as described in multiple threads on the web the setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance("classpath*:**/beanRefContext.xml")); and setBeanFactoryLocatorKey("service"); methods.
    In my web.xml I have the correspondig parentContextKey and the locatorFactorySelector entries.

    Everything works greath … except in one scenario … when I deploy/(re)start my EAR when there are messages on the queue. In this situation I'm running into the problem that the container preloads the MDB and calls the setMessageDrivenContext method in which the above method calls occur. Of course, at that point in time my web module is not started yet and therefore the shared application context is not loaded/initialized yet.
    As a result I get a spring exception and my application doesn't start.

    Is there a way to get around this problem ? For example, can I initialize the context from within my ejb and "make it available" to my web module, or could deploying a spring context as a JCA adapter help ?

    Any help, advise, workarounds would be appreciated because I'm really stuck.

    Kind regards,

    EDH


  37. [quote comment="85032"]when I deploy/(re)start my EAR when there are messages on the queue. In this situation I'm running into the problem that the container preloads the MDB and calls the setMessageDrivenContext method in which the above method calls occur. Of course, at that point in time my web module is not started yet and therefore the shared application context is not loaded/initialized yet.
    As a result I get a spring exception and my application doesn't start.[/quote]

    I don't think the shared context can only be created by the ContextLoader from the web module; that class has a method called loadParentContext which calls BeanFactoryLocator.useBeanFactory(parentContextKey) which triggers the creation of the shared parent context, but the AbstractEnterpriseBean.loadBeanFactory method does exactly the same thing. That method gets called from AbstractMessageDrivenBean.ejbCreate(): that should happen after the setMessageDrivenContext method gets called by the container, so the loadBeanFactory should recreate your parent context using your ContextSingletonBeanFactoryLocator and beanFactoryLocatorKey, right? So, just by looking at the code, one would expect the shared parent context to be loaded and initialized just fine, regardless of the module that starts first.

    Can you provide the exception that you receive? This might have something to do with the shared context not being properly destroyed on restart, so it doesn't get recreated when useBeanFactory gets called. It might also help to put in some trace logging in the methods involved to see what happens exactly after a restart. Also enable trace logging for the org.springframework.beans.factory loggers to see what Spring is doing!

    HTH,

    Joris


  38. Joris,

    Thanks for your quick response !

    In the meantime I also created a bug report for this: http://jira.springframework.org/browse/SPR-4301. That bug report shows the exceptions I'm getting. Now, I might have been a bit to fast to consider this a bug. From the comments on my bug report you'll see that a first problem I'll have to solve is to find out why the spring.schemas (file) is not found when the MDB gets created(preloaded) while in the normal scenario, when the web module is first loaded the schemas are found without any problem ? Do you have some advise on this perhaps ?

    Now, let's say I've solved this schema problem then what I understand from your comment is that when the MDB is created/preloaded (before the web module has started and thus before the web module's contextloader kicks in) the setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance("classpath*:**/beanRefContext.xml")) call will also lead to the creation/initialization of the shared context. Is that correct ? Is so, then what happens at the time the web module gets loaded and it's contextloader kicks in ? Will it "detect" that the shared context is already there, or will it try to re-initialize it again ?

    In either case, I'll try out your suggestions, and get back to you on this.

    Thanks,
    EDH


  39. [quote comment="85381"]…a first problem I'll have to solve is to find out why the spring.schemas (file) is not found when the MDB gets created(preloaded) while in the normal scenario, when the web module is first loaded the schemas are found without any problem ? Do you have some advise on this perhaps ?[/quote]
    Not sure: could be classloader-related, maybe? Where is your spring.jar and how do you make it available to the ejb jar? If the spring.jar is in the ear, is it also refered to in the MANIFEST.MF Class-Path entry of the ejb jar?
    [quote comment="85381"]…what I understand from your comment is that when the MDB is created/preloaded (before the web module has started and thus before the web module's contextloader kicks in) the setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance("classpath*:**/beanRefContext.xml")) call will also lead to the creation/initialization of the shared context. Is that correct ?
    [/quote]
    Almost: not the setBeanFactoryLocator call leads to creation, but the call to loadBeanFactory from the ejbCreate.
    [quote comment="85381"]If so, then what happens at the time the web module gets loaded and it's contextloader kicks in ? Will it "detect" that the shared context is already there, or will it try to re-initialize it again ?
    [/quote]
    It should detect it, since the context is already registered in a Map that's kept as a singleton (so your web module and your ejb module should use a spring.jar loaded by the same single classloader).

    Joris


  40. It looks like the default file isn't actually beanRefFactory.xml, but beanRefContext.xml. That confused me for sometime, until I looked at the source download.


  41. Very cool; I wasn't aware of this feature. Thanks for the write-up.

    It seems like one thing that may be very useful for an EAR that packages WARs is to define a single viewResolver at the EAR level that each WAR could then inherit. Though, that doesn't appear to be easily doable because the 'prefix' definition is typically scoped to the WAR:

    Any thoughts?


  42. I'd say that typically each 'module' (war file in this case) should package its own configuration for the MVC-related beans. To share something like a ViewResolver instance would indeed mean that all WARs are forced to use the exact same configuration, so it's probably counter-productive in the end.
    I've mostly used the described feature to make sure that global beans (middle-tier services, Hibernate SessionFactories, etc.) are defined only once and shared between multiple WARs. This is not only about reducing duplicated configuration, it's really about making sure that certain beans are instantiated only once and then shared.

    Note that in the case of the ViewResolver, you could still share a single config file that defines the ViewResolver bean and uses property placeholder:
    <property name="prefix" value="${view.prefix}"/>
    (hope that markup made it through the HTML filter)
    In that case, each WAR could define its own PropertyPlaceholderConfigurer to provide a unique value, but you wouldn't have to duplicate the entire bean definition for the ViewResolver across each WAR. That doesn't require a shared ApplicationContext, obviously, just a shared config file that's loaded by each ApplicationContext.


  43. (This is a reply to a comment from Bruno Sant'Anna that now seems have disappeared:)
    Does my example work for you? The errors you're showing are not coming from my sample, as that doesn't have a my.service.AccountService not an accountService property.
    It looks like a classloading issue to me: the proxy should be an instance of my.service.AccountService, but that interface (or is it a concrete class? that would explain the use of a CGLIB proxy) might be defined in multiple classloaders, thus causing the exception. It's hard to tell without further details, but you probably need to package your jars in another way to ensure the AccountService type is defined in a single classloader.


  44. Hi, Joris.

    In one of your replies, you mentioned exposing an ApplicationContext via JNDI. This is something that I'm trying to do but can't seem to find documentation on. Could you point me to links, post hints or even outline a solution outright for how this is accomplished? Is there a container-independent way of doing this? I need to expose it that way because the EJB support of Spring recommends that the Context be picked up this way (sadly they don't mention how to do the first part).


  45. If you just want to share an ApplicationContext between your EJBs and your web app, you don't have to use JNDI to store your ApplicationContext. I guess you are referring to the ContextJndiBeanFactoryLocator? That only retrieves its config file locations from JNDI to create an ApplicationContext, it doesn't retrieve the ApplicationContext itself. I find that one quite cumbersome to use.
    What I do in those cases is to use the Spring support classes for EJB, but override the setSessionContext method to call setBeanFactoryLocator with a ContextSingletonBeanFactoryLocator. This is also suggested in the JavaDocs of AbstractEnterpriseBean. This ends up working very similar to what I've described in my blog.


  46. Hi Joris,

    thanks for this interesting hint. I used this implement modules for a web app last year and this worked perfectly for me.

    But then I tried if I get my app running in a OSGI container using Spring DM. I know that OSGI now provides a better approach for modularizing an application, but I tried to do as little changes as possible for enabling OSGI.

    So I added a OSGI manifest and deployed using the spring web extender. But now I get the following error message:

    java.lang.IllegalStateException: BeanFactory not initialized or already closed – call 'refresh' before accessing beans via the ApplicationContext

    Looks like Spring DM does not allow to change the root context? Or is there a way to "refresh" the context in order to get it run?

    Thanks
    Joern


  47. Hi Joern,

    with Spring-DM this model simply doesn't make a lot of sense:
    first of all, you don't want the bundle that defines the child context to trigger the creation of the parent context, as each bundle has its own ApplicationContext. This context is created when the bundle is started by the Spring-DM extender bundle.
    Second of all, Spring-DM allows for a much more refined model than hierarchical contexts through its integration with the OSGi service registry. You're no longer confined to a tree of contexts, but each bundle can expose the beans it wants to share as an OSGi service which gives you much more flexibility.

    To adapt your application to this model does not require a lot of work and hardly any changes. For your 'parent' bundle, just define an extra Spring config file that uses Spring-DM's osgi: namespace to export the beans that should be accessible by the 'child' bundle(s) as OSGi services with <osgi:service>. For your child bundle(s), create a similar file that contains <osgi:reference> elements to create proxies that will access these services. If these references use the same ids as the exported bean definitions, you don't have to touch your existing config files: just make sure that the new files are loaded as part of the created ApplicationContext. Of course you would remove the context parameter from your web.xml that triggers the parent context loading and setting. With such a shared services war, you do need to define a custom subclass of the XmlWebApplicationContext that is OSGi-aware. Which class depends on if you just use Spring-DM or the dm Server: consult the documentation for the respective projects for details.

    I must admit that I'm not very familiar with Spring-DM's web extender, as I always use the SpringSource dm Server for OSGi-based web applications. I'm sure this approach would work with both environments, though.


  48. Hi Joris,

    thanks for your feedback. Your suggestion sounds good to me, even so I have to admit that I'm not sure if I understand all the details :)

    The point where I got lost is, how can I make an XML application context OSGI aware? And another question is, can I use this context as a local BeanFactory?

    Until today I used the getBean() method to dynamically create beans and their dependencies. Now I read that Spring DM discourages me to do so. I feel a bit lost here. How shall I create dynamic structures now? Or am I discouraged to do so either? Anyway I couldn't find an easy way to create a BeanFactory in an OSGI environment. Now I'm wondering if a custom XmlWebApplicationContext would solve this problem for me?

    I know this is not a Spring-DM blog and I'm sorry if you are the wrong person to ask :) But then perhaps you can give me pointer, where I should follow up.

    Thanks a lot
    Joern


  49. For plain Spring-DM, check here:
    http://static.springframework.org/osgi/docs/1.1.3/reference/html/web.html#web:spring-mvc

    For dm Server, check here:
    http://static.springsource.com/projects/dm-server/1.0.x/programmer-guide/html/ch05s02.html#developing-applications-packaging-war

    Not sure what you mean with using "getBean() method to dynamically create beans". getBean() uses existing bean definitions: are you referring to protype-scoped beans, maybe? That should simply work.

    You are asking the right person, but for further questions you might want to use the forums instead ;)


  50. Hi Joris,

    I'm just citing from the Spring DM doc, chapter 4.2.2:

    "Note: the application context is published as a service primarily to facilitate testing, administration, and management. Accessing this context object at runtime and invoking getBean() or similar operations is discouraged."

    This is what confuses me a lot, especially since it is not explained, how to get this context, if you are using the web extender. Perhaps this could be clarified a bit in the documentation?

    Thanks a lot for your time and help!
    Joern


  51. Ah, I see: that section says that the ApplicationContext from a bundle is also exposed as a service itself. Other bundles should typically only interact with it by using services that are backed by Spring beans from that context, not by calling the other bundle's ApplicationContext itself using calls like getBean. In general, we discourage API calls to the ApplicationContext or BeanFactory as it ties your code to Spring.
    Do you have a particular use case for which you need the actual ApplicationContext of another bundle and getBean() instead of just accessing its beans as OSGi service references?


  52. Hi Joris,

    This is Shameer from Dubai, I attended your course at Dubai. We had discussed the same problem there, which we were already implementing(not declaratively, but programmatically by adding the shared context as the parent of the web of EJB contexts), using the SingletonBeanFactory locator.

    This blog is helpful for us, since it gives us a clue to use the existing mechanism in spring (the declarative use of parentContextKey.

    But we still have a problem here, whenever a sub-context(web or ejb) of a multi-war EAR app locates the spring bean-factory using SingletonBeanFactoryLocator, it does return the once initiated bean-factory, but it refreshes (calls the refresh method) itself once again. So the result is, suppose there are five war modules in an EAR, there will be minimum five calls to the refresh method, which is undesirable.

    Right now we handle it by overriding the refresh method in a sub class and controlling the further refresh calls (till startup of the application finishes) using a static boolean variable (it is a hack :) ).

    Is there a way to avoid the further refreshes of an application-context unless it is forced to called by the client ?

    Thanks,
    Shameer


  53. Hi Shameer,

    I haven't actually tried what happens, but looking at the code for the ContextLoader (which is responsible for creating the sub-contexts for the war files) I see only one call to refresh(), after the ApplicationContext has been created and its parent has been set. I'm therefore assuming that you're talking about the shared parent context that gets refreshed multiple times? Looking at the code in the ContextSingletonBeanFactoryLocator this might be caused by the fact that its initializeDefinition() method is called multiple times. Can you confirm that? In that case it's either a classloader issue (BeanFactoryGroup not found when it should be) or a bug, in which case I would advise you to open a JIRA issue against Spring.


  54. Great post, I have not yet seen spring setup this way. I'm thinking about giving it a shot but there is one question I have yet to find out the answer on.

    Are you allowed to have multiple shared parentcontextkeys?

    Example:

    WAR-1 depends on Module-A and Module-B. Lets assume Module-A contains the DAO's and Module-B contains some services.

    Module-B depends on Module-A. WAR-1 depends on Module-A and Module-B.

    Can you specify a parent context key in WAR-1 for both Module-A and Module-B…similar to multiple configLocations?

    Thanks


  55. Actually, after reading what I wrote I don't think it's clear.

    How can you insure that a war uses a shared instance for the two different domain models?

    Lets say you have 2 different applications which have their own domain layer packed up and you want to create a common webapp sharing these 2 domain models, only instantiating them once.

    sorry for the double post…


  56. Hi Phil,

    the ApplicationContexts need to form a strict hierarchy/tree, which means that each one can only have one parent. Not sure if that answers your question, but it means that the WebApplicationContext of a WAR (created by a ContextLoader) can only point to one parent context that's indicated by the parentContextKey.

    That doesn't necessarily mean that that parent in turn can't have another parent, which would be reachable transitively from the WebApplicationContext: that would be set up in the beanRefContext.xml where you actually create the parent context. There is a constructor on the ClassPathXmlApplicationContext that let's you pass in a String[] with config file locations and a parent ApplicationContext.
    You can create yourself a whole forest of contexts if you like: I wouldn't typically recommend this, though, as it will be pretty confusing to most people. If you need a proper way to share Spring-managed objects between applications, you might want to take a look at OSGi and its service registry and how to use that in dm Server via Spring-DM.


  57. Thanks for the feedback.

    So having only 1 parent shared context means in order to support 2 domain layers packed separately you would need to do something like the following:

    Domain-1 is Parent to Domain-2, and Domain-2 is Parent to WAR-1.

    Is there any tricks that can be done in the configuration to allow for also this configuration:
    Domain-1 is the Parent to WAR-2 or Domain-2 is the parent to WAR-3, but not both Domain-1 and Domain-2.

    I understand your previous point, but it seems like this approach is really application centric. I'd like to know if there is an easier way to create the configurations so the dependencies are not so tightly coupled.

    Thanks again Joris.


  58. You should think about what it means to share a domain layer first: typically I'd say it involves sharing *types* (classes, mostly) and not *instances*. You can easily do that, and even share the same Spring XML config files if you like, without needing anything like a shared ApplicationContext.
    A shared context is only of interest if you need to share beans (not just bean definitions), so managed *instances*, between multiple ApplicationContexts. Stateful services are the typical example here, that cache data for example. A domain layer is not even known to Spring in most applications, as instances of domain classes are not Spring-managed beans.

    There are certainly workarounds you can come up with if you really need to access multiple contexts and not just a single parent: you can use the (ContextSingleton)BeanFactoryLocator yourself to obtain a reference to the context and perform a lookup by name or by type, for example. However, I wouldn't recommend that: again, if you really have requirements to do in-VM SOA I would recommend to use OSGi services instead. That gives you an extremely robust and fully dynamic model that goes way beyond what you can achieve with context hierarchies. By using Spring-DM the programming model remains the same as always, and with dm Server most enterprise libraries and frameworks will work just fine combined with OSGi.


  59. This has very interesting possibilities. I am curious if anyone has tried using this with Spring Security. If I package multiple WARS in one EAR will this allow me to share one security context, thus essentially having SSO across all the web applications?


  60. "If I package multiple WARS in one EAR will this allow me to share one security context, thus essentially having SSO across all the web applications?"

    Unfortunately it's not that simple: by default, the SecurityContextHolder is populated with a SecurityContext that's stored in the HttpSession between requests. Each WAR will still have its own HttpSession, even though it can share a single WebApplicationContext as its parent context, so you'd need either a true SSO mechanism or a different storage location for the SecurityContext than the HttpSession, one that's shared between all WARs in the EAR on a per-user basis. This could be a singleton Map keyed on a shared cookie, for example, but you would also need to write a custom ServletFilter to replace the standard HttpSessionContextIntegrationFilter to actually use that. Haven't tried that myself, but I'm sure it wouldn't be too hard to come up with something that does the job.


  61. Hi Joris, thanks for the great post. I have this example working with a single ear and multiple wars contained in the ear. That works ok for some things, but what we are running into (and have been able to work around in the J2EE realm) is that we have many developers deploying to a single jboss instance. Therefore, we typically like to be able to isolate our applications (war/ears) from each other. So what we would like to do is deploy a single ear that contains a core set of services (DOAs, main services that most things will depend on) and then allow each developer create services that just depend on those and deploy them separately from the main ear. So we would have mainStuff.ear and simpleService.war and simpleService.war would want a reference to the application context exposed by mainStuff.ear (i.e. ear.context in your example). This setup additionally allows us to hot deploy sub-services without having to disturb the main/core set of services. I can't figure out how to make this work. Do you have any hints, or is this simply not possible with Spring? Let me know if that doesn't make sense.


  62. Hi Andrew,

    if you'd want to share instances across ears, they would need to be loaded by a classloader that is a parent of all ears: not something you could achieve by deploying a 'master ear', I'd say. This not being possible has nothing to do with Spring, it has to do with the J2EE architecture your server uses.
    In fact, OSGi with its services registry sounds like the perfect solution to what you're trying to achieve; doesn't JBoss have something as well with its new microkernel in this space?


  63. Hi Joris,
    I managed to deploy and reproduce your your example in Glassfish 2.1.
    Unfortunately, the situation in Glassfish v3 (final) is quite different.
    I'm facing different object ids in both web apps.

    Are you aware of any difference in both versions, concerning e.g. classloader hierarchy?

    Thanks in advance
    Jürgen


  64. doesnt work in jboss 5.x enviroment..


  65. Concur with above comment. Works fine on JBoss 4.2.3 and fails on JBoss 5.1.


  66. The code also appears to work fine on WebSphere 7.0.


  67. Nice work on this article. I've found this article a year or so ago and used this solution ever since. I've tried OSGI for a while and found it too much of a hassle since I'm usually involved with small to medium-sized applications.

    For those still interested I've built a mini-framework that takes this approach one step further, I've posted it here http://code.google.com/p/springlime/.


  68. Hi Joris

    So the parent applicationContext i shared in an application accross JVMs. Is it also possible to share it in an application that is clustered?


  69. Hi Johan,

    as this approach simply works through shared references and ApplicationContext lookups through singletons, there's no way to apply this to inter-VM/clustered applications. That would require some form of remoting or other distribution mechanism which would alter the semantics of your application completely.
    There are a number of approaches to clustering Spring applications, but shared contexts are not a solution to that problem.


  70. Hi Joris,

    Thanks for your post. We also need to implement this. But ours is 1 war and multiple ejbs. And I want to share the application context of the war to the ejbs. But I'm having trouble just running your sample ear in our weblogic 10.3 server. The first servlet is able to run successfully but when i try the second servlet it is giving me classcast exception:

    java.lang.ClassCastException: com.interface21.sample.multiplecontexts.service.SampleServiceImpl cannot be cast to com.interface21.sample.multiplecontexts.service.SampleService
    at com.interface21.sample.multiplecontexts.web2.SecondServlet.doGet(SecondServlet.java:26)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3498)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(Unknown Source)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2180)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2086)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1406)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)

    Do you have any idea why I'm having this problem?


  71. Hi Raymund,

    this indicates that the SampleService and SampleServiceImpl are loaded by different classloaders. You need to ensure that both WARs load these classes from the same (typically parent) classloader, since classes in different classloaders are always considered as different classes by the JVM. Putting them in an EJB jar would probably do the trick, as EJB code is typically loaded in a classloader that's a parent to the WAR classloaders of the same EAR; otherwise you can resort to WebLogic-specific options, like using the EAR's APP-INF/lib directory.


  72. Hi Joris,

    Thanks for the fast reply.
    I can try the using the APP-INF/lib later but I'm not very clear on how I can put them in an EJB jar?
    Could there be some setting in my server causing it to use different classloader if in case some other people was able to make it work in weblogic 10.3?


  73. Sure: I'm not familiar with WebLogic myself, but I'm sure that you could for example configure the server to use a single classloader for the entire EAR file. That should work, as there are no sibling WAR classloaders then. "Put them in an EJB jar" simply means moving the shared types (interfaces and classes) to one of your EJB jars instead of putting them in a WAR or a jar that happens to be loaded in a WAR classloader.

    To access the shared parent context from your EJBs as well, have a look at http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ejb.html#ejb-implementation-ejb2
    My personal preference is to use the ContextSingletonBeanFactoryLocator instead of the default ContextJndiBeanFactoryLocator in those cases, as shown in the example. Also check out the JavaDoc for this type.


  74. Hi Joris,

    Ok, I'll look them up on how to set up a single classloader on WLS.
    We are already using the ContextSingletonBeanFactoryLocator among our EJBs, the only problem is that our WAR is still having its own app context. So I'm in the process of modifying our WAR to use the same context.

    Thanks for the advice again.


  75. Hi Joris,
    Thanks for the great article.

    Have you done anything in multiple – parent child context scenario with Spring Security? For my application ear I was using a main service-layer context to load DAOs, Services, etc.
    I recently tried spring security 3 with my app and used its annotations for security.
    The annotations for security work fine in the beans defined using web context but not in the parent(service layer) context where I actually need it to support multiple interfaces into the application.
    I've the spring security namespace and everything else defined in the parent context but it still doesn't work.

    The application is run on jboss 4.2.3
    Any help would be appreciated.


  76. It could be that your web contexts are loaded by a different classloader, and that the spring security jars are loaded only by that classloader. In that case you'd need to ensure that these jars are loaded by a parent classloader; not sure what the best way to do that is on JBoss 4.2.
    Just as a sanity check you could program a small test that runs in your parent context and tries to access a spring security class.


  77. Thanks for the reply Joris.

    I'm able to access spring security classes in the service layer, BUT, I do not see the thread local objects. So, for instance the Authentication that is stored with SecurityContextHolder is null which is present in my Controller(web layer context defined bean) but not present in my service layer bean class.
    Not sure where the problem is.


  78. hi Joris,

    Thanks for the great article. I've similar situation where there are 2 jars from different vendors are trying to load the beans. So after Bootstrap class in jar1 loads beans there is ContextListener in JAR2 which again tries to initialize the spring context. So, i get java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present – check whether you have multiple ContextLoader* definitions in your web.xml!. Below is the code snippet in JAR1

    t extends Spring's ContextLoaderListener and overrides contextInitialzed method where in it calls super.contextInitialized(event), which calls ContextLoader's initWebApplicationContext(event.getServletContext()) which checks for
    servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null and this condition turns to be true and thus it throws exception. Please finf below code snippet

    public class PortalContextLoaderListener extends ContextLoaderListener {
    public void contextInitialized(ServletContextEvent event) {

    InitUtil.init();
    super.contextInitialized(event); // error here
    ApplicationContext applicationContext =
    ContextLoader.getCurrentWebApplicationContext();

    }
    /************Spring ContextLoaderListener class ********************/

    public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
    this.contextLoader = createContextLoader();
    if (this.contextLoader == null) {
    this.contextLoader = this;
    }
    this.contextLoader.initWebApplicationContext(event.getServletContext());
    }
    ..
    ..
    }

    /************Spring ContextLoader class ********************/
    public class ContextLoader {
    …..
    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
    throw new IllegalStateException(
    "Cannot initialize context because there is already a root application context present – "
    "check whether you have multiple ContextLoader* definitions in your web.xml!");
    }

    Log logger = LogFactory.getLog(ContextLoader.class);
    servletContext.log("Initializing Spring root WebApplicationContext");
    if (logger.isInfoEnabled()) {
    logger.info("Root WebApplicationContext: initialization started");
    }
    ………..

    // other stuff.
    }

    In JAR2 there's Config object which is doing also initializing the context and setting it to parent.

    XmlBeanDefinitionReader xbdr = new XmlBeanDefinitionReader(ctx);

    String[] springLocsArray = springLocations.toArray(new String[springLocations.size()] );
    log.info( "Initializing spring with these config locations:: " springLocations );
    try{
    xbdr.loadBeanDefinitions( springLocsArray );
    }catch(Exception e){ log.info( "Exception e: " e);}
    log.info( "xbdr1" xbdr);
    xbdr.setBeanClassLoader(Thread.currentThread().getContextClassLoader());
    log.info("xbdr" xbdr);
    ctx.setClassLoader( Thread.currentThread().getContextClassLoader() );
    ctx.addBeanFactoryPostProcessor(ppc);
    if ( poc != null ) {
    ctx.addBeanFactoryPostProcessor( poc );
    }

    StaticApplicationContext parent = new StaticApplicationContext();
    parent.refresh();
    parent.getBeanFactory().registerSingleton( "config", this );
    ctx.setParent( parent );
    ctx.refresh();
    if ( beanFactory == null ) {
    beanFactory = ctx;
    }

    Can you pls advice how can I use the parent context as ceated in JAR2.

    regards
    Vijay


  79. Just thought I'll drop a question here as I can't figure out why JBoss 5.1 behaves like it does.

    Using the shared parent application context seems to work only if I omit the archive or folder being a ear. I even re-produced the issue with the example provided above. If I leave the archive as zip and drop it in the deploy folder the demo works fine, shared application context is used. Changing the extension of the archive to ear breaks the functionality, result is two application contexts. I got grey hair while debugging this on our application and unfortunately tried out the ear extension on the demo in the end to discover that it was the reason why our application didn't use shared app context…

    I'm sure there is something that could explain this but haven't found it yet and thought there might be somebody who could shed some light into to this.

    Br
    Mauritz


  80. @Mauritz: this must be a classloader issue then. I'm not intimately familiar with JBoss's classloader model for ear files, but some googling came up with a couple of useful links that might provide you with more information:
    http://detailfocused.blogspot.com/2008/08/jboss-ear-classloading.html
    http://community.jboss.org/wiki/ClassLoadingConfiguration
    http://community.jboss.org/wiki/JBossClassLoadingUseCases


  81. Great article. Does this work for sharing contexts amongst ejb's as well? I have an EAR project where I have an MDB and a WAR that need to utilize the same services.

    Thanks!

    Ravi


  82. Hi Ravi,

    yes, that works: in fact, it's exactly how I got started with this. Also see my previous comment for April 29 on some pointers for bootstrapping and accessing the shared context from your EJB. Again, depending on the application server you're using you might need to tweak the default classloading mechanism to ensure that the code for the shared context is loaded by a single classloader visible to both your WAR and your EJB jar (you don't want the WAR to have its own copy).


  83. Thanks, Joris, for your quick reply.

    I looked at all the suggestions above, and tried it out and it is mostly working. I just have one problem left: in your example, you have a parent context and in each war there is an application.xml. In the application.xml, you say to put in beans that are only required by the specific web application and do not need to be shared. So I have separated it that way — the parent context contains all shared model and service beans to access the data layer. My war's web application.xml has the controller and web-flow services needed by the web application only, and not needed in the shared context.

    However, the war context needs to inject some of the services initialized in the parent context. I assumed that would work, but it doesn't. When the application context's controller beans try to inject a DAO service, I get a NoSuchBeanDefinitionException, so the services can't be autowired.

    Is there something that you need to do to make the parent context available to the war's own application context during initialization?

    Thanks again for your help!

    Ravi


  84. The parent context is resolved automatically when the child context is created, and then you should indeed be able to inject beans from your child context with beans from the parent context. If that doesn't work then there's something wrong with your setup.
    The web.xml that contains a ContextLoaderListener should define a context param called parentContextKey that refers to the parent context by its name, and the EJB code should use the same name by setting the beanFactoryLocatorKey property in combination with a ContextSingletonBeanFactoryLocator, assuming you're extending AbstractMessageDrivenBean. Don't use the default bean factory locator, as it want to look up the key in JNDI which is typically very cumbersome to configure: the ContextSingletonBeanFactoryLocator is much easier.


  85. Fantastic post! This could aid lots of people find out about this matter.


  86. How would we use this approach with a web service application using spring-ws MessageDispatcherServlet.

    it doesn't appear to support the parentContextKey


  87. @Dan: the parentContextKey is used by the ContextLoader, which creates the WebApplicationContext that's the parent to both DispatcherServlet contexts and MessageDispatcherServlet contexts. So, you wouldn't need to do anything special except for making sure that your web.xml bootstraps this parent content using a regular ContextLoaderListener. With the extra root context I described in my blog post, that means that you'll end with (at least) 3 ApplicationContexts in a hierarchy: one for the MessageDispatcherServlet, one bootstrapped by the ContextLoaderListener (parent to the 1st), and one that acts as the root (parent to the 2nd), bootstrapped using a BeanFactoryLocator triggered through the parentContextKey servlet parameter.


  88. How would we use this approach with a web service application using spring-ws MessageDispatcherServlet.

    it doesn't appear to support the parentContextKey

    It doesn't use ContextLoader class at all to create it's application context.


  89. Its so highly informative things are posted here. These things are the fresh and having good information are posted here, and also am seeking for this kind of information thanks for updated.


  90. Thanks Joris,

    You're explaination of the extra level of nesting using spring dispatcher servlets makes it clear now.

    For the benfit of anyone else using Jetty embeded and configured with spring, one piece of the puzzle is that took me a while to discover is that the context-param needed to set the parentContextKey in a web.xml translates to an init-param in the servlet API.

    ContextLoader.loadParentContext() {
    [...]
    String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);

    Here's a full Jetty example for posterity

    /


  91. Thanks Joris, makes sense now.


  92. Joris,

    First of all thanks for such wonderful post. I have a question related to making the same feature you are doing here session/request specific. What I am talking about is using the RequestContextListener instead of the ContextLoaderListener. Have you come across anythng like that..please guide me if you have any idea


  93. Hi Jack,

    frankly I can't think of a good use case for creating a new ApplicationContext for every request. That is what you're suggesting, right? What is it exactly you're trying to achieve? Maybe using session- or request-scoped beans could help you to achieve what you want; if you have dynamic requirements for their creation then using a FactoryBean or an @Bean method on an @Configuration class might suffice.


  94. Hi Joris,

    Thank you for this excellent post and answering all those questions throughout the years. Did you have that on your mind when you were writing this blog post? :-)

    I wondered if this multiple context solution is equivalent to the use of prototypes in Spring 3? If correct wondering, which solution would you prefer?

    With kind regards,

    Loek


  95. Hi Loek,

    no, I had never anticipated that this entry would cause so much interest and feedback over the years ;)
    You say "prototypes", not sure what you mean: did you mean "profiles" perhaps? In that case it's not the same: profiles allow you to conditionally have certain beans defined depending on the profile(s) that are active when you start the ApplicationContext, this blog post talks about sharing beans from a single context across (web) modules in your application. Actually, my only other blog post which discusses environment-aware Spring applications is a way to achieve what can now be done with profiles natively in Spring 3.1.


  96. Hi Joris,

    Great post even for Spring3, but I have something confused about the singleton. You mentioned"In general, if you have stateful beans that should really be used as a singleton (in the Spring sense, i.e. one instance per application as opposed to per JVM) you should define them in a single context accessed by the other contexts.", and is the comparison about the per application and per JVM means the clustered deployment and a non clustered one? If not, in a single server I think all the wars in an ear will be in a same JVM. Could you help explain that point in more details?


  97. Hi Fellix,

    that remark is there to clarify that 'singleton' is not intended to mean the Gang of Four design pattern, but the default scope of a Spring bean definition. Spring cannot guarantee that only a single instance of a class exists, only that for a given bean definition defined in an ApplicationContext there's only going to be a single instance.
    Without a shared parent context, using a single Spring configuration file to define multiple contexts inside of a single application would mean that a separate instance would be created for every context, whereas a single shared context will ensure that only a single instance is created. That's only important if that instance holds state that you don't want to be replicated across the contexts that make up your application, or if its creation has additional side effects that should not be repeated for every context. Think about things like caches and pools: you want the entire application to share those objects, you don't want every web module (or whatever module with its own ApplicationContext you happen to be using) to define its own instances, since that would be inefficient and potentially even problematic.


  98. Great post. This is timely for us, as we have an EAR with 8 WARs that we are converting to Spring.

    Is it proper to move the datasource and transaction manager beans up into the EAR as well? Seems a little strange, because I am using resource-ref=true, and resource references are defined to the WAR.


  99. Stuck on the same problem that DomV mentioned above, anybody have any thoughts?

10 trackbacks

Leave a Reply