Ответ 1
Class#getResourceAsStream()
может принимать путь, который находится относительно местоположения Class
, который вы используете там как отправную точку. Например, если класс находится в пакете com.example
и вы запрашиваете путь foo/filename.properties
, то он фактически загрузит файл com/example/foo/filename.properties
. Но если вы используете /foo/filename.properties
, то он фактически загрузит foo/filename.properties
из корня classpath.
Итак, ваш код
java.util.Properties prop = new java.util.Properties();
String path = "localization/stat_codes.properties";
InputStream foo = prop.getClass().getResourceAsStream(path);
будет искать файл java/util/localization/stat_codes.properties
.
Но в приложениях с сложной иерархией многоуровневого загрузчика один загрузчик классов не является другим. Классный загрузчик, который загружал основные классы Java, не обязательно знает о файлах, которые находятся в webapp /WEB-INF/classes
. Поэтому префикс пути с /
не обязательно будет решением, он все равно вернет null
.
Если вы можете гарантировать, что текущий класс будет виден тем же загрузчиком классов, что и файлы свойств (поскольку они находятся в одном и том же под-корневом пути пути к классам, например /WEB-INF/classes
, тогда вы действительно должны использовать
String path = "/localization/stat_codes.properties";
InputStream foo = this.getClass().getResourceAsStream(path);
Но если в какой-то момент файлы свойств будут экстернализированы из-за более легкого обслуживания/редактирования во время выполнения, так что вам не нужно перестраивать/повторно развертывать/перезапускать webapp, когда вы хотите редактировать файлы, то приведенное выше строка кода, скорее всего, не удастся. Внешнее местоположение будет доступно только другому загрузчику классов. Каноническое решение заключается в том, чтобы вместо этого использовать загрузчик классов контекста потока как отправную точку, он имеет доступ ко всем ресурсам в пути к классам.
String path = "localization/stat_codes.properties";
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream foo = loader.getResourceAsStream(path);
(обратите внимание, что этот путь не может принимать путь, начинающийся с /
, он всегда относится к общему корню)