【问题标题】:Spring-boot inner jar files loading order? (embedded tomcat)Spring-boot内部jar文件加载顺序? (嵌入式tomcat)
【发布时间】:2021-08-31 22:44:38
【问题描述】:

我有一个带有嵌入式 tomcat (tomcat-embed-core-8.5.57.jar) 的 spring-boot "fat" jar (1.5.22)。

在 jar 内部 - 在 BOOT-INF/lib 下有许多“内部”jar。

类加载器按什么顺序加载这些内部 jar?

如果我在多台计算机上运行 java -jar myFatSpringBoot.jar - 内罐会以完全相同的顺序被拾取,还是 “依赖” 取决于每台计算机上的某些东西? (FS/tmpfs/java/等)


更新:许多响应者表示它会按照它们在胖罐中出现的确切顺序来使用内罐(因此至少 QA 和 PROD 对于同一个胖罐的行为方式应该相同,不像它用于非 spring-boot .war 应用程序)。

现在我想知道在创建/包装罐子的过程中,我们是否有任何机制来保留/强制执行/指定内罐子的顺序? (maven/gradle/...)

【问题讨论】:

  • 为什么这很重要?外部库的静态初始化器之间是否存在竞争条件?
  • @geanakuch - 由于 WEB-INF/lib 加载的字母数字顺序(范式与较新的 tomcats),然后有其他应用程序由于许多 jar 中的相同名称而发生意外的类冲突 - 测试在 QA 上通过了很好的测试,但在少数 PROD 主机上失败了(因为在 .war-unpack 期间顺序依赖于 FS),使得确保我们可以避免 SpringBoot 的 QA-vs-PROD 问题,更多信息请参见:stackoverflow.com/questions/67710064/…

标签: java spring-boot tomcat


【解决方案1】:

我认为顺序将保持不变。通常是 JRE 相关的类,然后是应用程序。您实际上可以自己查看加载顺序。只需使用-verbose 标志启动程序。像这样的

java -verbose -jar myFatSpringBoot.jar

这将打印大量关于从哪个 jar 和哪个路径加载的类的信息。除了启动之外,当您的应用程序被使用时,很少有类会被加载,因为通常类加载是惰性的。您可以将此信息记录到外部文件中,然后再进行分析。

java -verbose -jar myFatSpringBoot.jar > log.txt

【讨论】:

  • 在一台主机上尝试过,还记录了 strace(将尝试在更多主机上比较 Loaded/jar 顺序),但 strace 让我担心的是:[pid 5835] open("/myapp/myFatSpringBoot.jar", O_RDONLY) = 19 [pid 5835] open("/my.java.io.tmpdir/myFatSpringBoot.jar-spring-boot-libs-541d642d-ada7-4508-b1d5-5e1293d8f211/metrics-jersey-2.2.0.jar", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 20,例如我看到一些内部 jar 在被加载程序访问之前被解压到本地文件系统,并担心加载程序是否会使用 FS 诱导的命令(就像它用于非 springboot/非嵌入式 tomcat 的 WEB-INF/lib)跨度>
【解决方案2】:

BOOT-INF/lib 中的罐子是always added to Spring Boot’s class loader in the order in which they appear in the jar。这意味着,如果您在多个 jar 中声明了相同的类文件或资源,则无论操作系统、Java 版本等如何,相同的文件或资源总是会在您的应用程序的多次运行中获胜。即使您使用的是 Spring,这也是如此Boot 在运行时支持automatically unpacking certain jars

Spring Boot 还会在它构建的每个 jar 中打包一个 BOOT-INF/classpath.idx index file。它“按照它们应该添加到类路径的顺序”列出了所有嵌套的 jar。如果你解压 jar 文件,这样BOOT-INF/lib 中的 jar 就会被文件系统排序,如果你继续使用 Spring Boot 的JarLauncher 来启动应用程序it will honour the order in the index

Spring Boot 包含测试 such as these,在使用 java -jar 启动应用程序和使用 java org.springframework.boot.loader.JarLauncher 时验证类路径的顺序。

【讨论】:

  • 你的话很好,我的经验也一样,但是有保证吗?例如你说的是整个 Java 版本——但是如果我们明天转向 java_corretto 和明年“shmorretto”——范式会成立吗?例如是否有特定的类加载器代码在做/证明这一点(直接访问 jar 而不是临时解压到 FS/etc?)如果 spring-boot 自己的类加载器逻辑在这里发挥作用(而不是 rt.jar 之一) - 它可能会因一些 spring flag 或 SprgBoot 6.0 版本而中断,对吧?我重视/喜欢/尊重您的回答 - 只是寻找它所依据的基础
  • 我已经充实了一些东西。 FWIW,我是 Spring Boot 团队的成员,我们没有计划停止遵守 BOOT-INF/lib 中的 jar 顺序。我们知道类路径的顺序可能很重要,这就是为什么我们要确保它是可预测和可重复的。
  • 感谢您更新所有这些重要细节的答案,现在我相信转向 springboot 是正确的选择。生成 classpath.idx 的任何“最佳实践”? (通过 maven/gradle)还是手动制作文件是一个好方法?
  • 索引文件由 Spring Boot 的 Maven 和 Gradle 插件自动创建。类路径的顺序由 pom.xml 或 build.gradle 文件中的依赖声明的顺序控制。
猜你喜欢
  • 2018-01-08
  • 1970-01-01
  • 2016-07-22
  • 2021-03-03
  • 2018-05-28
  • 1970-01-01
  • 2016-01-30
  • 2019-09-30
  • 2017-03-12
相关资源
最近更新 更多