 |
Classloading in J2EE Applications
Posted by javaben on June 17, 2005 at 09:40 AM | Comments (13)
I've spent the last two or three years doing a large amount of client-side Java development. In that world, there are a number of techniques for partitioning the various JARs that compose the application into distinct class loader domains.
For example, using the Eclipse RCP, you can define your application as a set of plug-ins and define exactly which JARs *other* plug-ins can see.
Consider the following scenario: I have two frameworks, Foo and Bar. Framework Foo depends on a library called Commons-Sniping 1.0, and Framework Bar depends on a different version of the same library (Commons-Sniping 3.2). Version 3.2 breaks a bunch of 1.0 APIs and introduces its own new stuff.
Having Foo, Bar, and both versions of Commons-Sniping exist in the same class loader domain is foolish with a capital F. Weird, exotic, and fun errors can and will occur at run-time. So, you make Foo and Bar plug-ins, and define that those plug-ins only expose the Foo and Bar API. As a result, only Foo can see Commons-Sniping 1.0, and only Bar can see Commons-Sniping 3.2. And, things are good.
So, the other day I had this problem in the context of a web application. Two frameworks relied on different versions of the same library, and versions were different by a major version (e.g., 2.x and 3.x). So, uh, what do I do?
I asked several J2EE developer friends whom I respect. And the answers I got from all were, "Uh, choose the latest version and hope for the best." Hmm...
Is this really the state-of-the-art for J2EE development? Do some app servers provide class loader partitioning services to web applications? Or do I have to do my own integration with one of the third-party plug-in engines out there? Or, do you just rely on libraries to not ever be backwards incompatible? How do you solve this problem?
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
You might want to check out http://jarjar.sf.net/
Posted by: herbyderby on June 17, 2005 at 10:48 AM
-
herbyderby: heh... that's a clever hack. Jar Jar Links allows you to specify classes to bulk rename and rewrites class files using bytecode manipulation to reference renamed versions.
Certainly solves the conflict issue, but does it also have the side-effect of allowing you to prevent unintended dependencies of libraries of frameworks that aren't part of the framework's public API? That wasn't the main focus of my blog entry, but its a great side-effect of partioned class loaders...
Posted by: javaben on June 17, 2005 at 11:01 AM
-
Ben, technically you can deploy different frameworks within its own ears and expose your own fasades for these features (like service access points). However in some cases it would be an overkill, because you can't use local interfaces and this is definetely not the option for servlet-only containers, such as Tomkat.
Besides that most if not all J2EE containers (WebLogic, JBoss...) has its own way to configure class loading hierarchy.
Posted by: euxx on June 17, 2005 at 11:46 AM
-
euxx: Solving the problem through remoting? Err... no thanks. I did figure that individual app servers provide proprietary mechanisms, good to hear that its true. Do many folks use them?
Posted by: javaben on June 17, 2005 at 11:53 AM
-
I suspect that you could probably utilization the dependencies functionality in jar manifests to accomplish this versioning as well. Given the original example above, take the following steps:
Place the two versions of commons-sniping in jars commons_sniping_1_0.jar and commons_sniping_3_2.jar
Package Framework Foo in jar foo.jar
Package Framework Bar in bar.jar
Add a Class-Path entry containing commons_sniping_1_0.jar to MANIFEST.MF in foo.jar
Add a Class-Path entry containing commons_sniping_3_2.jar to MANIFEST.MF in bar.jar
Of course, you'll need to try this out in whatever container you're using, as most implement their own classloaders and behavior may vary.
Posted by: adbrowning on June 18, 2005 at 08:04 PM
-
You can also write your own ClassLoaders, as shown in the article: Internals of Java Class Loading
Posted by: binildas on June 20, 2005 at 07:20 AM
-
adbrowning: That's an interesting idea. You'd have to put the dependent JARs outside of the WEB-INF/lib directory to prevent the default webapp class loader from seeing them. I wonder how effective this technique would prove to be.
binildas: Yup, I've done that a few times. Certainly you can solve this problem by architecting your own class loading strategy, but my point was, "This seems like a common problem; how do folks typically solve it?" Writing a custom class loader seems a bit heavyweight IMO...
Posted by: javaben on June 20, 2005 at 08:00 AM
-
Yeah. I agree. We need to have a simpler solution, perhaps at the framework or specification level itself - Something similar to "side by side" execution in .NET. Or at least some way by which we can tweak the existing Java/J2EE infrastructure to achieve the result.
Posted by: binildas on June 20, 2005 at 08:22 AM
-
binildas: JSR-277 is the long-term solution, I think, but for the short term... I guess using a proprietary app server feature where available or using one of the java plug-in frameworks (or, as a last resort, writing custom class loaders). Interesting...
Posted by: javaben on June 20, 2005 at 08:28 AM
-
I'm unclear on the goals of JSR-277. Half the people think its RPM, the other half think its OSGi. Or is it both?
Posted by: jsando on June 20, 2005 at 12:59 PM
-
jsando: I don't think the construction of an RPM/Maven style repository is at all what the JSR-277 folks have in mind, but I could be wrong. In either case, I think the core focus is to provide a new library distribution mechanism that leapfrogs the .NET assembly stuff (which leapfrogged the current JAR mechanism). The issues I describe in this blog certainly motivate the creation of JSR-277.
Posted by: javaben on June 20, 2005 at 01:22 PM
-
Borland app server has web app partitioning feature and would solve your problem just right! I am not aware if other app servers have this feature.
Posted by: vijayphadke on June 20, 2005 at 10:13 PM
-
vijayphadke: Very cool, thanks for the tip!
Posted by: javaben on June 20, 2005 at 10:19 PM
|