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

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:
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
- POJO Aspects in Spring 2.0: A Simple Example
- SpringSource Application Platform Deployment Options
- Source for demos shown at NL-JUG session June 13th 2007
- Spring Dynamic Language Support and a Groovy DSL
- BeanInitializer: wiring dependencies in unit tests











Erwin Vervaet says:
Added on June 12th, 2007 at 12:48 amNice entry. I wondered about this, but never actually looked it up.
Christian Seiler says:
Added on June 12th, 2007 at 6:49 amI'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?
Joris Kuipers (blog author) says:
Added on June 12th, 2007 at 7:43 am[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.
Corby Page says:
Added on June 12th, 2007 at 8:58 am"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.
Joris Kuipers (blog author) says:
Added on June 12th, 2007 at 9:26 am[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
Benoit Orihuela says:
Added on June 13th, 2007 at 2:30 amVery, 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.
Kerry Wright says:
Added on June 15th, 2007 at 12:48 pmAlso 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.
Jörg Heinicke says:
Added on June 28th, 2007 at 3:50 amIf 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
Burak says:
Added on July 2nd, 2007 at 8:02 amHi 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
Joris Kuipers (blog author) says:
Added on July 2nd, 2007 at 3:18 pm[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
Rapthor says:
Added on July 5th, 2007 at 4:54 amHello,
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?
Rapthor says:
Added on July 5th, 2007 at 6:51 amI 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.
Joris Kuipers (blog author) says:
Added on July 6th, 2007 at 3:27 am[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.
ziki says:
Added on August 24th, 2007 at 9:57 amI put the all spring applicaitonContext.xml to myapp.ear/APP-INF/classes
Dimitri Hautot says:
Added on September 5th, 2007 at 10:41 amHello,
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
Joris Kuipers (blog author) says:
Added on September 5th, 2007 at 12:26 pm[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.
Dimitri Hautot says:
Added on September 7th, 2007 at 3:44 amHello,
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!
Ales Novy says:
Added on September 19th, 2007 at 10:27 amUnfortunately, 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.
Jee says:
Added on September 25th, 2007 at 7:42 amHi 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
Joris Kuipers (blog author) says:
Added on September 25th, 2007 at 8:06 am[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
Jee says:
Added on September 25th, 2007 at 10:36 amIndeed 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.
JoeC says:
Added on October 22nd, 2007 at 10:42 amThanks 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;}}
Joris Kuipers (blog author) says:
Added on October 22nd, 2007 at 1:57 pm[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.
JoeC says:
Added on October 22nd, 2007 at 4:26 pmThanks 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();
JoeC says:
Added on October 23rd, 2007 at 8:37 amActually, 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.
Joris Kuipers (blog author) says:
Added on October 23rd, 2007 at 1:34 pm[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.
JoeC says:
Added on October 25th, 2007 at 3:23 pm[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.
Arnon Davidovici says:
Added on November 2nd, 2007 at 7:34 pmI 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.
Joris Kuipers (blog author) says:
Added on November 3rd, 2007 at 5:17 am[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:
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.
Arnon Davidovici says:
Added on November 6th, 2007 at 12:02 pmThanks 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).
Joris Kuipers (blog author) says:
Added on November 6th, 2007 at 12:16 pm[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.
Aidan Whiteley says:
Added on December 2nd, 2007 at 12:34 pmHi,
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!
Joris Kuipers (blog author) says:
Added on December 2nd, 2007 at 4:02 pm[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.
Aidan Whiteley says:
Added on December 3rd, 2007 at 4:27 pmHi 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.
Derek says:
Added on December 4th, 2007 at 3:10 pmJust 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
EDH says:
Added on January 5th, 2008 at 8:48 amJoris,
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
Joris Kuipers (blog author) says:
Added on January 5th, 2008 at 10:06 am[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
EDH says:
Added on January 6th, 2008 at 8:27 amJoris,
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
Joris Kuipers (blog author) says:
Added on January 6th, 2008 at 10:53 am[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
Eric says:
Added on June 19th, 2008 at 11:04 amIt 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.
Andy says:
Added on October 25th, 2008 at 7:03 pmVery 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?
Joris Kuipers (blog author) says:
Added on October 26th, 2008 at 3:53 amI'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.
Joris Kuipers (blog author) says:
Added on December 3rd, 2008 at 1:57 pm(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.
Richi Plana says:
Added on January 28th, 2009 at 3:22 pmHi, 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).
Joris Kuipers (blog author) says:
Added on January 28th, 2009 at 3:43 pmIf 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.
Joern Schimmelpfeng says:
Added on March 28th, 2009 at 10:06 amHi 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
Joris Kuipers (blog author) says:
Added on March 29th, 2009 at 4:55 amHi 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.
Joern Schimmelpfeng says:
Added on March 30th, 2009 at 4:17 pmHi 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
Joris Kuipers (blog author) says:
Added on March 31st, 2009 at 3:20 pmFor 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
Joern Schimmelpfeng says:
Added on March 31st, 2009 at 4:06 pmHi 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
Joris Kuipers (blog author) says:
Added on March 31st, 2009 at 5:18 pmAh, 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?
Shameer Kunjumohamed says:
Added on April 23rd, 2009 at 3:59 amHi 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
Joris Kuipers (blog author) says:
Added on April 23rd, 2009 at 4:23 amHi 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.
Phil says:
Added on May 4th, 2009 at 7:23 pmGreat 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
Phil says:
Added on May 5th, 2009 at 12:22 amActually, 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…
Joris Kuipers (blog author) says:
Added on May 5th, 2009 at 12:53 amHi 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.
Phil says:
Added on May 6th, 2009 at 1:00 pmThanks 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.
Joris Kuipers (blog author) says:
Added on May 6th, 2009 at 1:31 pmYou 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.
Dave says:
Added on July 24th, 2009 at 7:04 pmThis 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?
Joris Kuipers (blog author) says:
Added on July 25th, 2009 at 2:03 am"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.
Andrew says:
Added on November 6th, 2009 at 5:23 pmHi 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.
Joris Kuipers (blog author) says:
Added on November 13th, 2009 at 7:21 amHi 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?
Jürgen says:
Added on December 13th, 2009 at 5:55 pmHi 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
Berkay says:
Added on February 7th, 2010 at 9:45 amdoesnt work in jboss 5.x enviroment..
Joel says:
Added on March 3rd, 2010 at 12:50 pmConcur with above comment. Works fine on JBoss 4.2.3 and fails on JBoss 5.1.
Joel says:
Added on March 3rd, 2010 at 1:50 pmThe code also appears to work fine on WebSphere 7.0.
Dan says:
Added on March 16th, 2010 at 12:40 pmNice 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/.