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

Другие вопросы по тегам