Friday, 11 February 2005

Adventures with class loaders

One problem that we have been discussing around work I wanted to share with everyone else at of a point of interest.

Lets make an example: you are a group that is hosting lots of J2EE applications. Some you have control over the source, some you don't. A lot of these apps will use common jars like log4j.

There are two things that you can do now:
1) put all the jars in a common location on the server
2) have each app including the required jars they need

Both setups have advantages and disadvantages. If you go with #1 then you have a common place for jars but you run into headaches when App A needs log4j version 1 and App B needs log4j version 2. This also means that you have to make sure that the server setups are exactly the same or apps will blow up if you move them from one server to another. The applications are no longer as atomic. And every time you want to change a shared jar, you have to do a full regression on all the apps that use it. And then you may not find the bugs at all until a weird case comes to the surface.

So you go with option #2 and have each app include what they need. Things are good, the sky is blue, the birds are singing, the applications depend less on the server setup and don't conflict. Now, of course there is a hitch: static classes.

Both App A and App B use log4j. App A uses an old version that has a org.apache.log4j.Constants class that has 2 static members in it. App B uses a version with 3 static members in it. You test both apps on developer workstations and everything is great. You load them to the server where they are both in the same JVM and everything is melts down.

With the class loader it checks if a static class is already loaded. If it is, then it doesn't bother to load them again. This means you are stuck with whatever version gets loaded first. Both versions may be incompatible with each other. The applications are no longer so atomic.

What's the solution to this? I don't really know what you could do other than putting the apps into different JVM's, but I'm still thinking about it. ;-)

Note: I don't know if there is a log4j constants class like that... I was just making one up.

2 comments:

  1. The server-side problem is definitely an interesting one.
    FYI, in Eclipse and Eclipse-based applications (like Rich Client Platform apps) each plugin has its own classloader. Each plugin (and thus classloader) could have it's own version of log4j loaded and they wouldn't interfere.
    The other neat thing about the Eclipse plugin classloaders is that you have control over class visibility. You might have a public class in a jar file in a plugin that classes in other plugins can compile to, but if you don't expose that class in the plugin settings (in plugin.xml, either explicitly by package or with a wildcard) none of the other plugins can use the compiled class at runtime.

    ReplyDelete
  2. Well if they are constants just use the one with 3 constants, or update the one with 2 constants so it has the three constants. If they are static but can be changed then there are going to be problems, because one application may change the value of the variables without the other application being aware.

    ReplyDelete