jdk之加载classpath资源

Java的官方文档说明中讲到:classloader装载类时的优先级(-jar命令参数 > -classpath命令参数 > CLASSPATH环境变量 > 默认的'.'指定的当前路径)。详细可参考官方文档How Classes are Found一文。 

System.out.println(PhantomReferenceDemo.class.getResource("./"));
//获取当前类的相对路径
System.out.println(PhantomReferenceDemo.class.getResource(""));
//获取当前类的绝对根路径:类路径的根路径
System.out.println(CustomResource.class.getResource("/"));

输出:

file:/Users/zhfeng/mayun/sun-jdk/base/target/classes/net/base/reference/
file:/Users/zhfeng/mayun/sun-jdk/base/target/classes/net/base/reference/
file:/Users/zhfeng/mayun/sun-jdk/base/target/classes/

getResource & getResourceAsStream:加载路径其实都是一样的,只不过结果一个表示URL,另一个为InputStream。 

1.ClassLoader加载资源公共逻辑

切记:只要是借助类加载器加载系统资源则一定是以类路径classpath为根路径。

public abstract class ClassLoader {
    public URL getResource(String name) {
        URL url;
        if (parent != null) {
            url = parent.getResource(name);
        } else {
            url = getBootstrapResource(name);
        }
        if (url == null) {
            //URLClassLoader#findResource
            url = findResource(name);
        }
        return url;
    }
}

如果最终资源是借助 URLClassLoader 类加载器处理,则name属性一定是相对路径,而且是相对于类路径classpath。

public class URLClassLoader{
    public URL findResource(final String name) {
        // 因为URL是指类路径classpath下某个资源,所以name属性一定是类路径下的子路径,否则url为null
        URL url = AccessController.doPrivileged(
            new PrivilegedAction<URL>() {
                public URL run() {
                    return ucp.findResource(name, true);
                }
            }, acc);

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

默认情况下都是通过 系统类加载器 加载指定的资源。


 2.Class类获取系统资源

URL resource = CustomResource.class.getResource("/test.txt");
URL resource = CustomResource.class.getResource("test.txt");
InputStream inputStream = resource.openStream();

绝对路径:类路径classpth【根路径】下寻找test.txt资源。

相对路径:类路径classpth【根路径】 + 当前类CustomResource全限定性名下寻找test.txt资源。

public final class Class<T>{
    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);// 利用类加载器URLClassLoader加载资源
    }

    private String resolveName(String name) {
        if (name == null) {
            return name;
        }
        if (!name.startsWith("/")) {//name属性不以"/"开头
            Class<?> c = this;
            while (c.isArray()) {
                c = c.getComponentType();
            }
            // 获取当前类的全限定性类名:包名 + class名
            String baseName = c.getName();
            int index = baseName.lastIndexOf('.');
            if (index != -1) {
                // 将 当前类的 baseName 拼接在 目标路径 name之前
                name = baseName.substring(0, index).replace('.', '/') +"/"+name;
            }
        } else {// 存在以"/"开头,则直接去掉"/"
            name = name.substring(1);
        }
        return name;//返回的路径name一定是相对路径,即路径开头没有"/"
    }
}

3.ClassLoader类加载资源

URL resource = ClassLoader.getSystemClassLoader().getResource("test.txt");
System.out.println(resource.getPath());
read(resource.openStream());
URL systemResource = ClassLoader.getSystemResource("test.txt");
read(systemResource.openStream());
URL systemResource1 = ClassLoader.getSystemResource("net/base/resource/test.txt");
read(systemResource1.openStream());

 通过 ClassLoader 加载系统资源中间不存在类Class#resolveName帮忙解析路径,所以用户自己设定相对于根路径(classpath)的相对路径。

public abstract class ClassLoader {
    public static URL getSystemResource(String name) {
        ClassLoader system = getSystemClassLoader();
        if (system == null) {
            return getBootstrapResource(name);
        }
        // 系统类加载器 -> ClassLoader#getResource
        return system.getResource(name);
    }
}

 默认情况下最终还是通过 URLClassLoader 加载资源。


4.自定义类加载系统资源

// 基于类路径下classpath加载资源
URL resource = CustomResource.class.getResource("/test.txt");
read(resource.openStream());
// 拼接类的全限定性名 + CustomResource类名
URL resource1 = CustomResource.class.getResource("test.txt");
read(resource1.openStream());

其实,最终是通过Class类提供的相关api加载资源。

URL resource = CustomResource.class.getClassLoader().getResource("test.txt");
read(resource.openStream());
// 拼接类的全限定性名 + CustomResource类名
URL resource1 = CustomResource.class.getClassLoader().getResource("net/base/resource/test.txt");
read(resource1.openStream());

其实,最终是通过类ClassLoader提供的相关api加载资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值