В чем разница между Class.getResource() и ClassLoader.getResource()?

Интересно, какая разница между Class.getResource() и ClassLoader.getResource()?

edit: Я особенно хочу знать, связано ли какое-либо кэширование на уровне файлов/каталогов. Как в "списках каталогов, хранящихся в версии класса?"

AFAIK следующее должно по существу сделать то же самое, но они не:

getClass().getResource() 
getClass().getClassLoader().getResource()

Я обнаружил это при работе с некоторым кодом генерации отчета, который создает новый файл в WEB-INF/classes/ из существующего файла в этом каталоге. При использовании метода из класса я мог найти файлы, которые были там при развертывании, с помощью getClass().getResource(), но при попытке извлечь вновь созданный файл я получил нулевой объект. Просмотр каталога ясно показывает, что новый файл есть. Имена файлов были добавлены с помощью косой черты, как в "/myFile.txt".

Версия ClassLoader getResource(), с другой стороны, находила сгенерированный файл. Из этого опыта кажется, что происходит какое-то кэширование списка каталогов. Правильно ли, и если да, то где это документировано?

В API-документах на Class.getResource()

Находит ресурс с заданным именем. Правила для поиск ресурсов, связанных с данный класс реализуется определяющий загрузчик классов класса. Этот метод делегирует этот объект класс загрузчика. Если этот объект был загруженный загрузчиком класса загрузки, метод делегирует ClassLoader.getSystemResource(java.lang.String).

Для меня это гласит: "Class.getResource действительно вызывает свой собственный загрузчик классов getResource()". Это будет то же самое, что делать getClass().getClassLoader().getResource(). Но, очевидно, нет. Может ли кто-нибудь, пожалуйста, предоставить мне некоторое освещение в этом вопросе?

Ответ 1

Чтобы ответить на вопрос, происходит ли кеширование.

Я исследовал этот момент дальше, запустив автономное приложение Java, которое непрерывно загружало файл с диска с помощью метода getResourceAsStream ClassLoader. Мне удалось отредактировать файл, и изменения были немедленно отображены, т.е. Файл был перезагружен с диска без кеширования.

Однако: Я работаю над проектом с несколькими модулями maven и веб-проектами, которые имеют зависимости друг от друга. Я использую IntelliJ в качестве моей IDE для компиляции и запуска веб-проектов.

Я заметил, что вышеизложенное, похоже, уже не оправдано, причина в том, что файл, который я загружал, теперь запекается в банку и развертывается в зависящем веб-проекте. Я заметил это только после попытки изменить файл в моей целевой папке, но безрезультатно. Это заставило похоже, что происходит кеширование.

Ответ 2

Class.getResource может принимать "относительное" имя ресурса, которое обрабатывается относительно пакета класса. В качестве альтернативы вы можете указать "абсолютное" имя ресурса, используя ведущую косую черту. Порты ресурса Resourceload всегда считаются абсолютными.

Таким образом, они в основном эквивалентны:

foo.bar.Baz.class.getResource("xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt");

И так они (но они отличаются от вышесказанного:)

foo.bar.Baz.class.getResource("/data/xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt");

Ответ 3

Первый вызов выполняет поиск по отношению к файлу .class, в то время как последний ищет по отношению к корню classpath.

Чтобы отлаживать такие проблемы, я печатаю URL-адрес:

System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );

Ответ 4

Пришлось посмотреть в спецификациях:

Класс getResource() - документация указывает на разницу:

Этот метод делегирует вызов его загрузчику классов после внесения этих изменений в имя ресурса: если имя ресурса начинается с "/", оно не изменяется; в противном случае имя пакета добавляется к имени ресурса после преобразования ".". на "/". Если этот объект был загружен загрузчиком загрузки, вызов делегируется ClassLoader.getSystemResource.

Ответ 5

Все эти ответы здесь, а также ответы в этом вопросе позволяют предположить, что загрузка абсолютных URL-адресов, таких как "/foo/bar.properties", обрабатывалась одинаково на class.getResourceAsStream(String) и class.getClassLoader().getResourceAsStream(String). Это не так, по крайней мере, не в моей конфигурации/версии Tomcat (в настоящее время 7.0.40).

MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!  
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!

Извините, у меня нет абсолютно никакого объяснения, но я думаю, что tomcat делает грязные трюки и черную магию с загрузчиками классов и вызывают разницу. Я всегда использовал class.getResourceAsStream(String) в прошлом и не имел никаких проблем.

PS: Я также разместил это над здесь

Ответ 6

Я пробовал читать с input1.txt, который находился внутри одного из моих пакетов вместе с классом, который пытался его прочитать.

Следующие работы:

String fileName = FileTransferClient.class.getResource("input1.txt").getPath();

System.out.println(fileName);

BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName));

Наиболее важной частью было вызов getPath(), если вы хотите, чтобы имя пути было правильным в формате String. НЕ ИСПОЛЬЗУЙТЕ toString(), потому что он добавит дополнительный текст форматирования, который будет TOTALLY MESS UP fileName (вы можете попробовать его и посмотреть распечатку).

Отработано 2 часа отладки этого...: (

Ответ 7

Class.getResources будет извлекать ресурс загрузчиком классов, загружающим объект. В то время как ClassLoader.getResource будет извлекать ресурс, используя указанный загрузчик классов.