существуетJava, чтобы прочитать файл по относительному пути, часто используется следующий метод:
xxx.class.getResource();
xxx.class.getClassLoader().getResource();
существуетSpring, мы также можем пройтиSpringкоторый предоставилResourceСделай что-нибудь:
ClassPathResource
FileSystemResource
ServletContextResource
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
Вот краткое резюме их различий:
ClassLoader##getResource()
Этот метод является главным действующим лицом на сегодняшний день.
мы все знаемClassLoaderиспользуется для загрузки.classдокумент иClassLoaderэто следоватьJavaМеханизм родительского делегирования при загрузке класса.
Так,ClassLoaderкак ты это нашел.classЧто с файлом? ответURLClassPath
JavaПоставляется с 3ClassLoaderсоответственноBootStrap ClassLoader,EtxClassLoader,AppClassLoader,
эти 3ClassLoaderНаследованиеURLClassLoader,иURLClassLoaderсодержитURLClassPathзаписывать каждыйClassLoaderсоответствующая загрузка.classПуть к файлу, когда вам нужно загрузить ресурсы, просто начните сURLClassPathНайдите соответствующий путь.
Вот тестовый код:
System.out.println("BootStrap ClassLoader ");
Stream.of(System.getProperty("sun.boot.class.path").split(";")).forEach(System.out::println);
System.out.println("ExtClassLoader:");
Stream.of(System.getProperty("java.ext.dirs").split(";")).forEach(System.out::println);
System.out.println("AppClassLoader:");
Stream.of(System.getProperty("java.class.path").split(";")).forEach(System.out::println);
Результат выглядит следующим образом:
BootStrap ClassLoader
H:\java\jdk1.8\jre\lib\resources.jar
H:\java\jdk1.8\jre\lib\rt.jar
H:\java\jdk1.8\jre\lib\sunrsasign.jar
H:\java\jdk1.8\jre\lib\jsse.jar
H:\java\jdk1.8\jre\lib\jce.jar
H:\java\jdk1.8\jre\lib\charsets.jar
H:\java\jdk1.8\jre\lib\jfr.jar
H:\java\jdk1.8\jre\classes
ExtClassLoader:
H:\java\jdk1.8\jre\lib\ext
C:\Windows\Sun\Java\lib\ext
AppClassLoader:
H:\java\jdk1.8\jre\lib\charsets.jar
H:\java\jdk1.8\jre\lib\deploy.jar
H:\java\jdk1.8\jre\lib\ext\access-bridge-64.jar
H:\java\jdk1.8\jre\lib\ext\cldrdata.jar
H:\java\jdk1.8\jre\lib\ext\dnsns.jar
H:\java\jdk1.8\jre\lib\ext\jaccess.jar
H:\java\jdk1.8\jre\lib\ext\jfxrt.jar
H:\java\jdk1.8\jre\lib\ext\localedata.jar
H:\java\jdk1.8\jre\lib\ext\nashorn.jar
H:\java\jdk1.8\jre\lib\ext\sunec.jar
H:\java\jdk1.8\jre\lib\ext\sunjce_provider.jar
H:\java\jdk1.8\jre\lib\ext\sunmscapi.jar
H:\java\jdk1.8\jre\lib\ext\sunpkcs11.jar
H:\java\jdk1.8\jre\lib\ext\zipfs.jar
H:\java\jdk1.8\jre\lib\javaws.jar
H:\java\jdk1.8\jre\lib\jce.jar
H:\java\jdk1.8\jre\lib\jfr.jar
H:\java\jdk1.8\jre\lib\jfxswt.jar
H:\java\jdk1.8\jre\lib\jsse.jar
H:\java\jdk1.8\jre\lib\management-agent.jar
H:\java\jdk1.8\jre\lib\plugin.jar
H:\java\jdk1.8\jre\lib\resources.jar
H:\java\jdk1.8\jre\lib\rt.jar
F:\spring-test\target\classes
AppClassLoaderотвечает за часто используемыеJDK jarи от чего зависит проектjarСумкаВышеуказанные параметры можно получить через sun.misc.Launcher.class
Через выходные параметры мы можем ясно видеть, что каждый
ClassLoaderОтветственная зона
Сказав это, это иClassLoader#getResource()Что это значит?
Это большое дело, я только что задал вопрос ранее,ClassLoaderкак читать.classЧто с файлом?
ответURLClassPath#getResource()метод: каждыйUrlClassLoaderна всем протяженииURLClassPathЧтобы сохранить соответствующую область загрузки, когда вам нужно найти.classфайл, проходURLClassPath#getResource()Найди это.
Посмотрим еще разClassLoader#getResource()
//双亲委派查找
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;
}
//由于BootStrap ClassLoader是C++写的,Java拿不到其引用。
//因此这里单独写了一个方法获取BootStrapResource()
private static URL getBootstrapResource(String name) {
URLClassPath ucp = getBootstrapClassPath();
Resource res = ucp.getResource(name);
return res != null ? res.getURL() : null;
}
URLClassLoader#findResource()
public URL findResource(final String name) {
URL url = AccessController.doPrivileged(
new PrivilegedAction<URL>() {
public URL run() {
return ucp.findResource(name, true);
}
}, acc);
return url != null ? ucp.checkURL(url) : null;
}
Нам нужно только обратить внимание на это предложениеucp.findResource(name, true);, вот поиск.classфайловый метод, поэтому мы можем сделать выводClassLoader#getResource()процесс:
- Во-первых,
AppClassLoaderделегироватьExtClassLoaderУзнать, есть ли соответствующий ресурс -
ExtClassLoaderделегироватьBootStrap ClassLoaderНайдите, есть ли соответствующий ресурс -
BootStrap ClassLoaderпройти черезURLClasspathНайдите область, загруженную самостоятельно, и вернитесь, когда найдете ее. -
BootStrap ClassLoaderСоответствующий ресурс не найден.ExtClassLoaderпройти черезURLClasspathНайдите область, загруженную самостоятельно, и вернитесь, когда найдете ее. -
ExtClassLoaderСоответствующий ресурс не найден.AppClassLoaderпройти черезURLClasspathНайдите область, загруженную самостоятельно, и вернитесь, когда найдете ее. -
AppClassLoaderНе найдено, выдает исключение.
Этот процесс, как раз и загрузка.classФайловый процесс тот же.
Здесь мы можем найти это поClassLoader#getResource()может получитьJDKресурсы, зависит отJARпакеты ресурсов и т. д.
Поэтому мы можем даже написать:
//читатьjava.lang.String.classбайт-код
InputStream inputStream =Test.class.getClassLoader().getResourceAsStream("java/lang/String.class");
try(BufferedInputStream bufferedInputStream=new BufferedInputStream(inputStream)){
byte[] bytes=new byte[1024];
while (bufferedInputStream.read(bytes)>0){
System.out.println(new String(bytes, StandardCharsets.UTF_8));
}
}
ПонялClassLoader#getResource(), На самом деле эта статья почти такая же, потому что нижние слои методов, которые будут использоваться позже, всеClassLoader#getResource()
class##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);
}
Но есть небольшая разницаclass#getResource()один дополнительный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;
}
этоresolveName()Примерно определить, является ли путь относительным или абсолютным путем, если это относительный путь, имя ресурса будет добавлено к корневому пути текущего проекта:
Test.class.getResource("spring-config.xml");
становится после разрешения
com/dengchengchao/test/spring-config.xml
Такие ресурсы можно найти только в текущем проекте.
Test.class.getResource("test.txt"); //相对路径
Test.class.getResource("/"); //根路径
Уведомление:
ClassLoader#getResource()не может быть/начало
Spring # ClassPathResource()
существуетSpringв, даResourceбыл расширен так, чтоResourceМожет адаптироваться к большему количеству сценариев применения,
ноClssPathResource()дно все ещеClassLoader##getResource(),следовательноClassLoader##getResource()свойства д,ClassPathResourceтакже поддерживает.
protected URL resolveURL() {
if (this.clazz != null) {
return this.clazz.getResource(this.path);
} else {
return this.classLoader != null ? this.classLoader.getResource(this.path) : ClassLoader.getSystemResource(this.path);
}
}
ClassPathResourceдля чтенияclassesфайл каталога
Вообще говоря, дляSpringBootПроект, структура упакованной проекта выглядит следующим образом:
xxx.jar
|--- BOOT-INF
|--------|--classes
|--------|----|--com
|--------|----|-- application.properties
|--------|----|--logback.xml
| -------|-- lib
|--- META-INF
|--- org
можно увидеть,ClassPathResource()Начальный путьclasses, обычно мы читаемapplication.propertiesэто использоватьClasspathResource()приобретенный
В процессе обычного использования следует обратить внимание на три момента:
-
Разница между classpath и classpath*:
Класс: возвращать только первый файл, который выглядит ClassPath *: вернет все файлы нахождения
-
существует
Spring, вам нужно прямо выразить использованиеClassPathResource()Если вы хотите найти его, вы можете добавить его напрямуюclasspath:голова -
использовать
classpathот/а не к/разницы нет в начале
Spring # ServletContextResource
ServletContextResourceнаправлен наServletделать, мы знаем,ServletРегулированиеwebappКаталог выглядит следующим образом:
иServletContextResourceпутьxxxКаталог запускается. ЭтоServletContextResourceполучитьform.htmlи другие ресурсы.
Также сравните вышеClassPathResourceмы можем узнать:
"classpath:com"
Эквивалентно:
ServletContextResource("WEB-INF/classes/com")
Spring # FileSystemResource
FileSystemResourceНечего сказать, просто ресурсы системного каталога, такие как
ApplicationContext ctx =
new FileSystemXmlApplicationContext("D://test.xml");
Маркировка головы как этоfile:
Например:
ApplicationContext ctx =
new FileSystemXmlApplicationContext("flie:D://test.xml");
Если вы считаете, что текст хороший, добро пожаловать в общедоступную учетную запись WeChat: Yiyou Java, время от времени публикуйте несколько статей о продвинутых Java, каждый день, спасибо за внимание.