ClassLoader определяет, где будет расположен ресурс (взят из ClassLoader JavaDoc):
Класс ClassLoader использует модель делегирования для поиска классов и ресурсов. Каждый экземпляр ClassLoader имеет связанный родительский загрузчик классов. При запросе на поиск класса или ресурса экземпляр ClassLoader делегирует поиск класса или ресурса своему загрузчику родительского класса, прежде чем пытаться найти сам класс или ресурс. Встроенный загрузчик классов виртуальной машины, называемый загрузчиком классов начальной загрузки, сам по себе не имеет родителя, но может служить родителем экземпляра ClassLoader.
Так что где бы в вашем коде ни вызывался Class # getResource или Class # getResourceAsStream, это происходит (взято из 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);
}
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;
}
где ClassLoader # findResource фактически должен быть перезаписан реализацией ClassLoader. Это подразумевает, что поведение на сервере приложений, TomCat или если вы работаете из файла jar, отличается, это зависит от реализаций ClassLoader среды, в которой вы находитесь.
Здесь - это пример, который вы можете использовать для отслеживания того, что происходит в вашем конкретном случае.