Update docs to fully reflect BOOT-INF executable archive layout changes

Closes gh-5195
This commit is contained in:
Andy Wilkinson 2016-04-06 10:56:25 +01:00
parent 0ba605dbb2
commit fc6c57413b
4 changed files with 81 additions and 45 deletions

View File

@ -46,7 +46,7 @@ Spring Boot Loader compatible jar files should be structured in the following wa
+-classes +-classes
| +-mycompany | +-mycompany
| +-project | +-project
| +-YouClasses.class | +-YourClasses.class
+-lib +-lib
+-dependency1.jar +-dependency1.jar
+-dependency2.jar +-dependency2.jar
@ -77,7 +77,7 @@ Spring Boot Loader compatible war files should be structured in the following wa
| +-com | +-com
| +-mycompany | +-mycompany
| +-project | +-project
| +-YouClasses.class | +-YourClasses.class
+-lib +-lib
| +-dependency1.jar | +-dependency1.jar
| +-dependency2.jar | +-dependency2.jar
@ -95,26 +95,26 @@ a traditional web container should be placed in `WEB-INF/lib-provided`.
[[executable-jar-jarfile]] [[executable-jar-jarfile]]
=== Spring Boot's "`JarFile`" class === Spring Boot's "`JarFile`" class
The core class used to support loading nested jars is The core class used to support loading nested jars is
`org.springframework.boot.loader.jar.JarFile`. It allows you load jar `org.springframework.boot.loader.jar.JarFile`. It allows you to load jar
content from a standard jar file, or from nested child jar data. When first loaded, the content from a standard jar file, or from nested child jar data. When first loaded, the
location of each `JarEntry` is mapped to a physical file offset of the outer jar: location of each `JarEntry` is mapped to a physical file offset of the outer jar:
[indent=0] [indent=0]
---- ----
myapp.jar myapp.jar
+---------+---------------------+ +-------------------+-------------------------+
| | /lib/mylib.jar | | /BOOT-INF/classes | /BOOT-INF/lib/mylib.jar |
| A.class |+---------+---------+| |+-----------------+||+-----------+----------+|
| || B.class | B.class || || A.class ||| B.class | C.class ||
| |+---------+---------+| |+-----------------+||+-----------+----------+|
+---------+---------------------+ +-------------------+-------------------------+
^ ^ ^ ^ ^ ^
0063 3452 3980 0063 3452 3980
---- ----
The example above shows how `A.class` can be found in `myapp.jar` position `0063`. The example above shows how `A.class` can be found in `/BOOT-INF/classes` in `myapp.jar`
`B.class` from the nested jar can actually be found in `myapp.jar` position `3452` position `0063`. `B.class` from the nested jar can actually be found in `myapp.jar`
and `B.class` is at position `3980`. position `3452` and `C.class` is at position `3980`.
Armed with this information, we can load specific nested entries by simply seeking to Armed with this information, we can load specific nested entries by simply seeking to
the appropriate part of the outer jar. We don't need to unpack the archive and we the appropriate part of the outer jar. We don't need to unpack the archive and we
@ -141,11 +141,12 @@ file and it's used to setup an appropriate `URLClassLoader` and ultimately call
There are 3 launcher subclasses (`JarLauncher`, `WarLauncher` and `PropertiesLauncher`). There are 3 launcher subclasses (`JarLauncher`, `WarLauncher` and `PropertiesLauncher`).
Their purpose is to load resources (`.class` files etc.) from nested jar files or war Their purpose is to load resources (`.class` files etc.) from nested jar files or war
files in directories (as opposed to explicitly on the classpath). In the case of the files in directories (as opposed to explicitly on the classpath). In the case of
`[Jar|War]Launcher` the nested paths are fixed (`+lib/*.jar+` and `+lib-provided/*.jar+` for `JarLauncher` and `WarLauncher` the nested paths are fixed. `JarLauncher` looks in
the war case) so you just add extra jars in those locations if you want more. The `BOOT-INF/lib/` and `WarLauncher` looks in `WEB-INF/lib/` and `WEB-INF/lib-provided/` so
`PropertiesLauncher` looks in `lib/` in your application archive by default, but you can you just add extra jars in those locations if you want more. The `PropertiesLauncher`
add additional locations by setting an environment variable `LOADER_PATH` or `loader.path` looks in `BOOT-INF/lib/` in your application archive by default, but you can add
additional locations by setting an environment variable `LOADER_PATH` or `loader.path`
in `application.properties` (comma-separated list of directories or archives). in `application.properties` (comma-separated list of directories or archives).
@ -242,7 +243,9 @@ Environment variables can be capitalized with underscore separators instead of p
the default) as long as `loader.config.location` is not specified. the default) as long as `loader.config.location` is not specified.
* `loader.path` can contain directories (scanned recursively for jar and zip files), * `loader.path` can contain directories (scanned recursively for jar and zip files),
archive paths, or wildcard patterns (for the default JVM behavior). archive paths, or wildcard patterns (for the default JVM behavior).
* `loader.path` (if empty) defaults to `lib` (meaning a local directory or a nested one if running from an archive). Because of this `PropertiesLauncher` behaves the same as `JarLauncher` when no additional configuration is provided. * `loader.path` (if empty) defaults to `lib` (meaning a local directory or a nested one if
running from an archive). Because of this `PropertiesLauncher` behaves the same as
`JarLauncher` when no additional configuration is provided.
* Placeholder replacement is done from System and environment variables plus the * Placeholder replacement is done from System and environment variables plus the
properties file itself on all values before use. properties file itself on all values before use.

