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 ClassLoader不能找到类

下一篇: Java扩展应用程序类加载器?