为什么Spring Boot 1.4改变它的jar布局来定位Boot - inf下的应用程序类?



这主要是一个历史问题。Pivotal建议所有论坛讨论都在StackOverflow上进行,这就是我在这里问它的原因。

Spring Boot项目用来证明将应用程序的类和依赖项从可执行jar格式的"顶层"移到BOOT-INF/下面的原因是什么?

只是试着猜测,似乎这使得使用简单的java -xf the-jar.jar BOOT-INF/classes命令从fat jar中仅提取与应用程序相关的类和jar变得容易。是这样吗?还有其他原因吗?

TL;DR

将应用程序类打包到jar的根目录需要Spring Boot的类加载器使用非常规的委托模型,这也会导致Java代理出现问题。

详细说明

当使用java -jar启动jar文件时,jar根目录下的所有类都在系统类装入器的类路径上。在Spring Boot fat jar中,这包括用于启动器的类,它负责创建一个类加载器,该类加载器可以加载嵌套在fat jar中的应用程序类及其依赖项。

在Spring Boot 1.3及更早的版本中,应用程序类被打包在一个fat jar文件的根目录中。这意味着它们位于系统类装入器的类路径上。对于标准的父优先委托模型,这意味着应用程序类将由系统类装入器而不是Spring Boot的类装入器装入。这是有问题的,因为只有Spring Boot的类加载器可以从嵌套在fat jar中的依赖项中加载类。结果是应用程序无法加载任何依赖项的类。

Spring Boot 1.3通过为其类装入器使用非常规的委托模型克服了这个问题。它使用来自系统类装入器的url创建了一个新的类装入器,但没有使用系统类装入器作为父类——而是使用了系统类装入器的父类。这意味着Spring Boot的类加载器将被用来在jar的根目录中加载应用程序的类,在嵌套的jar中加载应用程序的依赖项的类。

这种方法有一些缺点。首先,它使Spring Boot的类加载器变得相当复杂。其次,它打破了Java代理所做的关于如何加载它们的类的许多假设。我们解决了几个问题,但很明显,我们正在打一场失败的战斗。

Spring Boot 1.4重新安排一个大的jar来将应用程序类放在BOOT-INF/classes中(它也将嵌套的jar移动到BOOT-INF/lib,但从类加载的角度来看,这没有影响)。将应用程序类移到BOOT-INF/classes中意味着它们不再位于系统类装入器的类路径上。这意味着Spring Boot的类加载器可以配置为从BOOT-INF/classesBOOT-INF/lib的jar中加载类,并使用系统类加载器作为其父类。Java代理可以打包在jar的根目录中,系统类加载器将从这里加载它们。

进一步阅读,您可能会对引入更改的提交消息和它所链接的其他问题感兴趣。

最新更新