Global singleton across all wars in tomcat [duplicate] - java

If I deploy and run 2 instances of same application on a single instance of Tomcat(Or any other server). Then a single object(of a Singleton class) would be created:
Across single instance of Tomcat (but common for 2 instances of same application) OR
Across application instance (different for 2 instances of application)
So essentially I want to understand that is it always a case that a single object of Singleton class gets created per JVM? How does this works in case of application hosted on a Web server(or container).

If you have a singleton class and you run two webapps that use this class in Tomcat both webapps will get 2 different instances of this singleton in JVM running the Tomcat.
But if your webapp will use a singleton from JRE or Tomcat shared libs, eg Runtime.getRuntime webapps will get the same instance of Runtime.
This is because Tomcat uses individual class loaders for webapps. When a webapp class loader loads a class it first tries to find it on webapp class path, if the class is not found it asks parent class loader to load the class.

A singleton is normally tied to a ClassLoader only.
So if you have a singleton based on a .class file in your .war file, and you deploy this web application multiple times, each application gets its own singleton.
On the other hand, if the .class file of your singleton is in the classpath of tomcat, then you only have one instance. This .class does not belong to a specific web application (it belongs to the tomcat instance).
If you have the singleton in both locations, it depends on the class loader hierarchy, and you can possibly select between "parent first" or "web application first".

It is possible to create such a singleton by assuring that you always query the same ClassLoader for the singleton. I wrote an extensive explanation in this other answer.

The Tomcat creates new class loader for each web application.
So if your Singleton class is stored in war file, the same war file will have two instances in Tomcat container i.e. it creates two separate Singleton class for each war file.
If the Singleton class is in Tomcat's share library path, Tomcat creates only one Singleton instance for the both application.
JVM analogy:
JVM is like big mansion. It contains combined family with serveral applicance and libraries.
ClassLoaders are family members, each family member represents one ClassLoader (works as delegate hierarchy not inheritance hierarchy). Note: ClassLoader is class, it can create multiple instances.
Applications are like appliance. for example: Washing Machine, Fridge, Air Cooler, Television, Dining table, Sofa and so on...
Libraries are each one having his own individual library. Every one search in parent's library if not found then search in his own library.
limitations:
If father buy an appliance their children can use it, but it can not used by his parent and siblings.
Each application might use different versions of the same libraries. i.e. If library contain two or more versions of same books, it picks whichever the book is available first.
Each family number can use only one unique appliance.
In home, we can use multiple appliance of same version. So, JVM allows us to run multiple applications of same versions.
Garbage Collector is a servant in Mansion, who roams as a daemon, who can clear any kind of Objects.
The scope of a static variable is limited to one per ClassLoader.

<shakey-ground>As far as I know, a singleton is unique per classloader. So I think the answer to your question depends on the way the container loads the web application.
If it allocates one classloader per web app, then it seems like you would get two, completely independent, singleton objects. If it allocates one classloader and all web apps use it, then they share the same singlet one instance.</shakey-ground>

Related

How Tomcat Classloader separates different Webapps object scope in same JVM?

