Java расширяет приложение Classloader?
Проблема: у моей компании есть много разных фляг / существующих проектов, которые они запускают у своих клиентов. В целях отладки мы хотели бы создать журнал, класс которого загружает каждый компонент, а более конкретно: откуда. Например: stack.overflow.ClassA в jar StackOverFlowJar.jar.
Мои мысли: я экспериментировал с передачей каждого jar/ существующего проекта загрузчику пользовательских классов. Этот пользовательский загрузчик классов может потенциально записать вышеупомянутую информацию в файл и делегировать нормальный поток загрузки класса его родителю.
Мой CustomClassLoader расширяет ClassLoader, и я вижу, что он загружает классы, такие как:
java.lang.Class
java.lang.Thread
java.lang.ThreadGroup
и т. д., все стандартные классы java из базовой библиотеки. Эти классы достигают моего CustomClassLoader. Однако, как видно из следующего изображения:
источник: http://javarevisited.blogspot.nl/2012/12/how-classloader-works-in-java.html
Есть несколько ClassLoaders. Загрузчик ClassLoader (тот, который я расширяю своим CustomClassLoader) отвечает только за основные библиотеки. Если он не может найти созданный пользователем класс, он делегирует его обратно в расширение ClassLoader. Если расширение ClassLoader не может его найти, оно делегирует его обратно в Application ClassLoader, и я вижу в режиме отладки, это действительно тот, который загружает мои пользовательские классы. Но это не происходит через мой CustomClassLoader.
Мой вопрос: возможно ли расширить Application ClassLoader и расширение ClassLoader? Или, может быть, есть другой обходной путь для моей проблемы?
Заранее большое спасибо!
2 ответа
Вы можете создать простой файл Jar, запустить его, используя только этот Jar в пути к классам. Вы могли бы тогда иметь класс, который расширяет URLClassLoader
передайте этому объекту реальный путь к классам, загрузите реальный основной класс через ClassLoader и вызовите метод main с помощью отражения.
Пример основного метода
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);
}
Пример объекта загрузчика классов
редактировать
Я немного расширил пример, и теперь в нем есть один загрузчик на jar/ URL, на тот случай, если вам нужно отслеживать, какой класс был загружен из какого 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;
}
}
}
Вы также можете использовать
-verbose: класс
Опция JVM для печати, откуда загружаются классы. https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html