Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does class loading work when the same class exists in different applications on the same server?

I have multiple web-apps running on an app server and each web-app WAR file contains a copy of the same jar file.

Does this mean that a class in that jar file will be loaded multiple times in the JVM, once for each WAR file it exists in? Following on from that, if I have a static synchronized method in such a class, is it only synchronized among threads within the web-app it exists in but not synchronized against the same method in the same class in a different jar file in a different WAR file? (Hope the question makes sense, will clarify if necessary).

If this is the case I presume the best solution is to remove the jar file from each WAR file and deploy it to a shared classpath folder on the server?

like image 773
CodeClimber Avatar asked Nov 09 '10 10:11

CodeClimber


2 Answers

A Java classloader typically works by looking for classes in one or more places in a fixed sequence. For instance, the classloader that loads your application when you run it from the command line looks first in the rt.jar file (and others on the bootclasspath), and then in the directories and JAR files specified by your classpath.

A webapp classloading is similar in principle, but a bit more complicated in practice. For a particular webapp, a webapp's classloader looks for classes in the following order. For example Tomcat 6 looks for classes in this order:

  1. Bootstrap classes of your JVM
  2. System class loader classes (described here)
  3. /WEB-INF/classes of the webapp
  4. /WEB-INF/lib/*.jar of the webapp
  5. $CATALINA_HOME/lib
  6. $CATALINA_HOME/lib/*.jar

Of course, once the classloader has found the class it is looking for, it looks no further. So classes with the same name later in the order won't get loaded.

The complication is that the web container has one classloader for each webapp, and these classloaders delegate to other classloaders that manage the common classes. In practice, this means that some classes will only ever be loaded once for the entire container (e.g. 1. and 2.) and others may get loaded multiple times by different classloaders.

(When a class is loaded more than once, it results in distinct Class objects and distinct class statics. The versions of the class are different types as far as the JVM is concerned and you cannot typecast from one version to the other.)

Finally, Tomcat can be configure to allow individual webapps to be "hot loaded". This entails stopping a webapp, creating a new classloader for it, and restarting it.

FOLLOWUP

So ... synchronizing a static method will not protect access to a shared resource where the class has been loaded multiple times?

It depends on the details, but it probably won't. (Or to look at if another way, if a class has actually been loaded multiple times, then a static method of each "load" of the class will access a different set of static fields.)

If you really want a singleton application class instance to be shared by multiple webapps in the same container, it is simplest if you put the class into $CATALINA_HOME/lib or the equivalent. But you also should ask yourself if this is good system design. Consider combining the webapps, or to using request forwarding etc instead of a shared data structure. The singleton pattern tends to be troublesome in webapps, and this flavor is even more so.

like image 71
Stephen C Avatar answered Oct 24 '22 16:10

Stephen C


Java EE application servers typically use multiple classloaders to isolate applications from each other, and allow new versions of one application to be deployed without affecting other apps.

You get patterns such as several WAR files and one EJB file in an EAR with a hierarchy of classloaders, each WAR having it's own.

This does lead to duplication as you describe, but this is not necesserily a bad thing. It means that you can even have different versions of the same JARs deployed a the same time, and that may actually be benficial, allowing incremental migration to new versions.

Some application servers (WebSphere for exmaple) have explicit support for a shared library concept, and I do use that.

Be wary of just popping JARs into arbitrary classpaths, you run the risk of destabilising the app server itself.

like image 30
djna Avatar answered Oct 24 '22 15:10

djna