Since Tomcat can load more than one webapp at once, and those webapps can work separately, and do not disturb each other, and they work in same JVM.
So I am very confused about how tomcat handle The Object scope in the same JVM.
For example I have a singleton object in both of the two different Webapps, and tomcat will generate two different singleton Object for each. I always thought that the singleton object have only one object in the same JVM, but in tomcat JVM there maybe has two or more.
I have read some info about the ClassLoader, Tomcat has its own WebAppClassLoader to load webapps. So does it mean the Object Scope here is the ClassLoader or am I wrong. Does anyone know about this or can give me some info about tomcat work memory layout?
All the secrets is behind those ClassLoader instances.
The state of the class (like all static variables, byte code and so on) is scoped by the class loader which loads that class (a class is identified in JVM by its fully qualiflied name and the class loader loading the class. This is not exactly a scope, but thinking as scope usually helps understanding this better).
So if a class is loaded by two different class loaders, this class exists twice within the VM, it has two sets of static fields, can have different byte code (like different method implementations) and all such. Note that these two objects cannot be cast to each other even their names are identical.
"Normal" Java applications have all classes loaded by a class loader hierarchy and every class is only loaded once.
For more complex scenarios, you will need different behaviours. Sometimes you want to isolate a library from messing with your code (like plugins in eclipse or web applications in an application server).
The basic idea to isolate your program from other classes is to load those with an extra class loader and use a lot of reflection. If you want to read up on this have a look at Oracle's documentation on ClassLoaders or OSGI.
Tomcat (and a lot of other web containers / application servers) load the application with separate ClassLoader hierarchies. This isolates all classes against other (web) applications and thus also makes sure, that singletons, different class versions and all this stuff does not collide.
Remember that a class in Java is identified by its fully qualified name and the classloader that loaded it. Tomcat uses separate classloaders for each context (web application) that you deploy, thus keeping them separate. In addition, the system classloader loads the tomcat specific libraries and JVM bootstrap loader load the Java core libraries.
In normal Java applications when a classloader is asked to load a class it forst delegates the request to it's parent class loader and then loads it if parent class loaders cannot find the requested class.
For web application servers this slightly differs. There are generally different class loader for each web app deployed in a web application server like tomcat. For Tomcat it looks like below -
So for web apps class loading resource happens in following order -
Bootstrap classes of your JVM (Core java classes)
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
System class loader classes (Tomcat / Classpath specific classes)
Common class loader classes (classes common to all web apps)
But note if web application class loader is configured with delegate="true" then order is changed -
Bootstrap classes of your JVM (Core java classes)
System class loader classes (Tomcat / Classpath specific classes)
Common class loader classes (classes common to all web apps)
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
For more details you can check Apache Tomcat's Class Loader HOW-TO page.
One thing that always gets left out when talking about singletons, is that a singleton can have only one instance per classloader. A ClassLoader limits class visibility, so the same class can exist under several different classloaders in the same VM. This allows you, among other things, to have different versions of jars loaded at the same time.
This question: Java Class Loaders seems to have some nice links and resources for further studying.
The "ID" of a class in the JVM consists of the fully qualified class name and the class loader that was used to load it. This means, if you load two classes with the same name by different class loaders they are considered different classes.
So a singleton would be singleton for a classloader - in a container/JVM; as a container/JVM might have multiple classloaders.
Different App in tomcat using different classloader to seperate. For example app1 using ClassLoaderA, app2 using classloaderB.
Each class will use its own classloader to load other classes. So if ClassA.class references ClassB.class then ClassB needs to be on the classpath of the classloader of ClassA, or its parents. For example In app1, com.exmaple.test1 loaded from ClassLoaderA. And com.exmaple.test1 want to new com.exmaple.test2(). By default It use its own classloader ClassLoaderA to load com.exmaple.test2. So In the view of com.exmaple.test1 it can only see its own classpath's class(app1/webapp/classes or app1/webapp/lib). And In app2, It will see a different view.
In summary learn classloader you must understand the delegation model. And the visibility is the child can see the parent. but the parent can not see the child and the sibling can not see the sibling. So we can isolate different app.

Singleton across JVM or Application instance or Tomcat instance

If I deploy and run 2 instances of same application on a single instance of Tomcat(Or any other server). Then a single object(of a Singleton class) would be created:
Across single instance of Tomcat (but common for 2 instances of same application) OR
Across application instance (different for 2 instances of application)
So essentially I want to understand that is it always a case that a single object of Singleton class gets created per JVM? How does this works in case of application hosted on a Web server(or container).
If you have a singleton class and you run two webapps that use this class in Tomcat both webapps will get 2 different instances of this singleton in JVM running the Tomcat.
But if your webapp will use a singleton from JRE or Tomcat shared libs, eg Runtime.getRuntime webapps will get the same instance of Runtime.
This is because Tomcat uses individual class loaders for webapps. When a webapp class loader loads a class it first tries to find it on webapp class path, if the class is not found it asks parent class loader to load the class.
A singleton is normally tied to a ClassLoader only.
So if you have a singleton based on a .class file in your .war file, and you deploy this web application multiple times, each application gets its own singleton.
On the other hand, if the .class file of your singleton is in the classpath of tomcat, then you only have one instance. This .class does not belong to a specific web application (it belongs to the tomcat instance).
If you have the singleton in both locations, it depends on the class loader hierarchy, and you can possibly select between "parent first" or "web application first".
It is possible to create such a singleton by assuring that you always query the same ClassLoader for the singleton. I wrote an extensive explanation in this other answer.
The Tomcat creates new class loader for each web application.
So if your Singleton class is stored in war file, the same war file will have two instances in Tomcat container i.e. it creates two separate Singleton class for each war file.
If the Singleton class is in Tomcat's share library path, Tomcat creates only one Singleton instance for the both application.
JVM analogy:
JVM is like big mansion. It contains combined family with serveral applicance and libraries.
ClassLoaders are family members, each family member represents one ClassLoader (works as delegate hierarchy not inheritance hierarchy). Note: ClassLoader is class, it can create multiple instances.
Applications are like appliance. for example: Washing Machine, Fridge, Air Cooler, Television, Dining table, Sofa and so on...
Libraries are each one having his own individual library. Every one search in parent's library if not found then search in his own library.
limitations:
If father buy an appliance their children can use it, but it can not used by his parent and siblings.
Each application might use different versions of the same libraries. i.e. If library contain two or more versions of same books, it picks whichever the book is available first.
Each family number can use only one unique appliance.
In home, we can use multiple appliance of same version. So, JVM allows us to run multiple applications of same versions.
Garbage Collector is a servant in Mansion, who roams as a daemon, who can clear any kind of Objects.
The scope of a static variable is limited to one per ClassLoader.
<shakey-ground>As far as I know, a singleton is unique per classloader. So I think the answer to your question depends on the way the container loads the web application.
If it allocates one classloader per web app, then it seems like you would get two, completely independent, singleton objects. If it allocates one classloader and all web apps use it, then they share the same singlet one instance.</shakey-ground>

Webapp classpaths and classes being loaded into heap

