Commit fc6c5741 authored by Andy Wilkinson's avatar Andy Wilkinson

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

Closes gh-5195
parent 0ba605db
......@@ -46,7 +46,7 @@ Spring Boot Loader compatible jar files should be structured in the following wa
+-classes
| +-mycompany
| +-project
| +-YouClasses.class
| +-YourClasses.class
+-lib
+-dependency1.jar
+-dependency2.jar
......@@ -77,7 +77,7 @@ Spring Boot Loader compatible war files should be structured in the following wa
| +-com
| +-mycompany
| +-project
| +-YouClasses.class
| +-YourClasses.class
+-lib
| +-dependency1.jar
| +-dependency2.jar
......@@ -95,26 +95,26 @@ a traditional web container should be placed in `WEB-INF/lib-provided`.
[[executable-jar-jarfile]]
=== Spring Boot's "`JarFile`" class
The core class used to support loading nested jars is
`org.springframework.boot.loader.jar.JarFile`. It allows you load jar
content from a standard jar file, or from nested child jar data. When first loaded, the
`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
location of each `JarEntry` is mapped to a physical file offset of the outer jar:
[indent=0]
----
myapp.jar
+---------+---------------------+
| | /lib/mylib.jar |
| A.class |+---------+---------+|
| || B.class | B.class ||
| |+---------+---------+|
+---------+---------------------+
^ ^ ^
0063 3452 3980
+-------------------+-------------------------+
| /BOOT-INF/classes | /BOOT-INF/lib/mylib.jar |
|+-----------------+||+-----------+----------+|
|| A.class ||| B.class | C.class ||
|+-----------------+||+-----------+----------+|
+-------------------+-------------------------+
^ ^ ^
0063 3452 3980
----
The example above shows how `A.class` can be found in `myapp.jar` position `0063`.
`B.class` from the nested jar can actually be found in `myapp.jar` position `3452`
and `B.class` is at position `3980`.
The example above shows how `A.class` can be found in `/BOOT-INF/classes` in `myapp.jar`
position `0063`. `B.class` from the nested jar can actually be found in `myapp.jar`
position `3452` and `C.class` is at position `3980`.
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
......@@ -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`).
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
`[Jar|War]Launcher` the nested paths are fixed (`+lib/*.jar+` and `+lib-provided/*.jar+` for
the war case) so you just add extra jars in those locations if you want more. The
`PropertiesLauncher` looks in `lib/` in your application archive by default, but you can
add additional locations by setting an environment variable `LOADER_PATH` or `loader.path`
files in directories (as opposed to explicitly on the classpath). In the case of
`JarLauncher` and `WarLauncher` the nested paths are fixed. `JarLauncher` looks in
`BOOT-INF/lib/` and `WarLauncher` looks in `WEB-INF/lib/` and `WEB-INF/lib-provided/` so
you just add extra jars in those locations if you want more. The `PropertiesLauncher`
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).
......@@ -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.
* `loader.path` can contain directories (scanned recursively for jar and zip files),
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
properties file itself on all values before use.
......
......@@ -2590,31 +2590,42 @@ details.
[[howto-build-an-executable-archive-with-ant]]
=== 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
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:
. Use the appropriate launcher as a `Main-Class`, e.g. `JarLauncher` for a jar file, and
specify the other properties it needs as manifest entries, principally a `Start-Class`.
. Add the runtime dependencies in a nested '`lib`' directory (for a jar) and the
`provided` (embedded container) dependencies in a nested `lib-provided` directory.
Remember *not* to compress the entries in the archive.
. If you are building a jar, package the application's classes and resources in a nested
`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 `BOOT-INF/lib` directory for a jar or
`WEB-INF/lib` for a war. 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`
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:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
[source,xml,indent=0]
----
<target name="build" depends="compile">
<copy todir="target/classes/lib">
<fileset dir="lib/runtime" />
</copy>
<jar destfile="target/spring-boot-sample-actuator-${spring-boot.version}.jar" compress="false">
<fileset dir="target/classes" />
<fileset dir="src/main/resources" />
<zipfileset src="lib/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
<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}" />
......@@ -2623,11 +2634,12 @@ Example:
</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"]
----
$ 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
......
......@@ -13,6 +13,7 @@
<property name="spring-boot.version" value="1.4.0.BUILD-SNAPSHOT" />
<property name="lib.dir" location="${basedir}/target/lib" />
<property name="start-class" value="sample.ant.SampleAntApplication" />
<target name="resolve" description="--> retrieve dependencies with ivy">
<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" />
</target>
<target name="clean-all" description="cleans all created files/dirs" depends="clean">
<delete dir="${lib.dir}" />
</target>
<target name="clean" description="cleans all class files">
<delete dir="target/classes" />
<target name="clean" description="cleans all created files/dirs">
<delete dir="target" />
</target>
<target name="build" depends="compile">
......@@ -47,4 +44,26 @@
</spring-boot:lib>
</spring-boot:exejar>
</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>
......@@ -3,8 +3,10 @@
<configurations>
<conf name="compile" description="everything needed to compile 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>
<dependencies>
<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>
</ivy-module>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment