Announcement Announcement Module
Collapse
No announcement yet.
Loading context from custom classloader Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Loading context from custom classloader

    I have a Spring-based application distributed in one or more jar files. Context file(s) are packaged inside of the jars.

    I need to dynamically load the contexts defined there from another application at runtime. I constructed a UrlClassLoader using the jars and use this classloader to create new instance of ClasspathXmlApplicationContext:
    Code:
    		
    loader = getClassLoader();
    Class contextClass = Class.forName(ClassPathXmlApplicationContext.class
    				.getName(), true, loader);
    		Constructor constructor = contextClass
    				.getConstructor(new Class[] { String[].class });
    		context = (ClassPathXmlApplicationContext) constructor.newInstance(new Object[] { new String[] {
    "com/path/to/my/spring-context.xml"} } );
    The problem is that context cannot be found. It appears that ClasspathxmlApplicationContext does not even look at resources defined by my custom classloader.

    Spring documentation indicates that there is a setClassLoader method available in this type of context but in fact there is not one.

    How should I handle this situation?
    TIA

  • #2
    javadoc for : org.springframework.context.support.ClassPathXmlAp plicationContext
    Methods inherited from class org.springframework.core.io.DefaultResourceLoader
    getClassLoader, getResource, getResourceByPath, setClassLoader

    Comment


    • #3
      yes I can read Javadoc, that is what I meant by "Spring Documentation" ;-)
      The DefaultResourceLoader does NOT have the setter method Javadoc says it does.

      Plus it would not help anyway because context object is already constructed.

      Comment


      • #4
        the DefaultResourceLoader does NOT have the setter method Javadoc says it does.
        From my source code of Spring (1.2.4):

        Code:
        public class DefaultResourceLoader implements ResourceLoader {
        
        	private ClassLoader classLoader;
        
        
        	/**
        	 * Create a new DefaultResourceLoader.
        	 * <p>ClassLoader access will happen via the thread context class loader on actual
        	 * access &#40;applying to the thread that does ClassPathResource calls&#41;.
        	 * @see java.lang.Thread#getContextClassLoader&#40;&#41;
        	 */
        	public DefaultResourceLoader&#40;&#41; &#123;
        	&#125;
        
        	/**
        	 * Create a new DefaultResourceLoader.
        	 * @param classLoader the ClassLoader to load class path resources with,
        	 * or null if using the thread context class loader on actual access
        	 * &#40;applying to the thread that does ClassPathResource calls&#41;
        	 */
        	public DefaultResourceLoader&#40;ClassLoader classLoader&#41; &#123;
        		this.classLoader = classLoader;
        	&#125;
        
        
        	/**
        	 * Specify the ClassLoader to load class path resources with,
        	 * or null if using the thread context class loader on actual access
        	 * &#40;applying to the thread that does ClassPathResource calls&#41;.
        	 * <p>The default is that ClassLoader access will happen via the thread
        	 * context class loader on actual access &#40;applying to the thread that
        	 * does ClassPathResource calls&#41;.
        	 */
        	public void setClassLoader&#40;ClassLoader classLoader&#41; &#123;
        		this.classLoader = classLoader;
        	&#125;
        Look at the ClassPathXmlApplicationContext and it's ancesters code:
        (from AbstractXmlApplicationContext)
        Code:
           /**
        	 * Loads the bean definitions via an XmlBeanDefinitionReader.
        	 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
        	 * @see #initBeanDefinitionReader
        	 * @see #loadBeanDefinitions
        	 */
        	protected void loadBeanDefinitions&#40;DefaultListableBeanFactory beanFactory&#41; throws IOException &#123;
        ...
        		// Configure the bean definition reader with this context's
        
        		// resource loading environment.
        		beanDefinitionReader.setResourceLoader&#40;this&#41;;
        		if &#40;getClassLoader&#40;&#41; != null&#41; &#123;
        			beanDefinitionReader.setBeanClassLoader&#40;getClassLoader&#40;&#41;&#41;;
        		&#125;
        ...
        	&#125;

        Comment


        • #5
          I am using 1.2.3 and it does not have that.

          Nevermind, because I figured it out. Spring apperantly uses the classloader context of the thread initiating the Spring context to find resources. So I just re-wrote my piece as:

          Code:
          		loader = getClassLoader&#40;&#41;;
          		Thread.currentThread&#40;&#41;.setContextClassLoader&#40;loader&#41;;
          		context = new ClassPathXmlApplicationContext&#40;new String&#91;&#93; &#123;
          "com/my/path/context.xml"
          				&#125;&#41;;
          and it works just fine.

          Thanks again, Spring developers, very elegant.

          Comment


          • #6
            Code:
                  loader = getClassLoader&#40;&#41;; 
                  Thread.currentThread&#40;&#41;.setContextClassLoader&#40;loader&#41;; 
                  context = new ClassPathXmlApplicationContext&#40;new String&#91;&#93; &#123; 
            "com/my/path/context.xml" 
                        &#125;&#41;;
            and it works just fine.

            Thanks again, Spring developers, very elegant.
            It looks like setClassLoader() was added for this exactly (or related) tasks in the 1.2.4. It'd be probably much better to switch to 1.2.5 and use it. Playing with context classloader is rather dangerous and not portable. Besides having to worry about reinstating old TCCL you might also run into issues with security manager.

            Comment


            • #7
              It looks like setClassLoader() was added for this exactly (or related) tasks in the 1.2.4. It'd be probably much better to switch to 1.2.5 and use it. Playing with context classloader is rather dangerous and not portable. Besides having to worry about reinstating old TCCL you might also run into issues with security manager.
              I second dvoytenko reply. It's better to use the official classloader setter (thus upgrading the spring library) then fool around with TCCL - especially inside a container (tomcat or a full AS) you might have some really wierd problems which are mainly caused by the CL.

              Comment

              Working...
              X