【问题标题】:Java extend Application Classloader?Java扩展应用程序类加载器?
【发布时间】:2014-10-14 08:41:42
【问题描述】:

问题: 我的公司有很多不同的罐子/现有项目,他们在客户那里运行。出于调试目的,我们希望生成一个日志,每个组件加载哪个类,更具体地说:from where。例如:jar StackOverFlowJar.jar 中的 stack.overflow.ClassA。

我的想法: 我已经尝试将每个 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

有多个类加载器。 Bootstrap ClassLoader(我用我的 CustomClassLoader 扩展的那个)只负责核心库。如果它找不到自定义创建的类,它将把它委托回扩展类加载器。如果 Extension ClassLoader 找不到它,它会将它委托回 Application ClassLoader,我可以在调试方式中看到,这确实是加载我的自定义类的方式。但它不是通过我的 CustomClassLoader 来实现的。

我的问题: 是否可以扩展应用程序类加载器和扩展类加载器?或者是否有其他解决方法可以解决我的问题?

非常感谢您!

【问题讨论】:

标签: java classloader


【解决方案1】:

您可以创建一个简单的 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;
      }
    }

  }

【讨论】:

  • 这可能是个好主意!我今天会尝试解决这个问题,如果有帮助,请将此答案标记为“那个”:) 谢谢!
  • 如果您遇到任何问题或有任何疑问,请添加评论:)
  • 感谢您的帮助。最后,我选择使用详细选项调用每个项目,并让它从命令写入文件。非常感谢你的好例子,我实际上从中学到了很多:)
【解决方案2】:

你也可以使用

-详细:类

JVM 选项,用于打印加载类的位置。 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

【讨论】:

    猜你喜欢
    • 2018-11-24
    • 2016-12-06
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-30
    • 2021-01-30
    相关资源
    最近更新 更多