zoukankan      html  css  js  c++  java
  • springboot05

    public class Handler extends URLStreamHandler {
        private static final String SEPARATOR = "!/";
        private static SoftReference<Map<File, JarFile>> rootFileCache;
        @Override
        protected URLConnection openConnection(URL url) throws IOException {
            if (this.jarFile != null) {
                return new JarURLConnection(url, this.jarFile);
            }
            try {
                return new JarURLConnection(url, getRootJarFileFromUrl(url));
            }
            catch (Exception ex) {
                return openFallbackConnection(url, ex);
            }
        }
        public JarFile getRootJarFileFromUrl(URL url) throws IOException {
            String spec = url.getFile();
            int separatorIndex = spec.indexOf(SEPARATOR);
            if (separatorIndex == -1) {
                throw new MalformedURLException("Jar URL does not contain !/ separator");
            }
            String name = spec.substring(0, separatorIndex);
            return getRootJarFile(name);
        }

    ClassLoader如何读取到Resource

    对于一个ClassLoader,它需要哪些能力?

    • 查找资源
    • 读取资源

    对应的API是:

    public URL findResource(String name)
    public InputStream getResourceAsStream(String name)
    • 1
    • 2

    上面提到,Spring boot构造LaunchedURLClassLoader时,传递了一个URL[]数组。数组里是lib目录下面的jar的URL。

    对于一个URL,JDK或者ClassLoader如何知道怎么读取到里面的内容的?

    实际上流程是这样子的:

    • LaunchedURLClassLoader.loadClass
    • URL.getContent()
    • URL.openConnection()
    • Handler.openConnection(URL)

    最终调用的是JarURLConnection的getInputStream()函数。

    //org.springframework.boot.loader.jar.JarURLConnection
        @Override
        public InputStream getInputStream() throws IOException {
            connect();
            if (this.jarEntryName.isEmpty()) {
                throw new IOException("no entry name specified");
            }
            return this.jarEntryData.getInputStream();
        }
    • 1

    从一个URL,到最终读取到URL里的内容,整个过程是比较复杂的,总结下:

    • spring boot注册了一个Handler来处理”jar:”这种协议的URL
    • spring boot扩展了JarFile和JarURLConnection,内部处理jar in jar的情况
    • 在处理多重jar in jar的URL时,spring boot会循环处理,并缓存已经加载到的JarFile
    • 对于多重jar in jar,实际上是解压到了临时目录来处理,可以参考JarFileArchive里的代码
    • 在获取URL的InputStream时,最终获取到的是JarFile里的JarEntryData

    这里面的细节很多,只列出比较重要的一些点。

    然后,URLClassLoader是如何getResource的呢?

    URLClassLoader在构造时,有URL[]数组参数,它内部会用这个数组来构造一个URLClassPath:

    URLClassPath ucp = new URLClassPath(urls);
    • 1

    在 URLClassPath 内部会为这些URLS 都构造一个Loader,然后在getResource时,会从这些Loader里一个个去尝试获取。 
    如果获取成功的话,就像下面那样包装为一个Resource。

    Resource getResource(final String name, boolean check) {
        final URL url;
        try {
            url = new URL(base, ParseUtil.encodePath(name, false));
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("name");
        }
        final URLConnection uc;
        try {
            if (check) {
                URLClassPath.check(url);
            }
            uc = url.openConnection();
            InputStream in = uc.getInputStream();
            if (uc instanceof JarURLConnection) {
                /* Need to remember the jar file so it can be closed
                 * in a hurry.
                 */
                JarURLConnection juc = (JarURLConnection)uc;
                jarfile = JarLoader.checkJar(juc.getJarFile());
            }
        } catch (Exception e) {
            return null;
        }
        return new Resource() {
            public String getName() { return name; }
            public URL getURL() { return url; }
            public URL getCodeSourceURL() { return base; }
            public InputStream getInputStream() throws IOException {
                return uc.getInputStream();
            }
            public int getContentLength() throws IOException {
                return uc.getContentLength();
            }
        };
    }
  • 相关阅读:
    iOS 关于字体根据不同屏幕尺寸等比适配的问题(zz)
    安卓开发:一种快速提取安卓app的UI图标资源的方法
    申请邓白氏编码的时候总是提示 Enter a valid Street Address 怎么办?
    利用日期、经纬度求日出日落时间 C语言程序代码(zz)
    JS导出Excel 代码笔记
    Bootstrap系列 -- 44. 分页导航
    Bootstrap系列 -- 43. 固定导航条
    Bootstrap系列 -- 42. 导航条中的按钮、文本和链接
    Bootstrap系列 -- 41. 带表单的导航条
    Bootstrap系列 -- 40. 导航条二级菜单
  • 原文地址:https://www.cnblogs.com/huaobin/p/14908796.html
Copyright © 2011-2022 走看看