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 ...@@ -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 ...@@ -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`. ...@@ -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 ...@@ -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 ...@@ -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.
......
...@@ -2590,31 +2590,42 @@ details. ...@@ -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> <fileset dir="target/classes" />
<jar destfile="target/spring-boot-sample-actuator-${spring-boot.version}.jar" compress="false"> <globmapper from="*" to="BOOT-INF/classes/*"/>
<fileset dir="target/classes" /> </mappedresources>
<fileset dir="src/main/resources" /> <mappedresources>
<zipfileset src="lib/loader/spring-boot-loader-jar-${spring-boot.version}.jar" /> <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: ...@@ -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
......
...@@ -13,6 +13,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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>
...@@ -3,8 +3,10 @@ ...@@ -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>
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