我怎么知道 java 中的当前 classLoader
how can I know the current classLoader in java
正在学习加载的过程javaclass遇到一些困惑
我知道加载 java class、current 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 ClassLoader 和 AImpl 是第三方对 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 加载器 B
是 Bootstrap 然后大约 AImpl
当前加载程序是 Bootstrap 所以它不能成立?
不知道是不是我猜的那样?
如有任何建议,我们将不胜感激。
总的来说你是对的,是找不到的。让我向您展示以下示例。假设我们有 3 个 classes:A
、B
和 Main
,如下所示:
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.jar
、b.jar
并将 Main.class
放入工作目录。之后让我们测试以下场景:
1) 一切(A.class
、B.class
、Main.class
)都由 system classloader
加载并且工作正常:
$ java -cp .:a.jar:b.jar Main
a
2) B.class
由 system classloader
加载,A.class
由 bootstrap classloader
加载,一切仍然正常,因为 system classloader
委托加载给 bootstrap classloader
(只是因为bootstrap classloader
可以加载):
$ java -Xbootclasspath/a:a.jar -cp .:b.jar Main
a
3) A.class
由 system classloader
加载,B.class
由 bootstrap 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)
让我们更仔细地看一下最后一个例子。这里发生了什么:
尝试用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
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
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 A
是 ext 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 ...
正在学习加载的过程javaclass遇到一些困惑
我知道加载 java class、current 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 ClassLoader 和 AImpl 是第三方对 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 加载器 B
是 Bootstrap 然后大约 AImpl
当前加载程序是 Bootstrap 所以它不能成立?
不知道是不是我猜的那样?
如有任何建议,我们将不胜感激。
总的来说你是对的,是找不到的。让我向您展示以下示例。假设我们有 3 个 classes:A
、B
和 Main
,如下所示:
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.jar
、b.jar
并将 Main.class
放入工作目录。之后让我们测试以下场景:
1) 一切(A.class
、B.class
、Main.class
)都由 system classloader
加载并且工作正常:
$ java -cp .:a.jar:b.jar Main
a
2) B.class
由 system classloader
加载,A.class
由 bootstrap classloader
加载,一切仍然正常,因为 system classloader
委托加载给 bootstrap classloader
(只是因为bootstrap classloader
可以加载):
$ java -Xbootclasspath/a:a.jar -cp .:b.jar Main
a
3) A.class
由 system classloader
加载,B.class
由 bootstrap 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)
让我们更仔细地看一下最后一个例子。这里发生了什么:
尝试用
public static main(String[] args)
方法找到class1.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
加载Main.class
已处理,我们尝试使用当前 classloadersystem classloader
B.class
2.1。
system classloader
还没有加载它所以委托给extension classloader
2.2。
extension classloader
还没有加载它所以委托给bootstrap classloader
2.3。
bootstrap classloader
还没有载入,载入B.class
加载B.class
已处理,我们尝试使用当前 classloaderbootstrap 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 A
是 ext 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 ...