What is an isolated classloader in Java? - java

When trying to solve this problem, I encountered some articles, etc. referring to "isolated" ClassLoaders. I was unable to find a definition for isolated classloader via Google search, so maybe the term is not widely-known jargon, and perhaps has a different meaning in different contexts.
Anyway, Maven's surefire plugin can use an isolated ClassLoader: http://maven.apache.org/plugins/maven-surefire-plugin/examples/class-loading.html
Also one of the answers below references an article explaining how to create an "isolated" ClassLoader.
Neither reference above gives a definition for an isolated ClassLoader; they seem to assume the reader knows what that means or can look it up. However, the second link does include a hint as to what it means by "isolated":
Bootstrapping lets you run your container without polluting the system classpath. This allows you to run your deployed applications with the unpolluted system classpath as its parent. You’ve achieved classloader isolation.
But I'm not quite clear on what is isolated from what and how from this paragraph or the rest of the article. I see that he's loading one version of a class w/o overriding / overwriting another version--maybe one classloader is isolated from another by being different instances w/o one being the parent of the other? I'm not sure.
I especially covet a Google or SO search link that contains a link clearly holding the answer. A direct link to an answer works too. :)

The author is using the term "isolation" basically to mean that the bootstrap classloader for the JVM (the "main" classloader) doesn't have any extra jars/classes in it (just one simple class which in turn sets up the child classloader(s)). The article isn't real obvious as to why this is "isolated" because it only sets up one child classloader. The "isolation" term becomes more obvious when you setup more than one child classloader. These children will be isolated from each other in that they won't share any classes (other than the core JRE classes). Thus, you can do things like have each child use a different version of the same jar.

Here's how to create an isolated classloader, you'd create one any time you want an unpolluted system classpath, useful for bootstrapping Java programs.

From my understanding from the article that you linked to that an isolated class loader is a class loader that is separate to the main system class loader. That is, classes loaded by the isolated class loader won't be available to every class in JRE (only the ones that the isolated class loader loaded itself [and any classes loaded by any child class loaders]).
This could be useful because two of your dependencies might require different versions of the same library to run. That is, your dependencies might expect to see different instantiations of the same class in the library. Thus giving them two separate isolated class loaders will allow them to load the classes they require and not interfere with each other.

