哪个 classloader 加载了所提供实例的 class

Which classloader loaded a class of the provided instance

在 JEE 环境中,知道从何处加载特定 class 很有用。

例如,我有一个 org.slf4j.Logger 的实例,由某个黑盒库提供。是否可以找到负责的 classloader?如果实例的 class 来自 JDK、Application Server、EAR 或 Web Application classloader?

原来很简单。 classloader 的名称由以下方式返回:

object.getClass().getClassLoader().getName()

它 returns 类似“应用程序”或“平台”的东西。注意 - classloader 是 null,如果 class 属于 bootstrap classloader,就像 JUL 记录器 java.util.logging.Logger 一样。

WebLogic 有一长串 classloader 没有名字。 WebLogic 的 classloader 包含一个有用的字段 annotation。阅读它可以找到 JEE 应用程序,classloader 属于:

public Object getAnnotation(ClassLoader classloader) {
    try {
        Method amethod = classloader.getClass().getMethod("getAnnotation");
        return amethod.invoke(classloader);
    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
        return "";
    }
}

如果您想打印所有可用 classloader 的概览而不挖掘注释,可以使用 classloader 实例的哈希码。这是一个小 JSP 页面。将它放入您的 Web 项目的 webapp 目录中以快速概览。

<%
response.setContentType("text/plain");

List<Class<?>> clazzes = List.of(Logger.class, object.getClass());

out.println("CLASSLOADERS:\n");
ClassLoader classloader = new Object() {}.getClass().getClassLoader();
while (classloader != null) {
    out.println(
            String.format("%-18s", classloader.getName()) + " " +
            String.format("%-10s", Integer.toHexString(classloader.hashCode()))  + " " + 
            classloader.getClass().getName() + " / " + getAnnotation(classloader));

    classloader = classloader.getParent();
}

out.println("\nCLASSES:\n");
for (Class<?> clazz : clazzes) {
    ClassLoader cloader = clazz.getClassLoader();
    URL location = Optional.of(clazz.getProtectionDomain()).map(x->x.getCodeSource()).map(x->x.getLocation()).orElse(null);
    out.println(
            clazz + " \n    " + 
            (cloader != null ? Integer.toHexString(cloader.hashCode()) : "<bootstrap>") + "\t" + 
            location);
}

%>