(This is primarily a history question. Pivotal recommended that all forum discussions take place on StackOverflow, which is why I am asking it here.)
What are the reasons that the Spring Boot project used to justify moving an application's classes and dependencies from the "top level" of the executable jar format to be underneath BOOT-INF/
?
Just trying to guess, it seems that this makes it easy to extract only the application-related classes and jars from the fat jar with a simple java -xf the-jar.jar BOOT-INF/classes
command. Was that it? Was there some other reason?
BOOT-INF : Spring Boot applications load from the BOOT-INF folder. Therefore the application classes must be placed in a nested BOOT-INF/classes directory. Dependencies should be placed in a nested BOOT-INF/lib directory.
It's a path inside your project where you place resources. During the build step, Maven will take files in there and place them in the appropriate place for you to use them in your runtime classpath, eg in an executable . jar , some physical file system location used in the classpath (with java 's -cp option), etc.
A pragmatic way: Class. forName("com. myclass") where com. myclass is a class that is inside (and only inside) your target jar; if that throws a ClassNotFoundException , then the jar is not on you current classpath.
Adding Classpath Dependencies. Spring Boot provides a number of “Starters” that let you add jars to your classpath. Our applications for smoke tests use the spring-boot-starter-parent in the parent section of the POM. The spring-boot-starter-parent is a special starter that provides useful Maven defaults.
Packaging application classes in the root of the jar required Spring Boot's class loader to use an unconventional delegation model and also caused problems with Java agents.
When a jar file is launched with java -jar
all of the classes in the root of the jar are on the class path of the system class loader. In a Spring Boot fat jar, this includes the classes for the launcher which is responsible for creating a class loader that can load the application's classes and their dependencies that are nested inside the fat jar.
In Spring Boot 1.3 and earlier, application classes are packaged in the root of a fat jar file. This means that they are on the class path of the system class loader. With a standard, parent first delegation model this would mean that application classes would be loaded by the system class loader rather than Spring Boot's class loader. This is problematic as it's only Spring Boot's class loader that can load the classes from the dependencies that are nested inside the fat jar. The result being that the application cannot load the classes of any of its dependencies.
Spring Boot 1.3 overcame this problem by using an unconventional delegation model for its class loader. It created a new class loader using the URLs from the system class loader but not using the system class loader as a parent – the system class loader's parent was used instead. This meant that Spring Boot's class loader would be used to load the application's classes in the root of the jar and the classes of the application's dependencies in the nested jars.
This approach had some drawbacks. The first was that it made Spring Boot's class loader rather complex. The second was that it broke a number of assumptions that Java agents make with regards to how their classes will be loaded. We worked around a couple of these but it became clear that we were fighting a losing battle.
Spring Boot 1.4 rearranges a fat jar to place application classes in BOOT-INF/classes
(it also moves nested jars to BOOT-INF/lib
but that has no effect from a class loading perspective). Moving the application classes into BOOT-INF/classes
means that they are no longer on the class path of the system class loader. This means that Spring Boot's class loader can be configured to load classes from BOOT-INF/classes
and from within the jars in BOOT-INF/lib
and use the system class loader as its parent. Java agents can be packaged in the root of the jar from where they'll be loaded by the system class loader as usual.
For further reading you may be interested in the message on the commit that introduced the change and the other issues to which it links.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With