Recently I have been playing a lot with the new JBoss 4.0.x, Spring, and the like. As an excercise in learning, I have constructed a little "project" to build a Hash Generator (MD5, SHA, etc). This little project uses:
- Hibernate for persistance of data
- Spring for DI (dependency injection) and convenience classes
- JBossMQ for messaging from the code that generated the permutations of text to hash and the code doing that hashing
- GWT (Google Web Toolkit) for the purpose of learning GWT
I seem to have run into a snag recently, however: My complete and utter lack of understanding concerning Class Loaders. More specifically, my confusion as to why its not working how I intuitively think it should.
I come from a JBoss 3 world, which seemed to favor the "Unified" Class Loader. In those days, anyone could see anyone...total visibility of all classes across the board. This came with some problems, however, when two deployment units required different versions of the same library. Most of the time, you couldn't tell WHERE a class was comming from, or whether it was the one you thought you had.
Along comes JBoss 4 with its "Hierarchical" Class Loader. As a CS major, I am all to familiar with the term Hierarchical, and it conjurs visions of trees and such on mention. Intuitively, this is how I picture it working:
JBoss Libs (lib folder at root of JBoss) \ <server> Libs (lib folder under your server \ EAR (everything at root of EAR file) \ WAR (everything in WEB-INF/lib \ JAR etc EJB SAR
In this illustration, the WAR can see everything in his lib, plus have visibility up the hierarchy to see everything above it. The WAR would not have visibility accross to his siblings (EJB and SAR). This would be great, except for the fact this doesn't work. Let me illustrate why.
In my little project mentioned above, I have a library file that has my DAOs/VOs, long with the parent Spring context file. It gets placed at the root of the EAR along with all the supporting JARs from Spring and the WAR. In my mind, the WAR should now have visiblity to the DAO layer, since the DAOs are in the root of the EAR. When it ran, however, I found that the WAR could NOT see the Spring classes at all. I have to admit, I am new to EAR deployment, so I am trusting Maven to put the libs where it thinks it needs them.
To make matters worse, when I put the Spring JAR into the JBoss lib dir, it STILL didn't see it! I finally had to add the Spring JAR to the WAR's lib folder, which got past this hurdle.
The next problem is in the DAO layer. As I stated, I am using Spring, and inside the JAR containing the DOA/VO classes is a "parent" Spring context. When the WAR deploys, it uses the ContextLoaderListener in the web.xml to load the WAR's Spring context, using a classpath to a file. It also loads the parent context, also defined as a classpath to a file. When I deployed the DAO JAR into the server lib and the WAR solo, everything worked fine. But, with the DAO JAR in the root of the EAR along with the WAR, the ContextLoaderListener never finds the parent context, I.E. it can't find the file in the classpath. The thing is, the DAO JAR is designed to be a shared DAO library layer, so visibility across the EAR is important.
Once again, admittedly I am VERY weak on EAR deployment, which is one of the reasons I choose to do this. In my JBoss 3.x past, we simply deployed everything, WARs/JARs/SARs/etc, directly in the deploy dir of the server. We also loaded the servers lib folder with all libraries.
I call out to you, my JBoss brothers and sisters...help those like me that have no idea whats going on in the Class Loader. Help us to understand as best we can how this stuff is working.