В чем разница между 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 будет извлекать ресурс, используя указанный загрузчик классов.