Java 密钥库未从jar中加载JKS文件
经过几个小时的斗争,我开始感到非常沮丧 我有一个JKS服务器文件,我想从jar中加载它。只要文件在Jar之外,使用FileInputStream就可以了,但只要我尝试将其更改为getResourceAsStream,它就不会接受它,比如说(没有这样的文件或目录) 这就是项目的分布方式Java 密钥库未从jar中加载JKS文件,java,classloader,loading,Java,Classloader,Loading,经过几个小时的斗争,我开始感到非常沮丧 我有一个JKS服务器文件,我想从jar中加载它。只要文件在Jar之外,使用FileInputStream就可以了,但只要我尝试将其更改为getResourceAsStream,它就不会接受它,比如说(没有这样的文件或目录) 这就是项目的分布方式 ProjectFolder -src --package.name ---JKS File ---Class calling the resource retrieval and loading into the
ProjectFolder
-src
--package.name
---JKS File
---Class calling the resource retrieval and loading into the keystore
我想我已经尝试了几乎所有我能想到的.getClass().getClassLoader().getResourceAsStream(“jksFile.jks”)的组合
我为没有更具体地使用代码提前道歉,但我已经记不清我尝试过什么和没有尝试过什么
救命啊
如果是关于war文件的,请提前感谢: 在构建和运行项目时,.class将不再位于此位置(/src),它将转到WEB-INF/classes/…,因此,您可以尝试将JKS文件放在那里,或者在getResourceAsStream()中从类引用到src
war文件文件夹层次结构的有用链接:假设jar包含
src
下的文件夹结构,并且包含编译后的.class
文件以及甚至代替源.java
文件(这使得目录名src
具有误导性):
或者其他获取类的方法,如this.getClass().getResourceAsStream(字符串)
然后MyClass.class
将资源名称视为相对于包含类的package=目录.getResourceAsStream(String)
或者其他查找类加载器的方法,如this.getClass().getClassLoader().getResourceAsStream(字符串)
然后athread.getContextClassLoader()
将资源名称视为相对于jar文件根的名称,因此需要.getResourceAsStream(String)
。 记住jar中的包路径使用斜杠,而Java源代码中的包路径使用点“package/names/jksfile.jks”
src/package/names/MyClass.java
和编译文件下时,通常会使用目录“src”和“bin”
在镜像层次结构
bin/package/names/MyClass.class中,通过class
对象和通过Classloader
获取getResourceAsStream
访问类路径内的资源有两种主要方式
最终,实现资源查找的精确规则取决于类加载器。但其中大部分都有明确规定。按名称查找资源
资源的名称是标识资源的“/”分隔路径名
而且,在探索类路径时,搜索顺序也很清楚
此方法将首先在父类装入器中搜索资源;如果父级为null,则搜索内置到虚拟机的类加载器的路径。如果失败,此方法将调用{@link#findResource(String)}来查找资源
findResource
是依赖于实现的部分。然而,大多数Java类加载器都是某种类型的URLClassLoader
s,它们的实现知道如何探索类路径条目(在文件系统上或JAR文件内部,甚至是远程文件),以将名称解析为所述条目的相对或绝对路径
因此,简而言之:您可以使用getResourceByName
探索类路径,通过类路径中的相对路径或绝对路径查找文件
Class#getresourceastream
和ClassLoader#getresourceastream
之间的区别在于Class
版本将相对路径解释为相对于Class
的包,而ClassLoader
版本将从类路径的根开始
所以。。。鉴于以下项目结构:
src
name
gpi
file.txt
Test.java
这个Test.java可以工作:
public static void main(String[] args) throws IOException {
// relative path from this class
InputStream is = Test.class.getResourceAsStream("file.txt");
byte[] content = new byte[4096];
int length = is.read(content);
System.out.println(new String(content, 0, length));
// relative path from the root of the classpath
is = Test.class.getClassLoader().getResourceAsStream("name/gpi/file.txt");
content = new byte[4096];
length = is.read(content);
System.out.println(new String(content, 0, length));
}
注意文档中的细节,如图所示
// This works : on the class object, absolute path are treated as "root of the classpath"
InputStream is = Test.class.getResourceAsStream("/name/gpi/file.txt");
//This does not work, because this looks actually at the root of the file system
InputStream is = Test.class.getClassLoader().getResourceAsStream("/name/gpi/file.txt");
如果您尝试了这里列出的组合,但它们实际上不起作用,那么要么您有一个“funky”类加载器(这绝对不应该发生在一个简单的项目上),要么您的编译器/打包程序设置(maven或eclipse或其他)的设置方式会从编译/打包结果(JAR)中丢弃您的JKS文件
在maven项目中,Java类通常属于src/main/Java目录,而属性、配置和JKS文件通常属于src/main/resources目录。根据具体的maven设置,将JKS文件放在java目录中可能会导致它从实际的可运行类路径中被丢弃。所以你也应该检查一下。谢谢,不幸的是,我没有编写web应用程序,我的JAR只有一个META-INF文件夹,然后是从包名派生的文件夹树,包括JKS文件,这就是为什么我对它不起作用感到困惑的原因:(另外,如果您的密钥库像您所指出的那样埋在某个包中,那么getResourceAsStream
将无法仅使用文件名找到它。如果没有路径,类加载器将查找与jar文件中包根相同级别的密钥库。这可能会帮助您:我尝试加载的jks文件位于sa中me package作为加载它的类,应用程序不够复杂,没有复杂的文件结构。这两个文件实际上是一个挨着另一个的:(你的项目是maven项目吗?谢谢!最后它工作了,我的构建设置是错误的,它把JKS文件漏掉了。你有相同的代码吗“这行得通”和“这行不通”部分?@eis:修正了,很抱歉。奇怪的是,它这样保持了这么长时间!中提出的方法效果很好。