I know Weblogic have a great application called ws-cat that you can use to diagnose classloading problems in the deployed applications. But, sometimes a find myself needing "a little more". I've had the necessity of knowing the classloaders involved in the classloader hierarchy and the classpath for each one...even if I know this is unsupported, that some of the involved classloaders have no documented behaviour,..etc.
ClassLoader cl = this.getClass().getClassLoader();
while(cl != null) {
System.out.println("Cl: " + cl + ", class: " + cl.getClass());
cl = cl.getParent();
}
Invoking the servlet, I obtained this:
Cl: weblogic.utils.classloaders.ChangeAwareClassLoader@22dd997d finder: weblogic.utils.classloaders.CodeGenClassFinder@704fd3b4 annotation: TestClApp@TestClWeb, class: class weblogic.utils.classloaders.ChangeAwareClassLoader
Cl: weblogic.utils.classloaders.FilteringClassLoader@8d40807 finder: weblogic.utils.classloaders.CodeGenClassFinder@185b0818 annotation: TestClApp@TestClWeb, class: class weblogic.utils.classloaders.FilteringClassLoader
Cl: weblogic.utils.classloaders.GenericClassLoader@b39c954 finder: weblogic.utils.classloaders.CodeGenClassFinder@706c26 annotation: TestClApp@, class: class weblogic.utils.classloaders.GenericClassLoader
Cl: weblogic.utils.classloaders.FilteringClassLoader@54cc3303 finder: weblogic.utils.classloaders.CodeGenClassFinder@2a293573 annotation: , class: class weblogic.utils.classloaders.FilteringClassLoader
Cl: weblogic.utils.classloaders.GenericClassLoader@1f0fde7d finder: weblogic.utils.classloaders.CodeGenClassFinder@1db2cc30 annotation: , class: class weblogic.utils.classloaders.GenericClassLoader
Cl: sun.misc.Launcher$AppClassLoader@752a2259, class: class sun.misc.Launcher$AppClassLoader
Cl: sun.misc.Launcher$ExtClassLoader@21353d27, class: class sun.misc.Launcher$ExtClassLoader
Thus, the classloader hierarchy in my webapp is: ChangeAwareClassLoader -> FilteringClassLoader -> GenericClassLoader -> FilteringClassLoader -> GenericClassLoader -> AppClassLoader (JVM) -> ExtClassLoader (JVM).
But now I want to know if I can obtain some information from them. Using a little reflection, we can see the methods the classloaders offer us:
ClassLoader cl = this.getClass().getClassLoader();
while(cl != null) {
System.out.println("Cl: " + cl + ", class: " + cl.getClass());
if(cl.getClass().getName().contains("ChangeAwareClassLoader") ||
cl.getClass().getName().contains("FilteringClassLoader") ||
cl.getClass().getName().contains("GenericClassLoader")) {
System.out.println("Methods:");
Method[] methods = cl.getClass().getMethods();
for(Method method : methods) {
System.out.println("- " + method);
}
}
cl = cl.getParent();
}
public java.lang.String weblogic.utils.classloaders.ChangeAwareClassLoader.getClassPath()
You can use again some reflection to invoke that method. If you do it, you can find the method returns the classpath for the classloader, with each entry separated by ';' (in Windows?). So, doing something like this, yo can obtain the classloader classpath.
ClassLoader cl = this.getClass().getClassLoader();
while(cl != null) {
System.out.println("Cl: " + cl + ", class: " + cl.getClass());
if(cl.getClass().getName().contains("ChangeAwareClassLoader") ||
cl.getClass().getName().contains("FilteringClassLoader") ||
cl.getClass().getName().contains("GenericClassLoader")) {
System.out.println("Classpath:");
Method method = cl.getClass().getMethod("getClassPath");
String classpath[] = ((String)method.invoke(cl)).split(";");
for(String cpEntry : classpath) {
System.out.println(cpEntry);
}
}
cl = cl.getParent();
}
That gives us very cool information about our application runtime. For example we can check if the documentation is telling us the truth :P, which classloaders have the web module classes, which have the EJB module classes, which have the App-level classes, etc. It can be even more useful if you're using shared libraries and want to know what's really going on.
ClassLoader cl = this.getClass().getClassLoader();
but maybe is more useful to use:
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Luckily, for my scenario, the results are exactly the same.
As I said at the post start, you may not use the output of this code as a "source of truth", but just as a means to get more light in your diagnosing efforts. This is internal Weblogic material that I guess "we should not use". For example, each of the Weblogic classloaders, has a companion "finder" classloader with its own classpath; what does it does?
classpath = ((String)method.invoke(cl)).split(";");
for(String cpEntry : classpath) {
System.out.println(cpEntry);
}
No hay comentarios:
Publicar un comentario