一、File
有 maven 项目,pom.xml 路径为:/home/zxm/IdeaProjects/load-test/pom.xml
1.java
@Test
public void testFile() {
File file1 = new File("src/main/resources/test.txt");
File file2 = new File("/");
System.out.println(file1.getAbsolutePath());
System.out.println(file2.getAbsolutePath());
}
结果:
/home/zxm/IdeaProjects/load-test/src/main/resources/test.txt
/
2.原理
执行 file.getAbsolutePath() 时:
如果 pathname 以 “/” 开头,则为绝对路径,file.getAbsolutePath() 的值 this.path;
如果 pathname 不以 “/” 开头,则为非绝对路径,file.getAbsolutePath() 的值是,System.getProperty("user.dir") + this.path。
// FIle.java
public File(String pathname) {
if (pathname == null) {
throw new NullPointerException();
}
this.path = fs.normalize(pathname);
this.prefixLength = fs.prefixLength(this.path);
}
public String getAbsolutePath() {
return fs.resolve(this);
}
// UnixFileSystem.java
public int prefixLength(String pathname) {
if (pathname.length() == 0) return 0;
return (pathname.charAt(0) == '/') ? 1 : 0;
}
public String resolve(File f) {
if (isAbsolute(f)) return f.getPath();
return resolve(System.getProperty("user.dir"), f.getPath());
}
二、ClassLoader 和 Class
1.java
@Test
public void testClassLoader() {
ClassLoader classLoader = this.getClass().getClassLoader();
URL resource1 = classLoader.getResource("test.txt");
URL resource2 = classLoader.getResource("com/example/Main.class");
URL resource3 = this.getClass().getResource("/test.txt");
URL resource4 = this.getClass().getResource("Main.class");
System.out.println(resource1);
System.out.println(resource2);
System.out.println(resource3);
System.out.println(resource4);
}
结果:
file:/home/zxm/IdeaProjects/load-test/target/classes/test.txt
file:/home/zxm/IdeaProjects/load-test/target/classes/com/example/Main.class
file:/home/zxm/IdeaProjects/load-test/target/classes/test.txt
file:/home/zxm/IdeaProjects/load-test/target/classes/com/example/Main.class
2.原理
classLoader 包含 classpath 信息,如有:file:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/resources.jar
、file:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar
、file:/home/zxm/IdeaProjects/load-test/target/classes/
、file:/home/zxm/IdeaProjects/load-test/target/test-classes/
等
执行 classLoader.getResource("test.txt"),遍历 classpath,从 classpath 中查找资源,最后使用 file:/home/zxm/IdeaProjects/load-test/target/classes/
+ test.txt
,定位到文件,查找到资源
// ClassLoader.java
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;
}
// URLClassLoader.java
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;
}
// URLClassPath.java
public URL findResource(String name, boolean check) {
Loader loader;
int[] cache = getLookupCache(name);
for (int i = 0; (loader = getNextLoader(cache, i)) != null; i++) {
URL url = loader.findResource(name, check);
if (url != null) {
return url;
}
}
return null;
}
// URLClassPath$FileLoader.java
URL findResource(final String name, boolean check) {
Resource rsc = getResource(name, check);
if (rsc != null) {
return rsc.getURL();
}
return null;
}
Resource getResource(final String name, boolean check) {
final URL url;
try {
URL normalizedBase = new URL(getBaseURL(), ".");
url = new URL(getBaseURL(), ParseUtil.encodePath(name, false));
if (url.getFile().startsWith(normalizedBase.getFile()) == false) {
// requested resource had ../..'s in path
return null;
}
if (check)
URLClassPath.check(url);
final File file;
if (name.indexOf("..") != -1) {
file = (new File(dir, name.replace('/', File.separatorChar)))
.getCanonicalFile();
if ( !((file.getPath()).startsWith(dir.getPath())) ) {
/* outside of base dir */
return null;
}
} else {
file = new File(dir, name.replace('/', File.separatorChar));
}
if (file.exists()) {
return new Resource() {
public String getName() { return name; };
public URL getURL() { return url; };
public URL getCodeSourceURL() { return getBaseURL(); };
public InputStream getInputStream() throws IOException
{ return new FileInputStream(file); };
public int getContentLength() throws IOException
{ return (int)file.length(); };
};
}
} catch (Exception e) {
return null;
}
return null;
}
执行 this.getClass().getResource("/test.txt"),解析 name,若 name 以 “/” 为前缀,去除“/”前缀,然后找到加载当前类的 classload,使用 classload.getResource(“test.txt”);
执行 this.getClass().getResource("Main.class"),解析 name,name 拼接当前类的目录,即 com/example/Main.class,然后找到加载当前类的 classload,使用 classload.getResource(“com/example/Main.class”);
// Class.java
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);
}
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;
}