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.
Related
Why this error sometimes in deploy phase appens in Glassfish / Payara application server?
I can guess that the application server is trying to use two different classes of two different classloaders but is there a way to prevent it to do this behavior?
I tried to lookup some source online whitout finding nothing.
Edit : this happens on the same application in time of redeploy. It gets solved by a restart of the application server but obliviously this is not a solution
java.lang.ClassCastException: class com.MyClass cannot be cast to class com.MyClass (com.MyClass is in unnamed module of loader org.glassfish.web.loader.WebappClassLoader#1, com.MyClass is in unnamed module of loader org.glassfish.web.loader.WebappClassLoader#2)
Last Edit, after the great response of Stephen C.
What are the tools to undestand why Payara/GC doesn't destroy the old object?
I can guess that the application server is trying to use two different classes of two different classloaders but is there a way to prevent it to do this behavior?
Yes, that's what I think is happening. If identical .class files are loaded by different classloaders, the resulting runtime types are different and cannot by cast.
There are three ways to avoid this:
Don't pass or share these objects between different webapps.
Move the JARs that define the classes that need to be shared into the web container's shared library area ... so that they are loaded by the webcontainer's classloader rather than the webapp classloader(s).
If the classes need to be loaded by multiple webapp classloaders (e.g. because the have the same name but different implementations) you may need to rearchitect your application so that the classes implement a common interface that is loaded by a single classloader. If your webapp code then only casts to the shared interface, you won't run into this problem.
What if the web app is the same? (so when the application redeploy the same app)
If that is the case, then it sounds like the problem is that your webapp's shutdown code is not doing the right thing. Java objects created by the earlier deployment of the webapp are leaking into the later one.
Check that something is not caching application objects.
Check that application objects are not hiding in session state or thread-locals, or something like that.
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>
JNDI use Thread context class loader.
Because its guts are implemented by bootstrap classes in rt.jar
but core JNDI classes may load JNDI providers implemented by independent vendors and potentially deployed in the application's -classpath.
Father class loader can not use child class loader to load class.
Question :
As we all known parent delegation model is a important feature,
Why not using system class loader everywhere? Child class loader can use father class loader to load class.
I am not totally sure I understand your question.
Especially in JEE runtime environments the Context Classloader of your current thread is you best choice.
Essentially it all boils down to the hierachy (which may even be inverted or use something like OSGI somewhere) and the missing knowledge on where exatly in the classloader hiearchy you class is actually located.
Multiple classloaders in general are a necessity, because it is sometimes needed to have different versions of the same class, p.ex. in different applications running on the same JVM.
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>
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.