If I have two webapps, both of which have the same third party library jars in their web-inf/lib directories, say log4j.....when the first webapp is loaded and a log4j class is created, this class is loaded into the heap. When the second webapp is loaded and tries to load a log4j class, will it find the class in the heap and use that one? Or will it load its own copy of the class into the heap?
Hmm I think it is mostly a ClassLoader problem here, it still depend of the application server you are using, but I guess most of them use a single JVM and reserve a ClassLoader per running webapp so that you can have different webapp with different version of the same jar/clases running alltogether.
In tomcat for instance, if you need to have some shared libraries, you can use the /tomcat/shared/lib folder where you put all the jars that will be accessible by all your webapps.
Otherwise yes, different webapp won't share the same heap, it would mean webapp could access object created by other webapp running in the same application server
No, it shouldn't.
The fact classes are loaded on the heap mean nothing here. as each class loader maintains its own list of classes it loaded.
However, Classloaders are also organised into a tree and they are supposed to ask their parent classloaders to attempt to load the class first, as described in the javadoc of the ClassLoader class.
The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.
However, webservers typically don't follow this delegation model, to avoid libraries used by the webserver itself being picked up by webapps. (This behaviour is sometimes configurable, but it depends on the webserver you're using.)
So in practice every webapp should have its own separate class space, independent of all the other webapps, therefore they can even use two different versions of the same library without any problems.
The other important lesson is that the same class file loaded by two different class loader will actually be two separate classes in the heap and objects from one class will not be compatible with the other class.

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?
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:
Bootstrap classes of your JVM
System class loader classes (described here)
/WEB-INF/classes of the webapp
/WEB-INF/lib/*.jar of the webapp
$CATALINA_HOME/lib
$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.
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.
Most application server use most specific along a path takes precedence policy.
If you have multiple library that do the same thing, You should consider to put them inside application server lib (f.e: TOMCAT_HOME/lib)

Do servlet containers prevent web applications from causing each other interference and how do they do it?

I know that a servlet container, such as Apache Tomcat, runs in a single instance of the JVM, which means all of its servlets will run in the same process.
I also know that the architecture of the servlet container means each web application exists in its own context, which suggests it is isolated from other web applications.
As depicted here:
Accepting that each web application is isolated, I would expect that you could create 2 copies of an identical web application, change the names and context paths of each (as well as any other relevant configuration), and run them in parallel without one affecting the other. The answers to this question appear to support this view.
However, a colleague disagrees based on their experience of attempting just that.
They took a web application and tried to run 2 separate instances (with different names etc) in the same servlet container and experienced issues with the 2 instances conflicting (I'm unable to elaborate more as I wasn't involved in that work).
Based on this, they argue that since the web applications run in the same process space, they can't be isolated and things such as class attributes would end up being inadvertently shared. This answer appears to suggest the same thing
The two views don't seem to be compatible, so I ask you:
Do servlet containers prevent web applications deployed to the same container from conflicting with each other?
If yes, How do they do this?
If no, Why does interference occur?
and finally, Under what circumstances could separate web applications conflict and cause each other interference?, perhaps scenarios involving resources on the file system, native code, or database connections?
The short answer is that the servlet container isolates the applications by using a separate classloader for each application - classes loaded by separate classloaders (even when from the same physical class files) are distinct from each other. However, classloaders share a common parent classloader and the container may provide a number of other container-wide resources, so the applications are not completely isolated from each other.
For example, if two applications share some common code by each including the same jar in their war, then each application will load their own instance of the classes from the jar and a static variable (e.g. a singleton) of a class in one application will be distinct from the static variable of the same class in the other application.
Now, take for example, that the applications try to use java.util.Logger (and presumably don't include their own instance of the Logger classes in their war files). Each application's own classloader will not find the class in the war file, so they will defer to their parent classloader, which is probably the shared, container-wide classloader. The parent classloader will load the Logger class and both applications will then be sharing the same Logger class.
Servlets in the same container will share some resources. I think it should be possible to deploy the same web application twice in the same container provided that you give each a different name and they don't collide on a particular resource. This would theoretically be the same as deploying two different servlets which just happen to have the same implementation, which we do all the time.
Some shared resources, off the top of my head (and I'm not an expert so don't quote any of this!):
Libraries (jars) in tomcat/common/lib (Tomcat 5) or tomcat/lib (Tomcat 6).
Settings in the global server.xml, web.xml, tomcat-users.xml
OS provided things, such as stdin/stdout/stderr, network sockets, devices, files, etc.
The logging system.
Java system properties (System.getProperty(), System.setProperty())
I suspect... static variables? I'm not sure if the ClassLoader design would prevent this or not.
Memory. This is the most common problem: one servlet can deny others availability by consuming all memory.
CPU - especially with multi-threaded apps. On the HotSpot JVM, each Java thread is actually an OS-level thread, which are expensive and you don't want more than a few thousand of them.
Doubtless there are more.
Many of these things are protected by a security manager, if you're using one.
I believe the isolation is in the class loader. Even if two applications use the same class name and package, their class loader will load the one deployed with the application.

Categories

Resources