【问题标题】:Keystore not loading JKS file from within jar密钥库未从 jar 中加载 JKS 文件
【发布时间】:2014-10-13 04:43:55
【问题描述】:

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

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

这就是项目的分发方式

ProjectFolder
-src
--package.name
---JKS File
---Class calling the resource retrieval and loading into the keystore

我想我已经尝试了几乎所有我能想到的 this.getClass().getClassLoader().getResourceAsStream("jksFile.jks") 的组合。

对于没有更具体的代码,我提前道歉,但我已经记不清我尝试过什么,没有尝试过什么。

帮助!

提前致谢

【问题讨论】:

标签: java classloader loading


【解决方案1】:

如果是关于战争文件:

在构建和运行项目时,.class 将不再位于此位置(/src),它将转到 WEB-INF/classes/...,所以,也许您可​​以尝试将您的 JKS 文件在那里,或者在 getResourceAsStream() 中从类到 src 的引用。

war 文件的文件夹层次结构的有用链接:http://www.yolinux.com/TUTORIALS/Java-WAR-files.html

【讨论】:

  • 谢谢你,不幸的是我不是在写一个网络应用程序,我的 JAR 只有一个 META-INF 文件夹,然后是从包名派生的文件夹树,包括 JKS 文件,它是为什么我对它为什么不起作用感到困惑:(
  • 另外,如果您的密钥库像您所指示的那样被埋在某个包中,那么getResourceAsStream 将无法仅通过文件名找到它。如果没有路径,类加载器将在 jar 文件中查找与包根目录相同级别的密钥库。
  • 也许这可以帮助你:stackoverflow.com/questions/941754/…
  • 我试图加载的 jks 文件与加载它的类在同一个包中,应用程序不够复杂,无法拥有复杂的文件结构。这两个文件实际上是一个相邻的:(
  • 你的项目是 maven 的吗?
【解决方案2】:

在类路径中访问资源有两种主要方式,通过Class 对象和通过Classloader,通过获取getResourceAsStream

最终,实现资源查找的精确规则取决于类加载器。但大部分都明确规定。按名称查找资源。

资源名称是一个以“/”分隔的路径名,用于标识该资源。

而且,在探索classpath的时候,搜索顺序也一目了然

此方法将首先在父类加载器中搜索资源;如果 parent 为 null,则搜索虚拟机内置的类加载器的路径。如果失败,此方法将调用 {@link #findResource(String)} 来查找资源。

findResource 是依赖于实现的部分。然而,大多数 Java 类加载器是某种URLClassLoaders,它们的实现知道如何探索类路径条目(在文件系统上或在 JAR 文件内部 - 甚至是远程文件)以将名称解析为所述条目中的相对或绝对路径.

因此,简而言之:您使用getResourceByName 来探索您的类路径,通过类路径中的相对或绝对路径查找文件。

Class#getResourceAsStreamClassLoader#getResourceAsStream 之间的区别在于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");

如果您尝试使用此处列出的组合,但实际上并没有,那么您要么有一个“时髦”的类加载器(这绝对不应该发生在一个简单的项目中),要么是您的编译器/打包器设置(maven 或eclipse 或其他) 的设置方式是从编译/打包结果 (JAR) 中丢弃您的 JKS 文件。

在一般的maven项目中,Java类属于src/main/java目录,而属性、配置和JKS文件通常属于src/main/resources目录。根据您确切的 Maven 设置,将 JKS 文件放在 java 目录中可能会导致它从实际的可运行类路径中丢弃。所以你也应该检查一下。

【讨论】:

  • 谢谢!终于让它工作了,我的构建设置错误,它把 JKS 文件遗漏了。
  • 你在“这工作”和“这不工作”部分有相同的代码?
  • @eis :已修复,抱歉。很好奇它一直保持这种状态!
【解决方案3】:

假设 jar 包含 src 的文件夹结构,并且包含已编译的 .class 文件以及甚至代替源 .java 文件(这使得目录名src 具有误导性):

  • this.getClass().getResourceAsStream(String) 或其他获取课程的方式,例如MyClass.class 然后.getResourceAsStream(String) 将资源名称视为相对于包含该类的 package = 目录

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

('src' 和 'bin' 目录一般在你将源文件放在src/package/names/MyClass.java 下和编译后的文件时使用和有用 在镜像层次结构中bin/package/names/MyClass.class。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-01
    • 2012-08-05
    • 2014-11-20
    • 1970-01-01
    • 2022-12-16
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    相关资源
    最近更新 更多