欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Class.getResource和ClassLoader.getResource的区别分析

程序员文章站 2022-05-27 15:11:06
...

Class.getResource

实现原理

  使用加载当前类的类加载器加载指定资源;

使用说明

  1. path不以’/’开头时,以类所在的包路径为基准路径获取资源;
  2. path以’/’开头时,以ClassPath为基准路径获取资源;
    Class.getResource和ClassLoader.getResource的区别分析

Class.getResource和ClassLoader.getResource的区别分析

代码实现

 public java.net.URL getResource(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResource(name);
        }
        return cl.getResource(name);
    }

ClassLoader.getResource

实现原理

双亲委派模型:首先委托父类加载器加载资源,如果找不到则调用自身findResource方法进行加载;

代码实现

   public URL getResource(String name) {
        URL url;
        if (parent != null) {
            url = parent.getResource(name);
        } else {
            url = getBootstrapResource(name);
        }
        if (url == null) {
            url = findResource(name);
        }
        return url;
    }

示例说明

  以AppClassLoader的实现逻辑为例进行说明。AppClassLoader继承URLClassLoader,创建实例时将classpath作为URL,如下图所示:
Class.getResource和ClassLoader.getResource的区别分析

findResource逻辑继承自URLClassLoader,权限校验之后从指定URL路径获取资源,如下图所示:

public URL findResource(final String name) {
        /*
         * The same restriction to finding classes applies to resources
         */
        URL url = AccessController.doPrivileged(
            new PrivilegedAction<URL>() {
                public URL run() {
                    return ucp.findResource(name, true);
                }
            }, acc);

        return url != null ? ucp.checkURL(url) : null;
    }

二者关联

关联逻辑:resolveName

private String resolveName(String name) {
        if (name == null) {
            return name;
        }
        if (!name.startsWith("/")) {
            Class<?> c = this;
            while (c.isArray()) {
                c = c.getComponentType();
            }
            String baseName = c.getName();
            int index = baseName.lastIndexOf('.');
            if (index != -1) {
                name = baseName.substring(0, index).replace('.', '/')
                    +"/"+name;
            }
        } else {
            name = name.substring(1);
        }
        return name;
    }

示例说明

  从上面的逻辑可以看出,class.getResource(“/”) == class.getClassLoader().getResource(“”),如下图所示:
Class.getResource和ClassLoader.getResource的区别分析

参考:

  1. http://swiftlet.net/archives/868
  2. http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/70e3553d9d6e/src/share/classes/sun/misc/Launcher.java