且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

类加载器如何在清单类路径中加载类引用?

更新时间:2023-01-10 10:52:37

简短的回答是实现是部分太阳的内部运作,而不是通过公共手段提供。 getURLs()只返回传入的网址。答案较长,但只适用于大胆。

The short answer is that the implementation is part of Sun's internal workings and not available through public means. getURLs() will only ever return the URLs that are passed in. There is a longer answer but it is only for the daring.

使用调试器逐步调试Oracle JVM 8使我通过与OpenJDK6完全相同的结构,您可以看到它加载类路径的位置此处一>。

Stepping through Oracle JVM 8 with the debugger has led me through pretty much an identical structure as OpenJDK6 and you can see where it loads the class path here.

基本上,类加载器会保留一堆尚未解析到内存中的URL。当被要求加载一个类时,它将从堆栈中弹出URL,将它们作为类文件或jar文件加载,如果它们是jar文件,它将读取清单并将类路径条目推送到堆栈。每次处理文件时,它都会添加loader,它将该文件加载到加载程序映射中(如果没有别的,则确保它不会多次处理同一文件)。

Basically, the class loader keeps a stack of URLs it has not yet parsed into memory. When asked to load a class it will pop URLs off the stack, load them as class files or jar files, and if they are jar files it will read the manifest and push class path entries onto the stack. Each time it processes a file it adds the "loader" which loaded that file to a loader map (if nothing else, to ensure it doesn't process the same file multiple times).

如果你真的有动机去做(不推荐),你可以访问这张地图:

You can access this map if you are really motivated to do (would not recommend it) with:

        Field secretField = URLClassLoader.class.getDeclaredField("ucp");
        secretField.setAccessible(true);
        Object ucp = secretField.get(loader);
        secretField = ucp.getClass().getDeclaredField("lmap");
        secretField.setAccessible(true);
        return secretField.get(ucp);

在假设置上运行,我有dummy-plugin.jar,它引用external.jar(in dummy-plugin.jar的清单我得到以下内容:

Running that on a dummy setup where I have dummy-plugin.jar which references external.jar (in the manifest of dummy-plugin.jar) I get the following:

1)创建类加载器之后(加载任何类之前):

1) Immediately after creating the class loader (before loading any class):

urlClassLoader.getURLs()=[file:.../dummy-plugin.jar]
getSecretUrlsStack=[file:.../dummy-plugin.jar]
getSecretLmapField={}

2)从中加载一个类之后dummy-plugin.jar:

2) After loading a class from dummy-plugin.jar:

urlClassLoader.getURLs()=[file:.../dummy-plugin.jar]
getSecretUrlsStack=[file:.../external.jar]
getSecretLmapField={file:.../dummy-plugin.jar=sun.misc.URLClassPath$JarLoader@736e9adb}

3)从external.jar加载一个类后:

3) After loading a class from external.jar:

urlClassLoader.getURLs()=[file:.../dummy-plugin.jar]
getSecretUrlsStack=[]
getSecretLmapField={file:.../dummy-plugin.jar=sun.misc.URLClassPath$JarLoader@736e9adb, file:.../external.jar=sun.misc.URLClassPath$JarLoader@2d8e6db6}

奇怪的是,面对 JDK for URLClassLoader


默认情况下,加载的类只授予
访问URLClassLoader时指定的URL的权限创建。

The classes that are loaded are by default granted permission only to access the URLs specified when the URLClassLoader was created.