By default classloaders form a tree with the system classloader at the root. New child classloaders will by default ask their parent first if it can load the class, and if not, load from their own sources.
The goal of an isolated classloader is to isolate yourself from the parent classloaders by checking your own sources FIRST, then your parent SECOND, so reversing the order. This allows you to create a new classloading context where you control the first place to look. You still want to fallback to the parent chain so you can load things like the jdk etc.
You also need to take care that the isolated classloader return instances of interfaces defined in the parent classloader, or else you will run into LinkageErrors or other issues.
Here's an article I wrote in 2006, but it's still fairly relevant (it's incomplete with respect to resource loading and the apis have changed a bit over the years):
http://tech.puredanger.com/2006/11/09/classloader/

Related

Java 9 overlapping non-exported packages

Various resources (infoq, jigsaw-dev, osdir) indicate that having the same package in different java modules will lead to a LayerInstantiationException, even when the packages are internal to the module (non-exported).
This seems to be the exact opposite of what the requirements say :
The Java compiler, virtual machine, and run-time system must ensure that modules that contain packages of the same name do not interfere with each other. If two distinct modules contain packages of the same name then, from the perspective of each module, all of the types and members in that package are defined only by that module.
So are (will) two modules used by an app be able to contain private packages of the same name ?
EDIT
This is an issue of JMPS as pointed by Stanislav Lukyanov
As said in the discussions you've linked, the issue is about mapping between class loaders and modules.
When you're loading two modules M1 and M2 both containing a non-exported (a.k.a. concealed) package P via a class loader CL JPMS has to reject such configuration, since otherwise both key JPMS principles - strong encapsulation and reliable configuration - could be broken. By throwing an exception here JPMS actually implements the requirement you've quoted and ensures that no conflicts may break anything later during the execution.
On the other hand, when you're loading M1 and M2 via two loaders CL1 and CL2 you're actually creating two run-time packages {CL1, P} and {CL2, P}, so there is no collision and the Layer can be instantiated.
The usability problem here is that java uses single loader for all modules of the application layer (the "starting" one, created from the command-line arguments) which leads to the LayerInstantiationException. That's currently an open issue on the JPMS list, see [here] (http://openjdk.java.net/projects/jigsaw/spec/issues/#AvoidConcealedPackageConflicts). But regardless of the issue's resolution, if needed, you should be able to deal with the split packages by writing a tiny main class that will create the Configuration you need (BTW a JPMS-aware application container will probably do it for you).
This definition is open to interpretation. It remains correct as Jigsaw ensures that two modules never define shared packages by crashing the class loading in case of such a conflict.
If you look into Java 9's class loader implementation, you can see that a package name is mapped by to a single module. Its therefore impossible two have two modules to declare ownership. It is however possible that two class loaders in child-parent relationship define the same package.

use of fragments over plugin

In my project, I could see all the JUnit Test cases are written
in eclipse fragments not in eclipse plugin. And we do run each test classes
as JUnit plugin. I am not very much
clear about the concepts. I am relatively new to this concept.
I just googled to get better knowledge about using fragments over Plugins for Tests.
What I have understood is, fragments and host plugins share the
same class loader.Please correct me if my understanding is wrong.
However I did not understand the meaning of the below line.
If we create the tests in eclipse plugin, test classes will be loaded by a separate Classloader and will therefore not have access to the non-public methods of the classes under test.
Why it does not have access to the non-public methods? can any one help me in understanding the meaning of the above with simple example?
To understand this you need to understand how classes and classloading actually works in Java. Often we think of loading in terms of 'the classpath', but this is a massive simplification of how things work. In many Java SE envrionments this just works, but in multi-tenanted environments like OSGi it gets more complicated.
Essentially in Java classes are scoped by three things:
Name
Package
ClassLoader
It is perfectly possible to have two instances of myPackage.MyClass loaded in the JVM at more than once, you just need multiple classloaders. Even though these classes could be loaded from identical .class files they will be different at runtime. This can cause much confusion when you write code like this:
MyClass c = (MyClass)obj;
and get a ClassNotFoundException: MyClass.
Classes exist in packages and there are special visibility rules associated with this. Types, methods and fields with no stated visibility are visible to all types in the same package. When a class is loaded it gets associated with a java.lang.reflect.Package and the visibility rules are resolved by essentially checking that the classes are associated with the same java.lang.reflect.Package instance. So in the case of mypackage.MyClass if you load it twice using two different classloaders you will get two Package instances for mypackage.
OSGi is designed to support multi-tenanted class loading, this is what allows you to have two different versions of a class or package in the same JVM at once. This solve many problems caused if you have different version dependencies. It implements this by using a different Classloader for each bundle. Fragments work differently that bundles in that they are associated with a bundle and classes in them are loaded by the bundle's Classloader rather than having their own one.
To relate this back to your original question if you put your junit tests in a bundle (rather than a fragment) your class will be loaded by a different classloader, so it'll be associated with a different instance of java.lang.reflect.Package so when the JVM tests for member accessability it will fail.

Sandboxed or walled classloader to separate application from runtime environment

Web applications for Tomcat are wrapped into a .war file and thrown into Tomcat. The application can use classes inside the war file and contained jar files. This separates the runtime-classes of Tomcat from the application classes.
When using storm (see storm-project.net), there is no similar segregation. Rather the recommended way requires to create a "fat jar", denoting a jar containing all the necessary class files after unwrapping them from their own individual jars. For simple situations this works, but the resulting fat jar must have all the META-INF/* files from all merged jars correctly merged, which does not work semi-automatically.
I would not be shy to write my own class loader which simulates something like a war-file. Except I have no clue how to intercept the default class loader that loads all the classes I deploy.
My theory is that one of the classes of my applications is loaded first by the default class loader. Presumably in its static-section I would cast the magic class loader spell such that all dependent classes will then be loaded by my own class loader, which would now how to get the necessary classes from whatever I deem suitable.
Any hints towards the general problems described as well as the specific magic needed are appreciated.
Intercepting the classloader: The default classloader is the one which loaded the class that is currently executing. So if you use a separate classloader to bring in the WAR's entry point, every class reference from it or its (run-time/creation) descendents will default to going through that classloader. That classloader can then decide what it should refer back to a higher-level classloader and what it should reload using its own resolution rules -- the simple rule "only ask the parent for things I don't have available in this plug-in", also known as "parent last", is often sufficient.

Java EE and Java SE classloading

The difference that I read on the Internet between Java EE and Java SE classloading is that
In Java SE, a classloader delegates the classloading to its parent
classloader and then tries to load the class itself
However, In Java EE, a classloader first tries to load the class itself and then
delegate the classloading of that class to its parent classloader.
Kindly validate my understanding.
Also, why is it designed like that in Java EE (Any advantages of keeping it like this.)
This is the link where I heard this [http://www.youtube.com/watch?v=t8sQw3pGJzM]
Alright then,
A common application has 3 standard classloaders:
Bootstrap Classloader
Extensions Classloader
System-Classpath Classloader
So far, so good. Now, this works for a single application running alone and free.
But what happens when you say J2EE? You have multiple applications running on the same place, so you have to figure out a way to prevent them from stumbling on each other. That's where these extra classloaders come into play.
Think about a server instance. There's a JBoss with two deployed EARs. What would happen if there were to be conflicting classes between applications? They're ok on their own particular context but as a whole they're inconsistent.
These extra classloaders are introduced in an application-wise way to ensure the isolation between them. Classloaders below System-Classpath Classloader recognize a class only if it is specified in the manifest file for one of its childs.
In J2SE, the three basic classloaders work in a parent-child relationship based on three principles:
Delegation: If a class is not loaded (cache), the request is delegated to its parent. This goes on until the top of the hierarchy (Bootstrap classloader) who loads basic J2SE related classes (i.e. Integer, ArrayList, amongst others). This is what you reference in your question: A classloader delegates the loading until the top of the hierarchy, then each classloader tries to load the class if its parent couldn't find it, until someone loads it. Otherwise: ClassNotFound.
Visibility: Classes loaded by a parent classloader are visible to its children, not the other way around.
Uniqueness: If a parent classloader loads a class, a children will never reload it.
In Java SE, a classloader delegates the classloading to its parent classloader and then tries to load the class itself.
True, due to the principles explained above.
There's no determined classloader structure in J2EE (a vendor has "poetic license" to implement it), but they kind of follow a hierarchy. In this case, the System-classpath classloader loads the main application: The server. The server libraries (its classes, more specifically) are available, then, to every application due to the visibility principle.
Down there, the applications have particular classloader structures, but as a whole they are different children of the System-classpath classloader. Each application loads its related and particular classes (both application and libraries).
The loading here is not propagated to the parents outside the application context. Why? because if the System-classpath classloader were to load the applications as usual, the class of every application would be visible to others due to the visibility principle, completely breaking the isolation between themselves. So:
However, In Java EE, a classloader first tries to load the class itself and then delegate the classloading of that class to its parent classloader.
This is partly true, but I'd rather limit this affirmation to the context of an application and leave out the Java related classes, that are indeed loaded by the top level classloaders.
Long story short: It's not a straightforward process but I wouldn't go as far as to say J2EE handles the classloading the opposite way around of J2SE.
I think Java EE class loading standard will help you on your way. As far as I know there is no mandated way of classloading for standard Java. For WebApps (WARs) however, it is specified that the classloading is parent-last.

How to use two incompartible classes with same full name?

A problem: My application uses two libraries which use incompatible versions of a third library. Does someone know any method for classes isolation?
I have heard about class loaders, but I do not understand, how they could help - if we will load one version of class, we cannot load another - class is already loaded?
I also thinking about Spring, but do not know if it provides such isolation.
ClassLoaders are basically the elements that gives meaning to classes in the JVM. They form a hierarchy for wich the root lies in the JVM and loads java classes. The ApplicationClassLoader is the first ClassLoader you have to consider, as it loads all the classes of your application.
When a class is loaded, all its references to other classes are resolved and theses classes are loaded. The JVM by default provides a system where classloaders ask their parent first to see if they have already loaded a class. If not, they search in their classpath
Two classes can be isolated if they live in 2 different classloader, and not in the app classloader. It's not difficult to do. You only have to create a classloader (like URLClassLoader) while specifying its parent and its classpath(the place where the bytecode is)
then, you tell him to load a class. It will ask its parent, and if the class is not loaded yet, it will search its classpath and load it. If you create another classloader attached to the same parent, the classes loaded by the first will never be seen by the seconds as they are siblings. And the second can loads a class with the same name without any problem
That's quite a good isolation
App Servers use another form of delegation to have a frank isolation between applications. they redefine a classloader extending, for example, URLClassLoader and reverse the delegation process by starting to search for classes in their classpath first, then ask to the parent
if we will load one version of class, we cannot load another - class
is already loaded?
Not true. The class loader is considered part of the class's identity. If it's loaded by a different classloader, it's considered a different class.
If at least one of the libraries is open source, and the library they depend on is open source, no need for messing about with classloaders. Just bulk rename all the packages in one of the versions of the library being depended on, making sure to also change all code which refers to those packages. Hey presto - no name clashes. This is what Sun actually did for the JDK, when they included Xerces and Xalan behind the scenes.

Categories