classLoader.getResources

简单例子

    @Test
    public void urlLoadTest() throws IOException {
            System.out.println(System.getProperty("java.class.path"));
            System.out.println(System.getProperty("java.ext.dirs"));
            URLClassLoader loader = new URLClassLoader(new URL[] { new URL("file:D:\\workspaces\\") });
            Enumeration<URL> result= loader.getResources("META-INF/spring.handlers");
            List<URL> rResult=new ArrayList<>();
            while (result.hasMoreElements()){
                rResult.add(result.nextElement());
            }
            System.out.println(rResult);
    }

执行结果

C:\Program Files\JetBrains\xxx\lib\idea_rt.jar;C:\Program Files\JetBrains\xxx\plugins\junit\lib\junit-rt.jar;C:\Program Files\JetBrains\xxx\plugins\junit\lib\junit5-rt.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\dev\project\private\project\quicklyCreateSpringMvc\miniSpring1\target\test-classes;D:\dev\project\private\project\quicklyCreateSpringMvc\miniSpring1\target\classes;C:\java环境\repository\maven\org\springframework\spring-webmvc\4.3.25.RELEASE\spring-webmvc-4.3.25.RELEASE.jar;C:\java环境\repository\maven\org\springframework\spring-aop\4.3.25.RELEASE\spring-aop-4.3.25.RELEASE.jar;C:\java环境\repository\maven\org\springframework\spring-beans\4.3.25.RELEASE\spring-beans-4.3.25.RELEASE.jar;C:\java环境\repository\maven\org\springframework\spring-context\4.3.25.RELEASE\spring-context-4.3.25.RELEASE.jar;C:\java环境\repository\maven\org\springframework\spring-core\4.3.25.RELEASE\spring-core-4.3.25.RELEASE.jar;C:\java环境\repository\maven\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\java环境\repository\maven\org\springframework\spring-expression\4.3.25.RELEASE\spring-expression-4.3.25.RELEASE.jar;C:\java环境\repository\maven\org\springframework\spring-web\4.3.25.RELEASE\spring-web-4.3.25.RELEASE.jar;C:\java环境\repository\maven\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;C:\java环境\repository\maven\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;C:\java环境\repository\maven\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;C:\java环境\repository\maven\junit\junit\4.12\junit-4.12.jar;C:\java环境\repository\maven\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\java环境\repository\maven\org\aspectj\aspectjrt\1.8.9\aspectjrt-1.8.9.jar;C:\java环境\repository\maven\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar;C:\Program Files\JetBrains\xxx\lib\idea_rt.jar
C:\Program Files\Java\Java\jdk1.8.0_111\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
[jar:file:/C:/java%e7%8e%af%e5%a2%83/repository/maven/org/springframework/spring-webmvc/4.3.25.RELEASE/spring-webmvc-4.3.25.RELEASE.jar!/META-INF/spring.handlers, jar:file:/C:/java%e7%8e%af%e5%a2%83/repository/maven/org/springframework/spring-aop/4.3.25.RELEASE/spring-aop-4.3.25.RELEASE.jar!/META-INF/spring.handlers, jar:file:/C:/java%e7%8e%af%e5%a2%83/repository/maven/org/springframework/spring-beans/4.3.25.RELEASE/spring-beans-4.3.25.RELEASE.jar!/META-INF/spring.handlers, jar:file:/C:/java%e7%8e%af%e5%a2%83/repository/maven/org/springframework/spring-context/4.3.25.RELEASE/spring-context-4.3.25.RELEASE.jar!/META-INF/spring.handlers]

其中loader层级

ExtClassLoader
APPClassLoader
URLClassLoader

以上层级是如何来的?我们可以看到最终是由Launcher 实现

public class URLClassLoader extends SecureClassLoader implements Closeable {
    //指定classLoader
    public URLClassLoader(URL[] urls, ClassLoader parent) {
        super(parent);
        ....
    }
    //使用默认
    public URLClassLoader(URL[] urls) {
        super();
        ....
    }
}

public class SecureClassLoader extends ClassLoader {
    protected SecureClassLoader() {
        super();
    }
}

public abstract class ClassLoader {
    protected ClassLoader() {
        this(checkCreateClassLoader(), getSystemClassLoader());
    }

    
    public static ClassLoader getSystemClassLoader() {
        initSystemClassLoader();
        ....
        return scl;
    }

    //默认loader由Launcher产生
    private static synchronized void initSystemClassLoader() {
            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
            ....
            scl = l.getClassLoader();
    }

    //最终赋值
    private ClassLoader(Void unused, ClassLoader parent) {
        this.parent = parent;
        ....
    }

}


