我怎么知道 java 中的当前 classLoader

how can I know the current classLoader in java

正在学习加载的过程javaclass遇到一些困惑

我知道加载 java classcurrent classLoader 不会加载java class 直接委托给它的 parent classLoader(一个递归过程)直到它的父无法加载这个 class。


问题是当前classLoader是什么? Bootstrap?扩大?应用?
如何获取当前的 classLoader?。 我知道有一个 API:

xxx.Class.getClassLoader();

但我不确定 return 值 是否是 currentClassLoader。我认为它应该是 classLoader 在现实中加载这个 java class.

为了更详细地描述我的问题,我将举一个例子。
我在博客中得到以下内容。

ThreadContextClassLoader is used to deal with java SPI, Interface is defined in java core lib and loaded by Bootstrap ClassLoader and third party implement these interface then the jar are loaded by AppClassLoader
Solution: traditional classLoader cant deal with this case,because it cant discovery the third party jar when we use the third party implement in core lib.

以上大部分我都能理解,但解决方案让我感到困惑: 例如,接口 CoreA 和 class CoreB 在 java core lib 中,应该由Bootstrap ClassLoaderAImpl 是第三方对 A 的实现,应该是由 AppClass 加载器.

加载

代码段如下:

 public Interface CoreA{
     void add();
 }

 public Interface AImpl implements CoreA{
     void add(){};
 }

 public class B{
      public void demo(){
         a = new AImpl();
      }
 }

然后如果我们在 main method 中引用 B,那么我们将加载 B,因为 class 加载器 BBootstrap 然后大约 AImpl 当前加载程序是 Bootstrap 所以它不能成立? 不知道是不是我猜的那样?

如有任何建议,我们将不胜感激。

总的来说你是对的,是找不到的。让我向您展示以下示例。假设我们有 3 个 classes:ABMain,如下所示:

public class A {
    public String a() {
        return "a";
    }
}

public class B {
    public String b() {
        return new A().a();
    }
}

public class Main {
    public static void main(String... args) {
        System.out.println(new B().b());
    }
}

然后我们将这些 classes 打包到对应的 jar 中:a.jarb.jar 并将 Main.class 放入工作目录。之后让我们测试以下场景:

1) 一切(A.classB.classMain.class)都由 system classloader 加载并且工作正常:

$ java -cp .:a.jar:b.jar Main
a

2) B.classsystem classloader 加载,A.classbootstrap classloader 加载,一切仍然正常,因为 system classloader 委托加载给 bootstrap classloader(只是因为bootstrap classloader可以加载):

$ java -Xbootclasspath/a:a.jar -cp .:b.jar Main
a

3) A.classsystem classloader 加载,B.classbootstrap classloader 加载(您的情况)。在这种情况下,在加载 B.class 期间,当前 class 加载程序是 bootstrap classloader,但找不到 B.class 并失败:

$ java -Xbootclasspath/a:b.jar -cp .:a.jar Main
Exception in thread "main" java.lang.NoClassDefFoundError: A
        at B.b(B.java:4)
        at Main.main(Main.java:4)

让我们更仔细地看一下最后一个例子。这里发生了什么:

  1. 尝试用public static main(String[] args)方法找到class

    1.1。 system classloader 还没有加载它所以委托给 extension classloader

    1.2。 extension classloader 还没有加载它所以委托给 bootstrap classloader

    1.3。 bootstrap classloader 还没有加载它并尝试加载它,它无法加载它并且 returns 控制到 extension classloader

    1.4。 extension classloader 尝试加载,它无法加载它并且 returns 控制到 system classloader

    1.5。 system classloader 加载 Main.class

  2. Main.class 已处理,我们尝试使用当前 classloader system classloader

    加载 B.class

    2.1。 system classloader 还没有加载它所以委托给 extension classloader

    2.2。 extension classloader 还没有加载它所以委托给 bootstrap classloader

    2.3。 bootstrap classloader还没有载入,载入B.class

  3. B.class 已处理,我们尝试使用当前 classloader bootstrap classloader

    加载 A.class

    3.1。 bootstrap classloader 尚未加载并尝试加载和 失败

希望对你有所帮助

the 'current classloader' is the real classloader(load this class in reality) of class that refer it.

例如 如果 classLoader of class Aext classloader and class A refer class B C D。那么B C D的'current classloader'就是ext classLoader。当然 main class 的 'current classLoader' 是 System classLoader.

当一个 class A 尝试加载另一个 class B 时,加载 A 的 ClassLoader 是当前的 ClassLoader。当前这个词模糊地指代执行上下文——例如你如何结束触发当前 class 加载调用的方法。

没有方法 - 比如 getCurrentClassLoader - 只是给出当前 ClassLoader,但是有 api 方法在内部使用当前 Class 的概念装载机。例如,Class.forName(String className)

如果你检查那个方法是如何实现的,它会告诉你"current class loader"的含义:

public static Class<?> forName(String className) throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

如果你能得到一个 Class 实例,你总是可以通过调用 Class::getClassLoader() 方法来请求它背后的加载程序。那将是您当前的 class 加载器。然而,棘手的一点是确定加载程序是 bootstrap、扩展程序还是系统 class 加载程序。棘手的原因是它是特定于实现的,您总是可以实现自己的 class 加载机制。

@dmitrievanthony 给出的例子说明了事情是如何变得非常复杂的。这是 JNDI 面临的类似情况,也是引入 hack Thread.getContextClassLoader() 的原因。更多相关信息 here

引用文章中最相关的部分:

... By definition, a current classloader loads and defines the class to which your current method belongs. This classloader is implied when dynamic links between classes resolve at runtime, and when you use the one-argument version of Class.forName(), Class.getResource(), and similar methods. It is also used by syntactic constructs like X.class class literals ...