Announcement Announcement Module
No announcement yet.
Classloader issue with Spring and Websphere? Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Classloader issue with Spring and Websphere?

    I am very new to Spring but so far I have been really impressed. To get my feet wet I wanted to replace the EJB layer of one of my Struts based web applications with Spring and Hibernate. I created new java beans to represent my old entity beans, DAO beans to implement my finders and some new business java beans to represent my old session beans. This stuff works great when I use just a standard Java application to create the context. My problem is with my web app. While the Spring context is initializing it can't find any of my DAO and buisiness logic beans. These beans are in seperate jar files from my web teir. To make jars like this accessible to a web app I usually place them in the top directory of an ear file allong with the war file for the web app.

    Unfortunatly by doing this the context can't find the classes when it is instantiating itself. Of course this sounded like a classloader problem so to test this I droped my DAO and business jars into the WEB-INF/lib dir of my project. Of course everything worked when I did this.

    Unfortunatly this is not a solution for me. WSAD is very restrictive in the way it likes to build and package projects. For this to work I would have to be exporting my DAO jars from WASD and importing them into the WEB-INF/lib dir of my web project for every change I made. I don't mind placing third pary jars their but I don't like to place my own jars that are generated from othe projects in my workspace. The way WSAD wants you to do this is to use the project utility aproach in the EAR file. If I do it this way WSAD will automate the whole process.

    So... Anyone else out there using WSAD and Websphere server have this working? I'm not too up on classloaders but I think if there is someway I can get Spring to use the same class loader as the Websphere server I should be fine.

    Oh. and to get the whole context up and going I am using the Struts Plugin provided in the Spring jar.


  • #2
    This approach should work as long as you:
    - Added the utility projects to the Java Jar Dependency List (in the web project's manifest, as well as the EJB Project). May not actually be neccessary, but won't hurt either.
    - you aren't asking spring to load some class that is sitting in the web project.

    BTW, The utility jar approach also works with the web project (at least it does in WSAD5.1.1). If you go to the properties on the web project you can specify "Web Library Projects" (something like that...don't have it handy). This will work like the Utilty Projects for the EAR, but the "Utility Project" will be packaged and placed under WEB-INF/lib instead of at the top level of the ear. I prefer to use this approach whenever possible.

    If you DO need spring to load some code that is sitting in the web project, you could probably get by with:

    - Reference your shared libraries (any of YOUR projects used by the EJB and WEB project) as a utility project in the EAR
    - Add the projects as java jar dependencies in the EJB and web projects
    - Drop the spring.jar (and probably aopalliance.jar) in both WEB-INF/lib and the top level of the EAR
    - Set the classloader policy for the WEB project to PARENT LAST (so it picks up your version of spring.jar before the one in the EAR)

    One of my projects uses this layout. This way when the EJB project needs spring stuff, it gets the one from the EAR (which CANNOT see the code inside the web app but can see code in the shared projects) and when the WEB project needs spring stuff, it gets the one in WEB-INF/lib (which CAN see stuff in the web app as well as code in the shared projects).

    Of course it is rather painful to have the jar in 2 places...If you didn't have the EJB project you could just make everything a WEB Library Project reference, drop all the other jars in WEB-INF/lib and be done with it.


    • #3
      To switch the classloader policy, open up the server configuration, and go to the 'Applications' tab. Expand the ear and click on the web project, then select PARENT_LAST from the drop-down to the right.


      • #4
        Thanks a bunch James!

        I ended up using the web library method because I replaced all my EJBs with hibernate and JavaBeans.

        Thanks for all the info on the class loaders as well. I always wondered what those settings meant. Now I know.


        • #5
          I encountered a similar issue. I am using Struts with Spring on WSAD 5.1.2, and I got the following exception. I cannot change the loading policy because of the company development environment. I have my struts.jar under WEB-INF/lib and my spring.jar under EAR's global /lib directory. Can somebody please tell me what is wrong?

          [12/5/05 12:31:32:364 EST] 3db37f03 ServletInstan E SRVE0100E: Did not realize init() exception thrown by servlet action: javax.servlet.ServletException: Error while defining class: org.springframework.web.struts.ContextLoaderPlugIn
          This error indicates that the class: org.apache.struts.action.PlugIn
          could not be located while defining the class: org.springframework.web.struts.ContextLoaderPlugIn
          This is often caused by having the class at a higher point in the classloader hierarchy
          Dumping the current context classloader hierarchy:
          ==> indicates defining classloader
          *** indicates classloader where the missing class could have been found
          [email protected] 1
          Local ClassPath: C:\src\Test\TestWAR\WebContent\WEB-INF\classes;C:\src\Test\TestWAR\WebContent\WEB-INF\lib\commons-beanutils.jar;C:\src\Test\TestWAR\WebContent\WEB-INF\lib\commons-collections.jar;C:\src\Test\TestWAR\WebContent\WEB-INF\lib\commons-digester.jar;C:\src\Test\TestWAR\WebContent\WEB-INF\lib\commons-fileupload.jar;C:\src\Test\TestWAR\WebContent\WEB-INF\lib\commons-lang.jar;C:\src\Test\TestWAR\WebContent\WEB-INF\lib\commons-logging.jar;C:\src\Test\TestWAR\WebContent\WEB-INF\lib\commons-validator.jar;C:\src\Test\TestWAR\WebContent\WEB-INF\lib\jakarta-oro.jar;C:\src\Test\TestWAR\WebContent\WEB-INF\lib\jaxen-full.jar;C:\src\Test\TestWAR\WebContent\WEB-INF\lib\jstl.jar;C:\src\Test\TestWAR\WebContent\WE B-INF\lib\saxpath.jar;C:\src\Test\TestWAR\WebContent \WEB-INF\lib\standard.jar;C:\src\Test\TestWAR\WebConten t\WEB-INF\lib\struts.jar;C:\src\Test\TestJAR\classes;C:\ src\Test\TestWAR\WebContent;
          Delegation Mode: PARENT_FIRST
          ==>[1] [email protected] Local Classpath: C:\src\Test\TestEAR\lib\spring.jar Delegation mode: PARENT_FIRST
          [2] [email protected] 6 Local ClassPath: C:\Program Files\IBM\WebSphere Studio\Application Developer\v5.1.2\runtimes\base_v51\lib\app; Delegation Mode: PARENT_LAST
          [3] [email protected] f03
          [4] [email protected]
          [5] [email protected]
          [6] [email protected]
          ---Original exception---
          java.lang.NoClassDefFoundError: org/apache/struts/action/PlugIn
          at java.lang.ClassLoader.defineClass0(Native Method)
          at java.lang.ClassLoader.defineClass( (Compiled Code))
          at Code))
          at Class(
          at ss( Code))
          at ss(
          at java.lang.ClassLoader.loadClass( ompiled Code))
          at lass(
          at ss(
          at java.lang.ClassLoader.loadClass( ompiled Code))
          at org.apache.struts.util.RequestUtils.applicationCla ss(
          at org.apache.struts.util.RequestUtils.applicationIns tance(
          at org.apache.struts.action.ActionServlet.initModuleP lugIns(
          at org.apache.struts.action.ActionServlet.init(Action
          at javax.servlet.GenericServlet.init(GenericServlet.j ava:258)
          at nce.doInit(
          at vlet._init(
          at letState.init(
          at vlet.init(
          at it(
          at javax.servlet.GenericServlet.init(GenericServlet.j ava:258)
          at r.addServlet(
          at r.loadServlet(
          at r.loadAutoLoadServlets( 42)
          at anager(
          at java:283)
          at .java:209)
          at tion(
          at all(
          at t(
          at art(
          at pl.fireDeployedObjectStart(DeployedApplicationImpl .java:808)
          at art(
          at pl.start(
          at artApplication(
          at art(
          at mponents(
          at .start(
          at mponents(
          at 8)
          at )
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(Native
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(De
          at java.lang.reflect.Method.invoke(
          at va:105)
          at nnerV5$


          • #6
            I got it worked. I put struts.jar and spring.jar both under WEB-INF/lib. It did not work before because I have spring.jar under both EAR/lib and WEB-INF/lib.


            • #7
              don't use monolithic spring.jar

              You don't have to use the monolithic spring.jar . You might be better of structuring your EAR by using the modular spring-xxx jars.
              Saved me a couple of times having to move utility jars and spring into the web module. Just copy only the spring-web*.jar into the web-inf/lib and the rest of spring (depends on what you need) into the toplevel ear.
              If done this way one can achieve succes WITHOUT duplicate jars.

              Setup up j2ee module depencies ( in case you need toplevel ear stuff from the webmodule.


              Faizal Abdoelrahman