Class#getResourceAsStream()
可以采用相对于Class
您在那里使用的位置作为起点的路径。因此,例如,如果类位于com.example
包中并且您请求路径foo/filename.properties
,那么它将实际加载com/example/foo/filename.properties
文件。但是如果你使用/foo/filename.properties
,那么它实际上foo/filename.properties
会从类路径根目录加载。
所以,你的代码
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);
(请注意,这个不能采用以 开头的路径/
,它总是相对于公共根)
也可以看看: