我知道要组合几个 jar 并创建一个可执行 jar,如果我不想解压缩依赖的jar,我需要使用OneJar 之类的工具。OneJar 有自己的自定义类加载器,可以在关联的 jar 中找到所需的类并加载它们。
我的问题是:为什么默认的类加载器无法从附加的 jar 中加载类。是因为安全吗?在创建包含其他依赖 jar 的单个可执行 jar(无需解压缩它们)时,我希望能清楚地解释需要自定义类加载器的原因。谢谢,
我知道要组合几个 jar 并创建一个可执行 jar,如果我不想解压缩依赖的jar,我需要使用OneJar 之类的工具。OneJar 有自己的自定义类加载器,可以在关联的 jar 中找到所需的类并加载它们。
我的问题是:为什么默认的类加载器无法从附加的 jar 中加载类。是因为安全吗?在创建包含其他依赖 jar 的单个可执行 jar(无需解压缩它们)时,我希望能清楚地解释需要自定义类加载器的原因。谢谢,
技术原因是 uri 规范jar:
不支持嵌套。
您可以编写一个 URI 处理程序来满足此需求,但是当您嵌套在每个 jar 文件中时,性能将开始受到影响。
使用单个 jar 文件,可以进行随机访问,因为索引提供了文件系统偏移量,您可以查找每个偏移量并仅读取您想要的文件
使用嵌套 jar,您可以查找内部 jar,但要从该 jar 中拉出文件,您必须先从外部解压缩内部 jar,然后才能查找。
如果您不想将 jar 文件提取到临时目录并从生成的类路径构建自己的类加载器,我会查看 OSGi 或 Maven Shade 插件提供的解决方案
除了其他答案(Stephen 的答案到目前为止更准确)之外,还要考虑 JVM 不会抢先探索可用的类路径条目,因此为了找到类com.foo.Bar它将查看类似的路径com/foo/Bar.class在类路径中列出的条目中。如果这个路径可能在一个嵌套的 jar 中(它本身没有在类路径声明中列出),为了找到所述路径,类加载器应该首先探索所有嵌套的 jar(在过程中解压缩它们)以便进行适当的查找.
我怀疑这个决定是出于安全性:如果任何东西通过嵌套或多或少地变得安全,那将是令人惊讶的。事实上,能够在我的 uber-JAR 中签署所有 JAR 作为一个整体并让它们都检查完整性作为验证我的 JAR 的一部分,这可能非常好。
我认为主要原因是性能和简单性。如果 JAR 可以嵌套,那么这些问题的答案应该是什么:
将 JAR 想象成共享库似乎是最直接的:它是一个很好的、打包的、索引的、签名的、扁平的、准备链接的包。值得注意的是 Unix .so 和 Windows .dll 也不允许嵌套,原因与我怀疑的大致相同。
旁注:通常不需要创建“uberjar”:您通常可以使用Class-Path
主 JAR 清单中的字段来允许它拉入外部库。
您可以将您的应用程序需要的所有 jars 放在您的应用程序文件夹(例如 lib)中,并
java -cp lib/*.jar ...
在主 jar 的清单 Class-Path 属性中使用或枚举所有 jars。