View File

@ -2590,31 +2590,42 @@ details.
[[howto-build-an-executable-archive-with-ant]] [[howto-build-an-executable-archive-with-ant]]
=== Build an executable archive from Ant without using spring-boot-antlib === Build an executable archive from Ant without using spring-boot-antlib
To build with Ant you need to grab dependencies, compile and then create a jar or war To build with Ant you need to grab dependencies, compile and then create a jar or war
archive as normal. To make it executable you can either use the `spring-boot-antlib` archive. To make it executable you can either use the `spring-boot-antlib`
module, or you can follow these instructions: module, or you can follow these instructions:
. Use the appropriate launcher as a `Main-Class`, e.g. `JarLauncher` for a jar file, and . If you are building a jar, package the application's classes and resources in a nested
specify the other properties it needs as manifest entries, principally a `Start-Class`. `BOOT-INF/classes` directory. If you are building a war, package the application's
classes in a nested `WEB-INF/classes` directory as usual.
. Add the runtime dependencies in a nested '`lib`' directory (for a jar) and the . Add the runtime dependencies in a nested `BOOT-INF/lib` directory for a jar or
`provided` (embedded container) dependencies in a nested `lib-provided` directory. `WEB-INF/lib` for a war. Remember *not* to compress the entries in the archive.
Remember *not* to compress the entries in the archive. . Add the `provided` (embedded container) dependencies in a nested `BOOT-INF/lib`
directory for jar or `WEB-INF/lib-provided` for a war. Remember *not* to compress the
entries in the archive.
. Add the `spring-boot-loader` classes at the root of the archive (so the `Main-Class` . Add the `spring-boot-loader` classes at the root of the archive (so the `Main-Class`
is available). is available).
. Use the appropriate launcher, e.g. `JarLauncher` for a jar file, as a `Main-Class`
attribute in the manifest and specify the other properties it needs as manifest entries,
principally a `Start-Class`.
Example: Example:
[source,xml,indent=0,subs="verbatim,quotes,attributes"] [source,xml,indent=0]
---- ----
<target name="build" depends="compile"> <target name="build" depends="compile">
<copy todir="target/classes/lib"> <jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
<fileset dir="lib/runtime" /> <mappedresources>
</copy>
<jar destfile="target/spring-boot-sample-actuator-${spring-boot.version}.jar" compress="false">
<fileset dir="target/classes" /> <fileset dir="target/classes" />
<fileset dir="src/main/resources" /> <globmapper from="*" to="BOOT-INF/classes/*"/>
<zipfileset src="lib/loader/spring-boot-loader-jar-${spring-boot.version}.jar" /> </mappedresources>
<mappedresources>
<fileset dir="src/main/resources" erroronmissingdir="false"/>
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="${lib.dir}/runtime" />
<globmapper from="*" to="BOOT-INF/lib/*"/>
</mappedresources>
<zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
<manifest> <manifest>
<attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" /> <attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" /> <attribute name="Start-Class" value="${start-class}" />
@ -2623,11 +2634,12 @@ Example:
</target> </target>
---- ----
The Actuator Sample has a `build.xml` that should work if you run it with The {github-code}/spring-boot-samples/spring-boot-sample-ant[Ant Sample] has a
`build.xml` with a `manual` task that should work if you run it with
[indent=0,subs="verbatim,quotes,attributes"] [indent=0,subs="verbatim,quotes,attributes"]
---- ----
$ ant -lib <folder containing ivy-2.2.jar> $ ant -lib <folder containing ivy-2.2.jar> clean manual
---- ----
after which you can run the application with after which you can run the application with

