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.
Related
I apologize in advance if the answer to this question is a simple one. It seems I don't have enough knowledge about classloading in Java.
Say I have a file called "properties" in my application. My application uses an external JAR and inside that JAR, there's also a file called "properties".
Question:
If the external JAR file attempts to open that file with getClass().getClassLoader().getResourceAsStream("properties"), why doesn't it load the one from my application. Not that I want it to, but wouldn't the ClassLoader in this case be the one that loaded my application? I thought that method would use the absolute path for finding the resource. Do classes in external JARs get loaded with a different classloader?
The class loading mechanism is the same for classes and resources (but the bytes found are treated differently).
See http://docs.oracle.com/javase/tutorial/ext/basics/load.html for the official explanation.
It is the first class loader actually asked which has the resource that wins. If the class loader does not have its resource, try again with the parent.
(Note that for web applications - WAR files - this is deliberately slightly different about which one is asked first).
ThClassLoader#getResourceAsStream(String) calls getResource(String) and this as getResource() on the parent. If this does not find anything, then it will ask the classloaders findResource(String).
It depends on this implementation what it does return, in case of the URLClassLoader this will be URLClassPath.findResource() which steps through all loaders (one loader for each search path entry) and returns the first find.
In a normal application your JARs as well as all libraries are loaded by the same (Application) class loader. In case of the Sun launcher this is sun.misc.Launcher$AppClassLoader which extends URLClassLoader. It puts all JAR and classes from the classpath in the search list.
It is a good idea to make resources either unique (putting them in your packages) or retrieve all resources and pick the right one (or all). The later is for example used by the ServiceLoader when it finds all implementations for a given service.
No, it loads the first found in that class' classloader. If you want to open a file using an absolute path, you open an InputStream pointing at the file.
Classes in external JAR might be loaded using different classloaders (e.g. in a Java EE container) but then classloaders need to be chained in order for you to see them.
I am having difficulty in understanding the significance of classLoader in ResourceBundle.getBundle(bundleName, locale, classLoader) API .
What could be the practical scenario where someone would want to provide custom loader for this API?
A Java application might have multiple class loaders. For example, a J2EE application running on Tomcat or Glassfish has multiple tiers of classloaders - some belonging to the J2EE server itself, some being specifically made for your webapp (otherwise your webapp would be able to access classes belonging to other webapps) and even custom classloaders that you might have instantiated yourself.
Standalone Java apps might also have multiple classloaders. For example, if your application supports plugins and each of these plugins is contained in its own JAR file (local or remote) then in order to load the plugin's classes at runtime you would have to create your own classloaders to do so.
Therefore, when you load a ResourceBundle you have to select the appropriate classloader to ensure that the resource is loaded from the correct source. Here's a simple example... imagine that your application contains a /version.properties file and your JVM also has a similar, yet different, /version.properties (e.g. IBM's Java has this properties file). Trying to load this resource file using the system's default classloader returns the version.properties that is included in the JVM and in order to load your own version of this file, you must use a custom classloader or one whose context is specific to your app.
There is an old but still very interesting explanation of how class loaders work and how hierarchies and loading contexts are useful in practice. For more info, check Internals of Java Class Loading.
What is need for an application or system to go for Custom class loader?
What are the limitations of the current set of classloaders that generally web application use ( Server + JVM )
Regards
Illustrate one of the usage of Custom class loader, I will take an example of my implementation,
Couple of months ago I have built a custom class loader to load a class created at run time from xml data source. The requirement was to create a java source files from a XML files, compile, jar it.
In order to load/execute these classes which resides in a DB I had to write custom class loader (extending URLClassLoader) since all the operation happening at run time, default/system classloader is not aware of the new classes(jar) , or not in the claspath.
We have used custom classloaders in our application to build a plugin framework. This classloader allowed us to embed jar files inside the plugin file (Which is also a jar file).
You can create your own ClassLoader to
1. Create new classes (for example, when custom proxying needed)
2. Redefine existing classes, when on some reason java.lang.instrumentation (javaagent) is not available.
Is there anyway to find all the class names which are extending a particular class by using classloader information?
More Detailed Explanation
I have a jar file which has 3 classes X (extends A), Y (extends A) and Z (extends B). I have put this jar file into the classpath and start the JVM (calling main method of some class). Now from this main method is there any way to find the classes which are sub classes of A? i.e. classes X and Y as they are extending the class A.
Unfortunately there's no easy way to do it. The JVM has no information about a particular class until it gets loaded by a classloader. But to have the classloader actually load the class, you must know the name of the class. Chicken and egg problem.
However, there is some other, but a bit more complicated way.
To determine which .jar files are on the classpath when running your application, you can call the System.getProperty("java.class.path") then split the classpath entries along the File.separatorChar characters. Classpath entries may be numerous, consider filtering them somehow (limiting only to a specific directory, leaving out standard entries like rt.jar, etc.)
If you know which .jar file contains your classes of interest, you can open it with an instance of the class JarFile. Then you can iterate over all entries (eg. .class files) and from their internal path in the JAR file you are able to construct their fully qualified class name.
With the classname in your hand, you can call Class.forName() to load the class, and the you can use reflection to get the superclasses of each class to find out whether it extends your particular class or not.
Note that this method is quite resource consuming, you make the JVM to actually load all the classes from a .jar file (or multiple .jar files), even if you won't use them later. This wastes a fair amount af memory (PermGen space).
There are some low-level libraries that manipulate Java bytecode and class files (see BCEL or ASM). Using them you will be able to determine the superclass for a class without actually (class)loading it, thus this way is more faster and uses less memory.
Your question resembles the way JavaEE application servers work when deploying a web application. To find out which classes to load and initialize as for example HTTP servlets they must examine all classes in the web archive looking for a specific Java annotation or superclass. However they are at least know which .war file to scan. Apache Tomcat for example uses BCEL instead of Java classloading mechanism.
If you're designing some sort of dynamic classloading mechanism for your application, then consider other design options to narrow down the numbers of classes your loader must scan to find the proper class to load: Telling the exact name of the .jar file instead of putting it on the classpath, using some meta information in the JAR (you can use the aforementioned JarFile to read entries from the META-INF/manifest.mf file) to specify which classes to look for, etc.
just fore the sake of completeness
http://code.google.com/p/reflections/
others where mentioned in the linked post
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.