Page 1 of 2 12 LastLast
Results 1 to 10 of 12

Thread: ApplicationContext hierarchy loaded at application startup

Hybrid View

  1. #1
    Join Date
    Sep 2004
    Location
    Montreal
    Posts
    2

    Default ApplicationContext hierarchy loaded at application startup

    Hi all,

    We have a web application with several jar modules. Each module has it's own context. We wanted those context to be loaded automatically at application startup to form a context hierarchy. Looking at the docs, I didn't see anything that could do this out of the box. Searching through this forum, I found a couple of posts related to this same problem, among others:

    http://forum.springframework.org/showthread.php?t=10228
    and
    http://forum.springframework.org/showthread.php?t=10335

    So I started from these posts and looked at the javadocs to find out that everything was there in the Spring APIs to load the context hierarchy at application startup. All that I needed to do was to create my own ContextLoader class and a ContextLoaderListener that instantiated this custom ContextLoader. My custom ContextLoader overrides loadParentContext() to load the hierarchy, using SingletonBeanFactoryLocator.

    I would like to know if this is the way it should be done? Or if anything already exists in Spring for this matter? Here is the source code. Hope it's usefull for other Spring users!

    Source for context loader:
    Code:
    package com.pyxis.spring.web.context;
    
    import javax.servlet.ServletContext;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.access.BeanFactoryLocator;
    import org.springframework.beans.factory.access.BeanFactoryReference;
    import org.springframework.beans.factory.access.SingletonBeanFactoryLocator;
    import org.springframework.context.ApplicationContext;
    import org.springframework.web.context.ContextLoader;
    
    /**
     * Context loader class that loads a parent context, using 
     * <code>SingletonBeanFactoryLocator</code>. Uses 
     * <code>SingletonBeanFactoryLocator</code> default definition 
     * (beanRefFactory.xml) file as the default parent context definition file. It
     * is possible to override this definition by adding the 
     * <i>parentContextConfigLocation</i> context-parame in the web.xml file. 
     * 
     * @author 	E. Hardy
     * @version $Revision: $ $Date: $
     */
    public class ContextHierarchyLoader 
    		extends ContextLoader
    {
        /**
         * Name of servlet context parameter that can specify the parent config 
         * location for the root context, falling back to the implementation's 
         * default else (beanRefFactory.xml).
         * 
         * <p>This constant value is: parentContextConfigLocation 
         */
        public static final String PARENT_CONFIG_LOCATION_PARAM = 
            	"parentContextConfigLocation";
        
        /**
         * Name of servlet context parameter that can specify the parent bean factory 
         * name for the root context, falling back to the implementation's 
         * default else (parentBeanFactory).
         * 
         * <p>This constant value is: parentBeanFactoryName
         */
        public static final String BEAN_FACTORY_NAME_PARAM = "parentBeanFactoryName";
        
        private static final String DEFAULT_BEAN_FACTORY_NAME = "parentBeanFactory";
        
        protected ApplicationContext loadParentContext(ServletContext servletContext)
                throws BeansException
        {
            String parentContextConfig = servletContext.getInitParameter(
                    		PARENT_CONFIG_LOCATION_PARAM);
            BeanFactoryLocator locator = null;
            
            if ((parentContextConfig != null) 
                    && (parentContextConfig.trim().length() > 0))
            {
                locator = SingletonBeanFactoryLocator.getInstance(parentContextConfig);
            }
            else
            {            
                locator = SingletonBeanFactoryLocator.getInstance();
            }
            
            String beanFactoryName = servletContext.getInitParameter(
                    		BEAN_FACTORY_NAME_PARAM);
            BeanFactoryReference bfr = null;
            
            if ((beanFactoryName != null) 
                    && (beanFactoryName.trim().length() >0))
            {
                bfr = locator.useBeanFactory(beanFactoryName);
            }
            else
            {
                bfr = locator.useBeanFactory(DEFAULT_BEAN_FACTORY_NAME);
            }        
            
            return (ApplicationContext)bfr.getFactory();
        }
    }
    And the source for the context loader listener:
    Code:
    package com.pyxis.spring.web.context;
    
    import org.springframework.web.context.ContextLoader;
    import org.springframework.web.context.ContextLoaderListener;
    
    /**
     * Bootstrap listener to start up Spring's root 
     * <code>WebApplicationContext</code>. This listener delegates to 
     * <code>ContextHierarchyLoader</code> to bootstrap the context hierarchy.
     *  
     * @author 	E. Hardy
     * @version $Revision: $ $Date: $
     */
    public class ContextHierarchyLoaderListener 
    		extends ContextLoaderListener
    {
        protected ContextLoader createContextLoader()
        {
            return new ContextHierarchyLoader();
        }
    }
    Cheers,
    Last edited by robyn; May 14th, 2006 at 09:45 AM.
    Etienne

  2. #2
    Join Date
    Aug 2004
    Location
    Toronto, Canada
    Posts
    736

    Default

    Yes, you're doing it the right way. I've actually posted code to the mailing list a few times that is basically almost identical to yours, and the ejbtest integration test/sample contains a version:

    http://cvs.sourceforge.net/viewcvs.p....2&view=markup
    Colin Sampaleanu
    SpringSource - http://www.springsource.com

  3. #3
    Join Date
    Sep 2004
    Location
    Montreal
    Posts
    2

    Default

    Thanks for the reply! Any chance will see that piece of code integrated in the next Spring release?

    Cheers,
    Etienne

  4. #4
    Join Date
    Nov 2004
    Posts
    17

    Default

    You should check out Matt Raible's solution to this problem. It's much simpler and uses no custom code:

    http://www.jroller.com/page/raible?a...g_config_files

  5. #5
    Join Date
    Aug 2004
    Location
    Toronto, Canada
    Posts
    736

    Default

    Quote Originally Posted by cardsharp
    You should check out Matt Raible's solution to this problem. It's much simpler and uses no custom code:

    http://www.jroller.com/page/raible?a...g_config_files
    What Matt's post is showing is not a hierarchy of contexts though. It's just relying on the standard spring classpath*: prefix to load all fragments of the same name. That's great if this is good enough, but if you need a hierarchy that's something different...
    Colin Sampaleanu
    SpringSource - http://www.springsource.com

  6. #6

    Default

    As far as I can tell using classpath: in contextConfigLocation param like Matt Raible shows does not support the classpath*: directive or wildcard characters like applicationContext*.xml and does not allow you to use a beanRefFactory.xml. All of which I need.

    The solution proposed by E. Hardy is exactly what I am looking for. I had a similar implementation before I came across this post, but I could not get it to work. I tried the exact code posted and that doesn't work either. I get the following error while tomcat 5.5.9 is starting up:

    [java] SEVERE: Exception sending context initialized event to listener inst
    ance of class com.rjlg.commons.frmwrk.spring.SpringHelperContext LoaderListener
    [java] org.springframework.beans.FatalBeanException: Unable to load group d
    efinition. Group resource name [classpath:conf/spring/beanRefFactory.xml], facto
    ry key [beanFactory]; nested exception is org.springframework.beans.factory.Bean
    DefinitionStoreException: IOException parsing XML document from class path resou
    rce [conf/spring/beanRefFactory.xml]; nested exception is java.io.FileNotFoundEx
    ception: Could not open class path resource [conf/spring/beanRefFactory.xml]
    [java] org.springframework.beans.factory.BeanDefinitionSt oreException: IOEx
    ception parsing XML document from class path resource [conf/spring/beanRefFactor
    y.xml]; nested exception is java.io.FileNotFoundException: Could not open class
    path resource [conf/spring/beanRefFactory.xml]
    [java] java.io.FileNotFoundException: Could not open class path resource [c
    onf/spring/beanRefFactory.xml]


    There is a jar in WEB-INF/lib that has a conf/spring/beanRefFactory.xml. I can get the same code working in a standalone application.

    I'm using Spring 1.1.4.

  7. #7

    Default

    Actually, it works great. I have lots of problems getting log4j to initialize correctly when I redeploy to tomcat. It happened to initialize correctly on a deploy and I saw lots of spring log info that showed it was finding the conf/spring/beanRefFactory.xml. I was getting an error later on because I had removed the configContextLocation param from web.xml, so it was looking for /WEB-INF/applicationContext.xml by default and did not find one when it was doing the context initialization of the WebApplicationConext. You have to remember that this solution does not take the place of the WebApplicationConext initialization, it initializes a parent context of the WebApplicationContext using a beanRefFactory. Very nice.

    It has my vote for inclusion into the framework! It is very helpful for anyone that builds both web and standalone clients and uses shares spring enabled jars between them. I wrote a SpringHelper class that acts as a facade for spring initialization for my standalong clients. So now for the web apps I just make the custom ContextLoader delegate to it, so I'm use the same SpringHelper class to initialize standalone and web based applications!


    Thanks for the post E. Hardy!

  8. #8
    Join Date
    Aug 2004
    Location
    Toronto, Canada
    Posts
    736

    Default

    Just a note to anybody reading this thread that since Spring 1.1.4 ContextLoader has had support for loading a shared parent context which is done via the ContextSingletonBeanFactoryLocator mechanism. This is essentially the same code I pointed to before in this thread, but now it's built in.

    See the ContextLoader JavaDocs.
    Colin Sampaleanu
    SpringSource - http://www.springsource.com

  9. #9

    Default

    That was easy. Thanks.

    Did I miss this in the documentation or should I request that it be added to the docs?

  10. #10
    Join Date
    Aug 2004
    Location
    Toronto, Canada
    Posts
    736

    Default

    Yeah, this really should be documented in the bean chapter, around the section "Creating an ApplicationContext from a web application". Will add a Jira issue...
    Colin Sampaleanu
    SpringSource - http://www.springsource.com

Similar Threads

  1. Replies: 4
    Last Post: Jul 11th, 2005, 12:11 PM
  2. Stack Overflow
    By rayho222 in forum Container
    Replies: 6
    Last Post: May 17th, 2005, 03:42 AM
  3. Questioning the core component
    By Martin Kersten in forum Swing
    Replies: 6
    Last Post: Feb 21st, 2005, 03:45 AM
  4. Replies: 1
    Last Post: Nov 4th, 2004, 09:11 AM
  5. application startup time
    By davidedr in forum Data
    Replies: 1
    Last Post: Sep 1st, 2004, 04:06 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •