Ресурс Java из класса против потока

В чем разница между

getClass().getResource("some-resource-file.txt")

против

Thread.currentThread().getContextClassLoader().getResource("some-resource-file.txt")

У меня есть ресурсы в src/test/resources, и я пытаюсь получить к ним доступ из модульного теста. Это типичная структура каталогов в стиле maven.

Я ожидал, что оба будут вести себя одинаково. Но это не так. GetClass(). GetResource() не извлекает ресурс, где, как из потока, я могу получить ресурс.

Так чем они отличаются?

2 ответа

Решение

Существует особый случай запуска первого класса (именно поэтому вы должны объявить метод main() как статический с массивом строк в качестве аргумента). Как только этот класс загружен и запущен, будущие попытки загрузки классов будут выполняться загрузчиком классов. В самом простом случае загрузчик классов создает плоское пространство имен тел классов, на которые ссылается строковое имя. Каждый класс в Java использует собственный загрузчик классов для загрузки других классов. Так что если ClassA.class Рекомендации ClassB.class затем ClassB должен быть на пути к классам ClassLoader из ClassAили его родители.

Контекст потока ClassLoader особенный в том, что это текущий ClassLoader для текущего запущенного потока. Это полезно в средах с несколькими классами загрузчиков. Объект может быть создан из класса в ClassLoader C а затем перешли к теме, принадлежащей ClassLoader D, В этом случае объект должен использовать Thread.currentThread().getContextClassLoader() напрямую, если он хочет загрузить ресурсы, которые не доступны сами по себе ClassLoader,

Допустим, вы разрабатываете библиотеку, а jar библиотеки помещается в путь к классу веб-контейнера.

Теперь допустим, что веб-приложение, использующее эту библиотеку, развернуто в контейнере.

Веб-приложение будет иметь собственный загрузчик классов, использующий WEB-INF/classes и WEB-INF/lib/*. Jar в качестве пути к классам. И контейнер для каждого запроса, поступающего в ваше веб-приложение, устанавливает текущий загрузчик классов потока в загрузчик классов пути к классам.

Когда код вашей библиотеки использует getClass().getResource(), он загрузит ресурс, используя загрузчик классов, используемый для загрузки классов библиотеки. Таким образом, он будет использовать загрузчик классов контейнера и, таким образом, будет использовать ресурсы в jar вашей библиотеки и в других библиотеках, используемых для запуска контейнера.

Если код вашей библиотеки использует Thread.currentThread().getContextClassLoader() вместо этого, чтобы загрузить ресурс, он будет использовать загрузчик классов, связанный с текущим потоком, и, таким образом, загрузит ресурсы из загрузчика классов веб-приложения, ища ресурс в WEB-INF/classes и в jar-файлах внутри WEB-INF/lib.

Последний может быть тем, что вы хотите. Например, если вы разрабатываете библиотеку журналов (пожалуйста, не надо), регистратор сможет читать разные файлы конфигурации для каждого веб-приложения, вместо того, чтобы иметь единую конфигурацию, совместно используемую всеми веб-приложениями.

Относительно того, как два метода ищут ресурсы, все они, наконец, делегируют ClassLoader для загрузки ресурса. Но загрузка его через класс будет относиться к относительным путям относительно вызванного класса, тогда как загрузка его через ClassLoader ожидает путь, начинающийся в корне дерева пакетов. Предположим, ваш класс находится в пакете com.foo, затем

 MyClass.class.getResource("hello.txt")

эквивалентно

MyClass.class.getResource("/com/foo/hello.txt")

и эквивалентно

MyClass.class.getClassLoader().getResource("com/foo/hello.txt");
Другие вопросы по тегам