1
votes

I'm having problems deploying a Spring web app to Tomcat 6.0. I want to deploy some jars to the shared/lib (catalina.properties is correctly configured); these jars contain various bean definitions. The main application, deployed to the webapps directory, uses:

<import resource="classpath*:com/**/*.xml"/>

to pick up the bean definitions in the jars deployed to shared/lib.

Some of the beans deployed to shared/lib have been updated and now implement the MessageSourceAware interface; when the app now starts, I get the following error:

Caused by: java.lang.NoClassDefFoundError: org/springframework/context/MessageSourceAware
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
    at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1667)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
    at org.springframework.util.ClassUtils.forName(ClassUtils.java:257)
    at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:408)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1282)
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1253)
    ... 72 more
Caused by: java.lang.ClassNotFoundException: org.springframework.context.MessageSourceAware
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    ... 89 more

If the jars are moved from shared/lib to the WEB-INF/lib directory of the app, obviously everything works OK, but I'd like to keep the jars in shared/lib if at all possible.

This looks like a classloader issue, but hasn't the spring-context.jar in WEB-INF/lib already been loaded by the time Spring tries to create the beans in the shared/lib jars?

I'm confused; any help would be much appreciated.

3

3 Answers

1
votes

Add jar file that contains org.springframework.context.MessageSourceAware to the Classpath. If you are using Eclipse(I assume you are) Right click on project and click on Build Path. And add corresponding jar file to classpath.

1
votes

Realised in the end that the shared/lib folder is exactly the wrong place to put these extension jars, owing to the hierarchical nature of the classloaders in Tomcat.

Instead, I wrote my own class loader that extends Tomcat's WebappClassLoader:

public class CustomWebappClassLoader extends WebappClassLoader {

    public CustomWebappClassLoader() {
        super();
        addCustomRepository();
    }

    public CustomWebappClassLoader(ClassLoader parent) {
        super(parent);
        addCustomRepository();
    }

    private void addCustomRepository() {
        String catalinaHome = System.getProperty("catalina.home");
        File dir = new File(catalinaHome, String.format("extensions%slib", File.separator));
        for (File file : dir.listFiles()) {
            if (file.getName().endsWith(".jar")) {
                String repository = String.format("file:/%s", file.getAbsolutePath());
                addRepository(repository);
            }
        }
    }
}

This adds any jars in %CATALINA_HOME%/extensions/lib to the classpath (along with WEB-INF/classes and WEB-INF/lib for the application).

The following line is then needed in context.xml:

<Loader loaderClass="com.test.CustomWebappClassLoader" delegate="true"/>
0
votes

You will need to include the spring-context-x.y.z.jar in your project WEB-INF/lib folder or in your TOMCAT_HOME/lib folder (where x, y, z is the version number).