View File

@ -13,6 +13,7 @@
<property name="spring-boot.version" value="1.4.0.BUILD-SNAPSHOT" /> <property name="spring-boot.version" value="1.4.0.BUILD-SNAPSHOT" />
<property name="lib.dir" location="${basedir}/target/lib" /> <property name="lib.dir" location="${basedir}/target/lib" />
<property name="start-class" value="sample.ant.SampleAntApplication" />
<target name="resolve" description="--> retrieve dependencies with ivy"> <target name="resolve" description="--> retrieve dependencies with ivy">
<ivy:retrieve pattern="${lib.dir}/[conf]/[artifact]-[type]-[revision].[ext]" /> <ivy:retrieve pattern="${lib.dir}/[conf]/[artifact]-[type]-[revision].[ext]" />
@ -32,12 +33,8 @@
<javac srcdir="src/main/java" destdir="target/classes" classpathref="compile.classpath" /> <javac srcdir="src/main/java" destdir="target/classes" classpathref="compile.classpath" />
</target> </target>
<target name="clean-all" description="cleans all created files/dirs" depends="clean"> <target name="clean" description="cleans all created files/dirs">
<delete dir="${lib.dir}" /> <delete dir="target" />
</target>
<target name="clean" description="cleans all class files">
<delete dir="target/classes" />
</target> </target>
<target name="build" depends="compile"> <target name="build" depends="compile">
@ -47,4 +44,26 @@
</spring-boot:lib> </spring-boot:lib>
</spring-boot:exejar> </spring-boot:exejar>
</target> </target>
<!-- Manual equivalent of the build target -->
<target name="manual" depends="compile">
<jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
<mappedresources>
<fileset dir="target/classes" />
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="src/main/resources" erroronmissingdir="false"/>
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="${lib.dir}/runtime" />
<globmapper from="*" to="BOOT-INF/lib/*"/>
</mappedresources>
<zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
<manifest>
<attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" />
</manifest>
</jar>
</target>
</project> </project>

View File

@ -3,8 +3,10 @@
<configurations> <configurations>
<conf name="compile" description="everything needed to compile this module" /> <conf name="compile" description="everything needed to compile this module" />
<conf name="runtime" extends="compile" description="everything needed to run this module" /> <conf name="runtime" extends="compile" description="everything needed to run this module" />
<conf name="loader" description="Spring Boot loader used when manually building an executable archive" />
</configurations> </configurations>
<dependencies> <dependencies>
<dependency org="org.springframework.boot" name="spring-boot-starter" rev="${spring-boot.version}" conf="compile" /> <dependency org="org.springframework.boot" name="spring-boot-starter" rev="${spring-boot.version}" conf="compile" />
<dependency org="org.springframework.boot" name="spring-boot-loader" rev="${spring-boot.version}" conf="loader->default" />
</dependencies> </dependencies>
</ivy-module> </ivy-module>