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

Lai*_*son 6 spring-boot

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

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

只是想猜测一下,似乎这样就可以很容易地通过一个简单的java -xf the-jar.jar BOOT-INF/classes命令从胖罐中提取与应用程序相关的类和jar .是吗?还有其他原因吗?

And*_*son 11

TL; DR

在jar的根目录中打包应用程序类需要Spring Boot的类加载器使用非常规委派模型,并且还会导致Java代理出现问题.

详细解释

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

在Spring Boot 1.3及更早版本中,应用程序类打包在胖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/classes从jar中加载类,BOOT-INF/lib并使用系统类加载器作为其父类.Java代理可以打包在jar的根目录中,系统类加载器将像往常一样加载它们.

为了进一步阅读,您可能对引入更改的提交消息以及它所链接的其他问题感兴趣.