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 result= loader.getResources("META-INF/spring.handlers");
            List 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 getResources(String name) throws IOException {
        @SuppressWarnings("unchecked")
        Enumeration[] tmp = (Enumeration[]) 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 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 findResources(final String name)
        throws IOException
    {
        final Enumeration e = ucp.findResources(name, true);
        ...
    }
}

public class URLClassPath {
    public Enumeration findResources(final String var1, final boolean var2) {
        return new Enumeration() {
            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:。。

你可能感兴趣的:(classLoader.getResources)