在Java中,使用引导加载器时,是否可能知道一个类是否已经被加载?

huangapple go评论107阅读模式
英文:

In Java, is it possible to know whether a class has already been loaded when using the bootstrap loader?

问题

以下是翻译好的部分:

这是https://stackoverflow.com/questions/482633的一个变种,关于在Java中是否有可能知道一个类是否已经被加载。我们的应用程序进行字节码插桩,并利用-Xbootclasspath/a:选项来能够插入Java运行时。我想知道是否可以通过引导加载程序加载了一个类 - 而无需尝试加载它。

在引用的查询中列出的代码如果类是由引导加载程序加载的,则不起作用 - 因为我不认为有任何方法可以获取引导加载程序的实例来在调用中使用。

有什么想法吗?我怀疑这是做不到的。虽然对我们的应用程序不是关键性的,但我很好奇。

英文:

This is a variation of https://stackoverflow.com/questions/482633/in-java-is-it-possible-to-know-whether-a-class-has-already-been-loaded. Our app does byte code instrumentation and makes use of the -Xbootclasspath/a: option to be able to instrument the Java runtime. I would like to know if a class has been loaded via the bootstrap loader - without attempting to load it.

The code listed in the referenced query will not work if class was loaded by bootstrap loader - as I don't believe there is any way to get an instance of the bootstrap loader to use in the invoke.

Any thoughts? I suspect it can't be done. It's not critical to our application but I am curious.

答案1

得分: 3

Sure, here's the translated content:

当你想进行运行时字节码插桩时,你应该使用 Instrumentation API 来实现一个 Java 代理(Java Agent)。

在其 premainagentmain 方法中,Java 代理会获得一个 Instrumentation 实例,其参数类型已被声明为 (String agentArgs, Instrumentation inst)

这个 API 允许你在运行时将 JAR 文件附加到引导类路径,因此你无需依赖于命令行上指定 -Xbootclasspath/a 选项。

此外,它具有 getAllLoadedClasses()getInitiatedClasses(ClassLoader) 方法,用于查询已加载的类。因此,你可以使用 getInitiatedClasses(null) 来获取引导加载器当前加载的所有类。你需要迭代它们并自行比较名称,以找出是否某个类包含在数组中。

英文:

When you want to perform runtime byte code instrumentation, you should implement a Java Agent using the Instrumentation API.

The Java Agent will get an Instrumentation instance in its premain or agentmain method when its parameter types have been declared as (String agentArgs, Instrumentation inst).

This API allows appending jar files to the bootstrap class path at runtime, so you don’t need to rely on the -Xbootclasspath/a option being specified on the command line.

Further, it has the methods getAllLoadedClasses() and getInitiatedClasses(ClassLoader) to query already loaded classes. So you can use getInitiatedClasses(null) to get all classes currently loaded by the bootstrap loader. You have to iterate them and compare the names yourself to find out whether a particular class in contained is the array.

答案2

得分: 0

Sure, here's the translated content:

好的,疯狂的想法。

您可以在您描述的线程中使用相同的技术,尝试不同的方法。Class ClassLoader有以下方法:

private Class<?> findBootstrapClassOrNull(String name)

此方法调用本地方法:

private native Class<?> findBootstrapClass(String name)

您也可以尝试使此方法可访问。

编辑:我尝试了以下代码,从应用程序类加载器运行,尽管如下:

public class MyClassLoader extends ClassLoader {
    public static void main(String[] args)
            throws NoSuchMethodException,
            InvocationTargetException,
            IllegalAccessException {
        Method method = ClassLoader.class.getDeclaredMethod(
                "findBootstrapClass", String.class);
        method.setAccessible(true);
        MyClassLoader cl = new MyClassLoader();
        System.out.println(method.invoke(cl, "java.lang.String"));
        System.out.println(method.invoke(cl, "sun.java2d.loops.GraphicsPrimitiveMgr$2"));
    }
}

(顺便说一句,这段代码不一定要扩展ClassLoader,我只是从以前的一个测试中保留了这个。在那个测试中,我在ClassLoader中调用了一个受保护的方法。)

无论我提供哪些类,在我的main方法运行时,似乎几乎所有的东西都已加载,不太确定。从“findBootstrapClass”方法的源代码中,我看到了这个:

    /**
     * Returns a class loaded by the bootstrap class loader;
     * or return null if not found.
     */
    private Class<?> findBootstrapClassOrNull(String name)

所以,除非在代码被插装时得到不同的结果,我认为这可能是不可行的。

注意:再次说明,我查看的源代码是针对OpenJDK 1.8的。

祝您好运。

英文:

Ok, crazy idea.

You can use the same technique in the thread you described, trying a different method. Class ClassLoader has the following method:

private Class&lt;?&gt; findBootstrapClassOrNull(String name)

This method calls a native method:

private native Class&lt;?&gt; findBootstrapClass(String name)

Which you could try to make accessible too.

EDIT: I've tried the following code, running from application class loader, though:

public class MyClassLoader extends ClassLoader {
    public static void main(String[] args)
            throws NoSuchMethodException,
            InvocationTargetException,
            IllegalAccessException {
        Method method = ClassLoader.class.getDeclaredMethod(
                &quot;findBootstrapClass&quot;, String.class);
        method.setAccessible(true);
        MyClassLoader cl = new MyClassLoader();
        System.out.println(method.invoke(cl, &quot;java.lang.String&quot;));
        System.out.println(method.invoke(cl, &quot;sun.java2d.loops.GraphicsPrimitiveMgr$2&quot;));
    }
}

(By the way, this code does not have to extend ClassLoader, I just left that from a previous test where I was invoking a protected method from ClassLoader.)

Whatever classes I provide, at the point my main method is running, it appears pretty much everything is loaded, not sure. From the source code for the "findBootstrapClass" method, I see this:

    /**
     * Returns a class loaded by the bootstrap class loader;
     * or return null if not found.
     */
    private Class&lt;?&gt; findBootstrapClassOrNull(String name)

So, unless you get different result running at the time the code is being instrumented, I'm thinking perhaps this is not doable.

NOTE: again, the source code that I looked at is for OpenJDK 1.8

Good luck.

huangapple
  • 本文由 发表于 2020年8月1日 09:21:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/63200883.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定