Java extend Application Classloader?
Problem: My company has a lot of different jars/existing projects that they run at their customers. For debugging purposes, we would like to generate a log which class every component loads and more specifically: from where . For example: stack.overflow.ClassA in jar StackOverFlowJar.jar.
My thoughts: I have experimented with passing each jar/existing project a custom class loader. This custom class loader could potentially write above information to a file, and delegate the normal flow of class loading to its parent.
My CustomClassLoader extends ClassLoader, and I can see it loads classes such as:
java.lang.Class
java.lang.Thread
java.lang.ThreadGroup
etc etc, all the standard java classes from the core library. These classes do reach my CustomClassLoader. However, as can be seen by next image:
source: http://javarevisited.blogspot.nl/2012/12/how-classloader-works-in-java.html
There are multiple ClassLoaders. The Bootstrap ClassLoader (the one I extend with my CustomClassLoader) is only responsible for core libraries. If it can't find a custom created class, it will delegate it back to the Extension ClassLoader. If the Extension ClassLoader can't find it, it will delegate it back to the Application ClassLoader, and I can see in debugging modus, this is indeed the one that loads my custom classes. But it doesn't do so through my CustomClassLoader.
My question: Is it possible to extend the Application ClassLoader and the extension ClassLoader? Or is there perhaps another workaround for my problem?
Thank you very much in advance!
You could create a simple Jar file, run that, using just that Jar in the classpath. You could then have a class that extends URLClassLoader
, pass this object your real classpath, load your real main class through your ClassLoader, and invoke the main method using reflection.
Example main method
public static void main (String... args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
URL[] classpath = new URL[0];
LoggingClassLoader loggingClassLoader = new LoggingClassLoader(classpath, Main.class.getClassLoader());
Class<?> aClass = loggingClassLoader.loadClass("com.company.project.RealMain");
Method main = aClass.getMethod("main", args.getClass());
main.invoke(null);
}
Example class loader object
Edit
I have slightly extended the example, with there now being one loader per jar/ URL, in case you need to keep track of which class was loaded from what jar:
public static class LoggingClassLoader extends URLClassLoader {
final List<ChildLogger> childLochildLoggersders = new ArrayList<>();
public LoggingClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
for(URL url : urls) {
childLochildLoggersders.add(new ChildLogger(url, this));
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
for(ChildLogger childLoader : childLochildLoggersders) {
try {
return childLoader.loadClass(name);
} catch(ClassNotFoundException ignore) {
}
}
throw new ClassNotFoundException(name);
}
private static class ChildLogger extends URLClassLoader {
private final URL url;
private ChildLogger(URL url, ClassLoader parent) {
super(new URL[]{url}, parent);
this.url = url;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> aClass = super.findClass(name);
System.out.println("Loaded from :" + url + " class: " + name);
return aClass;
}
}
}
You could also use the
-verbose:class
JVM option to print where classes are loaded from. https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
链接地址: http://www.djcxy.com/p/44398.html下一篇: Java扩展应用程序类加载器?