Java 密钥库未从jar中加载JKS文件

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

经过几个小时的斗争,我开始感到非常沮丧

我有一个JKS服务器文件,我想从jar中加载它。只要文件在Jar之外,使用FileInputStream就可以了,但只要我尝试将其更改为getResourceAsStream,它就不会接受它,比如说(没有这样的文件或目录)

这就是项目的分布方式

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
    然后
    .getResourceAsStream(String)
    将资源名称视为相对于包含类的package=目录

  • this.getClass().getClassLoader().getResourceAsStream(字符串)
    或者其他查找类加载器的方法,如
    athread.getContextClassLoader()
    然后
    .getResourceAsStream(String)
    将资源名称视为相对于jar文件根的名称,因此需要
    “package/names/jksfile.jks”
    。 记住jar中的包路径使用斜杠,而Java源代码中的包路径使用点

(当您将源文件放在
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:修正了,很抱歉。奇怪的是,它这样保持了这么长时间!中提出的方法效果很好。