public class Launcher {
    private static Launcher launcher = new Launcher();
    //最终实现
    public Launcher() {
        Launcher.ExtClassLoader var1= Launcher.ExtClassLoader.getExtClassLoader();
        this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
        Thread.currentThread().setContextClassLoader(this.loader);
    }
    public static Launcher getLauncher() {
        return launcher;
    }
}

那么在getResources时ExtClassLoader、APPClassLoader、URLClassLoader三个loader怎么协作的?

    public Enumeration<URL> getResources(String name) throws IOException {
        @SuppressWarnings("unchecked")
        Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];
        if (parent != null) {
            tmp[0] = parent.getResources(name);
        } else {
            tmp[0] = getBootstrapResources(name);
        }
        tmp[1] = findResources(name);

        return new CompoundEnumeration<>(tmp);
    }

可以看到,其实是递归获取parent-loader的getResources的内容,最终合并到一起。

URLClassLoader loader = new URLClassLoader(new URL[] { new URL("file:D:\\workspaces\\") });
Enumeration<URL> result= loader.getResources("META-INF/spring.handlers");

所以,其实上面代码,等效于分别获取ExtClassLoader、APPClassLoader、URLClassLoader的findResources方法合并结果。

ExtClassLoader处理路径

    static class ExtClassLoader extends URLClassLoader {
        public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
            final File[] var0 = getExtDirs();
            ...
        }

        private static File[] getExtDirs() {
            String var0 = System.getProperty("java.ext.dirs");
            File[] var1;
            if (var0 != null) {
                StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator);
                ..
            } else {
                var1 = new File[0];
            }

            return var1;
        }
    }

我们观察到两个点,

  • 其实ExtClassLoader 继承自URLClassLoader (这是代码结构,而非parent,说明只是部分重写了URLClassLoader功能。)
  • String var0 = System.getProperty("java.ext.dirs"),其实ExtClassLoader 就是对这个路径进行处理。

AppClassLoader处理路径

    static class AppClassLoader extends URLClassLoader {
        final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);

        public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
            final String var1 = System.getProperty("java.class.path");
            ..
        }

处理路径为System.getProperty("java.class.path"),即项目引用的各种lib里的jar包;

UrlClassLoader处理路径

通过参数外面传入

 URLClassLoader loader = new URLClassLoader(new URL[] { new URL("file:D:\\workspaces\\") });

URLClassLoader.findResources方法

上面说到,getResources方法等效于等效于分别获取ExtClassLoader、APPClassLoader、URLClassLoader的findResources方法合并结果。

public class URLClassLoader extends SecureClassLoader implements Closeable {
    public Enumeration<URL> findResources(final String name)
        throws IOException
    {
        final Enumeration<URL> e = ucp.findResources(name, true);
        ...
    }
}

public class URLClassPath {
    public Enumeration<URL> findResources(final String var1, final boolean var2) {
        return new Enumeration<URL>() {
            private int index = 0;
            private int[] cache = URLClassPath.this.getLookupCache(var1);
            private URL url = null;

            private boolean next() {
                if (this.url != null) {
                    return true;
                } else {
                    do {
                        URLClassPath.Loader var1x;
                       //获取相应loader,这一步可以理解为获取目录地址,例如java.class.path会有很多目录
                        if ((var1x = URLClassPath.this.getNextLoader(this.cache, this.index++)) == null) {
                            return false;
                        }
                       //获取相应拼接
                        this.url = var1x.findResource(var1, var2);
                    } while(this.url == null);

                    return true;
                }
            }
            ...
    }


    private synchronized URLClassPath.Loader getNextLoader(int[] var1, int var2) {
        if (this.closed) {
            return null;
        } else if (var1 != null) {
            ...
        } else {
            return this.getLoader(var2);
        }
    }

    private synchronized URLClassPath.Loader getLoader(int var1) {
        if (this.closed) {
            return null;
        } else {
            //循环完成以后才执行
            while(this.loaders.size() < var1 + 1) {
            }
            //最终实现
            return (URLClassPath.Loader)this.loaders.get(var1);
        }
    }
}

其中
var1x.findResource
三个实现了类
FileLoader:直接从文件流中获取
JarLoader:从jar中读取,基于zip压缩,拼接路径获取
Loader:。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容

  • ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于某些框架开发者来说却非常常见...
    时待吾阅读 1,028评论 0 1
  • ClassLoader就是类加载器。ClassLoader的作用就是将class文件加载到jvm虚拟机中去。jvm...
    你需要一台永动机阅读 94评论 0 0
  • 1、classLoader 类加载器,将class文件加载到JVM虚拟机内存中,使得程序可以运行。通常情况下,JV...
    helloWorld_1118阅读 2,150评论 0 2
  • 本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 ClassLoader翻译过来就是类加载器,普...
    尼尔君阅读 626评论 1 0
  • 转发:本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 ClassLoader翻译过来就是类加载...
    尼尔君阅读 509评论 0 1