Announcement Announcement Module
Collapse
No announcement yet.
Sharing a "global" applicationContext.xml Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Sharing a "global" applicationContext.xml

    Hi,

    I have several Message-driven beans and I want them all to share the same applicationContext.xml (call it the "global" applicationContext.xml").

    I load the global applicationContext.xml using a ServletContextListener, ie.

    public final class ApplicationContextLoader implements ServletContextListener
    {
    private ApplicationContext appcontext = null;

    public void contextInitialized(ServletContextEvent event)
    {
    appcontext = new
    ClassPathXmlApplicationContext("applicationContext .xml");
    }


    Now I have a single MDB implementation whose instances are managed by WLS 8.1 in a pool and i want then all to share the SAME global applicationContext.xml.

    Here's the bean impl:

    public class JMSAgentBean extends AbstractJmsMessageDrivenBean
    {
    public void onEjbCreate(){
    // ...
    bean = (SomeBean)getBeanFactory().getBean("SomeBean");
    }
    }

    From ejb-jar.xml, we also have:
    <ejb-name>JMSAgentBean</ejb-name>
    <snip>
    <env-entry>
    <env-entry-name>ejb/BeanFactoryPath</env-entry-name>
    <env-entry-type>java.lang.String</env-entry-type>
    <env-entry-value>applicationContext.xml</env-entry-value>
    <snip>

    (and applicationContext.xml is indeed found in the classpath)

    Given all of the above, when I deploy to the server, the ServletContextListener
    creates an ApplicationContext, as does every JMSAgentBean that gets created in the pool (not what I want :-(

    So now I add this to the JMSAgentBean in hopes of being able to share an ApplicationContext singleton)

    public void setMessageDrivenContext(javax.ejb.MessageDrivenCon text context) {
    setBeanFactoryLocator(ContextSingletonBeanFactoryL ocator.getInstance("classpath:applicationContext.x ml"));
    }

    Now when I deploy, only 1 ApplicationContext is created (and its done by the ServletContextListener
    so thats good), however, no calls are made to the onEjbCreate() method for any of the JMSAgentBean's which means they did not deploy correctly.

    Looking at the slew of debug messages, I do not see any exceptions or error so I don't know what to do now.

    Any ideas?

    thanks for any tips you can give,
    Mike

  • #2
    Same problem

    I have a similar problem that I posted about just below you (WAS 5 question).
    One thing I thought of was binding a facade RMI object from where I can access/call all that I want, could this work? How does plain-vanilla RMI behave in this case? Is it the same object that gets returned on each call?
    I think it might work, haven't tried it yet though..

    Comment


    • #3
      Thanks for the RMI idea but I don't see how this can help since both ApplicationContext and BeanFactory are NOT serializable.

      There must be some basic way to share the global appContext that is just not yet apparent to me yet??

      if you figure this out, please let me know.

      thanks,
      mike

      Comment


      • #4
        Re: Sharing a &quot;global&quot; applicationContext.xml

        Originally posted by mikem
        Given all of the above, when I deploy to the server, the ServletContextListener
        creates an ApplicationContext, as does every JMSAgentBean that gets created in the pool (not what I want :-(
        You already did the right thing, except that the default implementation of the BeanFactoryLocator is ContextJndiBeanFactoryLocator which creates an instance of the ClassPathXmlApplicationContext everytime the bean is created. If you do not want this, try changing the default implementation of BeanFactoryLocator by calling the setter 'setBeanFactoryLocator(BeanFactoryLocator newlocator)'

        You can use these two classes that Spring provide:

        - SingletonBeanFactoryLocator
        - ContextSingletonBeanFactoryLocator

        This time the beanfactory uses a singleton factory which is shared among EJB instances.

        Comment


        • #5
          RMI use

          "Thanks for the RMI idea but I don't see how this can help since both ApplicationContext and BeanFactory are NOT serializable. "

          I am proposing that you dont have the BeanFactory or ApplicationContext in the MDB at all.
          The way I have it, I have an object bound to an RMI-object that has a BeanFactory, my MDB then delegates all its work to this facade RMI-object that does all the BeanFactory work and other execution.

          Something like this:
          onMessage(Message msg){
          rmiFacade.onMessage(msg);
          }

          I tend to not have too much application logic in my MDB:s or EJB:s anyway, I usually delegate their work to POJO:s (who incidentally, tend to have full Spring-access without any quirks).

          Comment


          • #6
            Hi,
            I have a simmilar deployment: an EAR with a web application and message driven beans.
            In my message driven bean, I have set the main application context to be a singleton:
            Code:
            ......
            public void setMessageDrivenContext&#40;MessageDrivenContext messageDrivenContext&#41; &#123;
                    super.setMessageDrivenContext&#40;messageDrivenContext&#41;;
                    setBeanFactoryLocator&#40;ContextSingletonBeanFactoryLocator.getInstance&#40;"classpath*&#58;spring/beanRefContext.xml"&#41;&#41;;
                    setBeanFactoryLocatorKey&#40;"applicationContext-main"&#41;;
                &#125;
            ......
            In the web.xml I have configured the web application context to be the child of the singleton application context:
            Code:
             <context-param>
                    <param-name>contextConfigLocation</param-name>
                    <!-- applicationContext-web.xml contains configurations specific only to the web application.-->
                    <param-value>/WEB-INF/spring/applicationContext-web.xml</param-value>
                </context-param>
                <context-param>
                    <param-name>locatorFactorySelector</param-name>
                    <param-value>classpath*&#58;spring/beanRefContext.xml</param-value>
                </context-param>
                <context-param>
                    <param-name>parentContextKey</param-name>
                    <param-value>applicationContext-main</param-value>
                </context-param>
            My beanRefCintext.xml file looks like:
            Code:
            <?xml version="1.0" encoding="UTF-8"?>
            <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http&#58;//www.springframework.org/dtd/spring-beans.dtd">
            
            <beans>
            
                <bean name="applicationContext-main" class="org.springframework.context.support.ClassPathXmlApplicationContext">
                    <constructor-arg>
                       <list>
                         <value>spring/dataAccessContext.xml</value>
                         <value>spring/applicationContext-xxx.xml</value>
                         <value>spring/applicationContext-yyy.xml</value>
                         <value>spring/applicationContext-zzz.xml</value>
                       </list>
                    </constructor-arg>
                </bean>
                    
            </beans>
            Hope this helps, Mircea

            Comment


            • #7
              config file location question

              I am trying to setup an application that is very similar to this but with one war and many mdb ejb jars. The war contains its own config for the spring mvc bootstrap and the rest of the spring config is shared across the war and the ejb jars. I am trying to place the common configuration in a "conf" directory under the EAR and leave the dispatcher servlet bean config in the WAR and then use the parent context loader as you described but it appears that the bean factory locator is not able to find the beanRefContext.xml. Could you clarify exactly where your bean configuration files are located in your setup?

              i.e. in mine the structure looks like

              EAR
              -> conf (difectory)
              -> various bean config files
              -> beanRefContext.xml
              -> WAR
              -> WEB-INF
              -> conf
              -> wwwapp-servlet.xml

              In my web.xml
              -----------------------------------------
              Code:
              <context-param>
                 <param-name>contextConfigLocation</param-name>
                 <param-value></param-value>
              </context-param>
              
              <context-param> 
                 <param-name>locatorFactorySelector</param-name> 
                 <param-value>classpath*&#58;conf/beanRefContext.xml</param-value> 
              </context-param> 
              
              <context-param> 
                 <param-name>parentContextKey</param-name> 
                 <param-value>mainApplicationContext</param-value> 
              </context-param>
              
              <listener>
                 <listener-class>
                 org.springframework.web.context.ContextLoaderListener
                 </listener-class>
              </listener>
              
              <servlet>
                 <servlet-name>wwwapp</servlet-name>
                 <servlet-class>
                 org.springframework.web.servlet.DispatcherServlet
                 </servlet-class>
                 
                 <init-param>
                    <param-name>contextConfigLocation</param-name>
                    <param-value>wwwapp-servlet.xml</param-value>
                 </init-param>
              
                 <load-on-startup>1</load-on-startup>
              </servlet>
              ----------------------------
              beanRefContext.xml
              ----------------------------
              Code:
              <beans>
              <bean 
                 id="mainApplicationContext"
                 class="org.springframework.context.support.ClassPathXmlApplicationContext">
                 <constructor-arg>
                    <list>
                       <value>/conf/rootApplicationContext.xml</value>
                       <value>/conf/rootApplicationContext_DataSource.xml</value>
                       <value>/conf/rootApplicationContext_DAO.xml</value>
                       <value>/conf/rootApplicationContext_Service.xml</value>
                       <value>/conf/rootApplicationContext_JMS.xml</value>
                       <value>/conf/rootApplicationContext_Quartz.xml</value>
                    </list>
                 </constructor-arg>
              </bean>
              </beans>
              -----------------------------------

              To this point the MDB's are not an issue so I will skip that configuration but when I package as an EAR and deploy to weblogic 9.0 I receive the following exception at startup...

              Code:
              org.springframework.beans.FatalBeanException&#58; Unable to return specified BeanFactory instance&#58; factory key &#91;mainApplicationContext&#93;, from group with resource name &#91;classpath*&#58;conf/beanRefContext.xml&#93;; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException&#58; No bean named 'mainApplicationContext' is defined&#58; org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans &#91;&#93;; root of BeanFactory hierarchy
              org.springframework.beans.factory.NoSuchBeanDefinitionException&#58; No bean named 'mainApplicationContext' is defined&#58; org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans &#91;&#93;; root of BeanFactory hierarchy
              	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition&#40;DefaultListableBeanFactory.java&#58;365&#41;
              	at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedBeanDefinition&#40;AbstractBeanFactory.java&#58;635&#41;
              	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean&#40;AbstractBeanFactory.java&#58;194&#41;
              	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean&#40;AbstractBeanFactory.java&#58;146&#41;
              	at org.springframework.context.support.AbstractApplicationContext.getBean&#40;AbstractApplicationContext.java&#58;504&#41;
              	at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory&#40;SingletonBeanFactoryLocator.java&#58;401&#41;
              	at org.springframework.web.context.ContextLoader.loadParentContext&#40;ContextLoader.java&#58;265&#41;
              	at org.springframework.web.context.ContextLoader.initWebApplicationContext&#40;ContextLoader.java&#58;148&#41;
              	at org.springframework.web.context.ContextLoaderListener.contextInitialized&#40;ContextLoaderListener.java&#58;48&#41;
              	at weblogic.servlet.internal.EventsManager$FireContextListenerAction.run&#40;EventsManager.java&#58;336&#41;
              	at weblogic.security.acl.internal.AuthenticatedSubject.doAs&#40;AuthenticatedSubject.java&#58;321&#41;
              	at weblogic.security.service.SecurityManager.runAs&#40;SecurityManager.java&#58;121&#41;
              	at weblogic.servlet.internal.EventsManager.notifyContextCreatedEvent&#40;EventsManager.java&#58;79&#41;
              	at weblogic.servlet.internal.WebAppServletContext.preloadResources&#40;WebAppServletContext.java&#58;1549&#41;
              	at weblogic.servlet.internal.WebAppServletContext.start&#40;WebAppServletContext.java&#58;2565&#41;
              	at weblogic.servlet.internal.WebAppModule.startContexts&#40;WebAppModule.java&#58;859&#41;
              	at weblogic.servlet.internal.WebAppModule.start&#40;WebAppModule.java&#58;321&#41;
              	at weblogic.application.internal.flow.ModuleListenerInvoker.start&#40;ModuleListenerInvoker.java&#58;114&#41;
              	at weblogic.application.internal.flow.StartModulesFlow.activate&#40;StartModulesFlow.java&#58;28&#41;
              	at weblogic.application.internal.BaseDeployment$2.next&#40;BaseDeployment.java&#58;635&#41;
              	at weblogic.application.utils.StateMachineDriver.nextState&#40;StateMachineDriver.java&#58;26&#41;
              	at weblogic.application.internal.BaseDeployment.activate&#40;BaseDeployment.java&#58;257&#41;
              	at weblogic.application.internal.DeploymentStateChecker.activate&#40;DeploymentStateChecker.java&#58;154&#41;
              	at weblogic.deploy.internal.targetserver.AppContainerInvoker.activate&#40;AppContainerInvoker.java&#58;80&#41;
              	at weblogic.deploy.internal.targetserver.BasicDeployment.activate&#40;BasicDeployment.java&#58;383&#41;
              	at weblogic.deploy.internal.targetserver.BasicDeployment.activateFromServerLifecycle&#40;BasicDeployment.java&#58;560&#41;
              	at weblogic.management.deploy.internal.DeploymentAdapter$1.activate&#40;DeploymentAdapter.java&#58;50&#41;
              	at weblogic.management.deploy.internal.AppTransition$2.transitionApp&#40;AppTransition.java&#58;30&#41;
              	at weblogic.management.deploy.internal.ConfiguredDeployments.transitionApps&#40;ConfiguredDeployments.java&#58;232&#41;
              	at weblogic.management.deploy.internal.ConfiguredDeployments.activate&#40;ConfiguredDeployments.java&#58;168&#41;
              	at weblogic.management.deploy.internal.ConfiguredDeployments.deploy&#40;ConfiguredDeployments.java&#58;122&#41;
              	at weblogic.management.deploy.internal.DeploymentServerService.resume&#40;DeploymentServerService.java&#58;166&#41;
              	at weblogic.management.deploy.internal.DeploymentServerService.start&#40;DeploymentServerService.java&#58;81&#41;
              	at weblogic.t3.srvr.SubsystemRequest.run&#40;SubsystemRequest.java&#58;64&#41;
              	at weblogic.work.ServerWorkManagerImpl$WorkAdapterImpl.run&#40;ServerWorkManagerImpl.java&#58;518&#41;
              	at weblogic.work.ExecuteThread.execute&#40;ExecuteThread.java&#58;207&#41;
              	at weblogic.work.ExecuteThread.run&#40;ExecuteThread.java&#58;179&#41;
              <Oct 21, 2005 2&#58;26&#58;14 PM CDT> <Warning> <HTTP> <BEA-101162> <User defined listener org.springframework.web.context.ContextLoaderListener failed&#58; org.springframework.beans.FatalBeanException&#58; Unable to return specified BeanFactory instance&#58; factory key &#91;mainApplicationContext&#93;, from group with resource name &#91;classpath*&#58;conf/beanRefContext.xml&#93;; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException&#58; No bean named 'mainApplicationContext' is defined&#58; org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans &#91;&#93;; root of BeanFactory hierarchy.
              org.springframework.beans.FatalBeanException&#58; Unable to return specified BeanFactory instance&#58; factory key &#91;mainApplicationContext&#93;, from group with resource name &#91;classpath*&#58;conf/beanRefContext.xml&#93;; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException&#58; No bean named 'mainApplicationContext' is defined&#58; org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans &#91;&#93;; root of BeanFactory hierarchy
              	at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory&#40;SingletonBeanFactoryLocator.java&#58;404&#41;
              	at org.springframework.web.context.ContextLoader.loadParentContext&#40;ContextLoader.java&#58;265&#41;
              	at org.springframework.web.context.ContextLoader.initWebApplicationContext&#40;ContextLoader.java&#58;148&#41;
              	at org.springframework.web.context.ContextLoaderListener.contextInitialized&#40;ContextLoaderListener.java&#58;48&#41;
              	at weblogic.servlet.internal.EventsManager$FireContextListenerAction.run&#40;EventsManager.java&#58;336&#41;
              	Truncated. see log file for complete stacktrace
              org.springframework.beans.factory.NoSuchBeanDefinitionException&#58; No bean named 'mainApplicationContext' is defined&#58; org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans &#91;&#93;; root of BeanFactory hierarchy
              	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition&#40;DefaultListableBeanFactory.java&#58;365&#41;
              	at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedBeanDefinition&#40;AbstractBeanFactory.java&#58;635&#41;
              	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean&#40;AbstractBeanFactory.java&#58;194&#41;
              	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean&#40;AbstractBeanFactory.java&#58;146&#41;
              	at org.springframework.context.support.AbstractApplicationContext.getBean&#40;AbstractApplicationContext.java&#58;504&#41;
              	Truncated. see log file for complete stacktrace
              >

              Comment


              • #8
                Format fix

                Sorry lost the formatting on the EAR structure... Here is what it looks like

                Code:
                EAR
                   -> conf &#40;difectory&#41;
                      -> various bean config files
                      -> beanRefContext.xml
                   -> WAR
                      -> WEB-INF
                         -> conf
                            -> wwwapp-servlet.xml

                Comment


                • #9
                  You need to get to the base context (for example, the servlet context in a web app). Then you can use something like:

                  Code:
                  public static Object getSpringBeanFromWeb(String beanName, ServletContext servletContext)
                  {
                  	ApplicationContext appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
                  	return appContext.getBean(beanName);
                  }
                  In JSF, I accomplish this by starting with the facescontext:

                  Code:
                  servletContext = (ServletContext)FacesContext.getCurrentInstance().getExternalContext().getContext();
                  myBean = (MyBean)MyApp.getSpringBean("myBean", servletContext);
                  Hope this is helpful,

                  - Mark

                  Comment


                  • #10
                    Sample configuration

                    I'm having a similar problem.

                    I want to have my stateless session beans share the same context.
                    I know from the Spring doco and the forum threads that you can use ContextSingletonBeanFactoryLocator to achieve this.

                    What's still not clear too me is how I should configure things.

                    In my EJB's setSessionContext I need to code:
                    super.setSessionContext(aContext);
                    setBeanFactoryLocator(ContextSingletonBeanFactoryL ocator.getInstance("A"));
                    setBeanFactoryLocatorKey("B");


                    In my beanRefContext.xml I have to code:
                    <bean id="C" lazy-init="true" class="org.springframework.context.support.ClassPa thXmlApplicationContext">
                    <constructor-arg>
                    <value>D.xml</value>
                    </constructor-arg>
                    </bean>

                    The question I still have is how A, B, C and D relate to each other, whether I still need an env-entry in my ejb descriptor and if so what should it look like ?

                    Can somebody shed some light on this ?

                    Comment


                    • #11
                      B=C and A=D.

                      my config looks like this:
                      Code:
                                  public void setSessionContext(SessionContext sessionContext) {
                              setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());
                              setBeanFactoryLocatorKey("my.app.context");
                              super.setSessionContext(sessionContext);
                          }
                      and
                      Code:
                      	<bean id="my.app.context"
                      		class="org.springframework.context.support.ClassPathXmlApplicationContext">
                      		<constructor-arg index="0" value="applicationContext-ejb.xml" />
                      		<constructor-arg index="1" type="boolean">
                      			<value>true</value>
                      		</constructor-arg>
                      	</bean>

                      Comment


                      • #12
                        Hi,

                        Here is another detailed example for Sharing a spring context across multiple modules

                        Nabil

                        Comment


                        • #13
                          Works

                          Hi Nabil,

                          I finally got this to work.

                          It works like a breeze.

                          Thanks for pinpointing me to this article.

                          Cheers,
                          Edwin

                          Comment


                          • #14
                            Hi Edwin,

                            i would like to know ho did u manage to get it working.
                            I'm experiencing an issue whith my ear app when i try to share a parent context between the war project and the ejb project.
                            The web layer bootstrap correctly the parent context (ear.context) trough the ServletContextListener with a parentContextKey that point to a beanRefFactory in a jar that sits in the ear/lib directory.
                            All the web jars are placed in the ear/lib directory and are referenced through a class-path key in the manifest as stated in various examples.
                            I would like to share the same parent context in the ejb applicationContext but the beanRefFactory can't get a reference to the ear.context.
                            Here is the ejb beanRefFactory:

                            Code:
                                 ...
                                <bean id="ejb.context"
                              class="org.springframework.context.support.ClassPathXmlApplicationContext">
                                    <constructor-arg index="0">
                                        <list>
                                           <value>META-INF/appCtx/data-service-transaction.xml</value>
                                            <value>META-INF/appCtx/data-service-aspects.xml</value>
                                            <value>META-INF/appCtx/data-service-beans.xml</value>
                                        </list>
                                    </constructor-arg>
                                    <constructor-arg index="1" type="boolean">
                               <value>true</value>
                              </constructor-arg>
                                   <constructor-arg index="2" type="org.springframework.context.support.ClassPathXmlApplicationContext">
                                        <ref bean="ear.context"/>
                                    </constructor-arg>
                                </bean>
                            </beans>
                            Thank u in advance
                            Best regards

                            Domenico
                            Last edited by domgif; Nov 21st, 2008, 12:34 AM. Reason: fix a mistake

                            Comment

                            Working...
                            X