Previously, if an application’s main method threw an exception,
MainMethodRunner would catch the exception and call System.exit(1).
This meant that the JVM would exit, irrespective of whether or not
any non-daemon threads were running. In contrast, when an application’s
main method was invoked directly (in an IDE, for example) the JVM
would not exit if one or more non-daemon threads were running. This
is standard JVM behaviour that we should be consistent with in the
launcher.
This commit updates MainMethodRunner to wrap any exception thrown by an
application’s main method in a RuntimeException and rethrow it. This
alllows the JVM to handle the exception and use its normal rules for
deciding whether or not it should exit.
Closes gh-4984
PropertiesLauncher creates a ClassLoader that is used by the Launcher
to load an application’s classes. During the creation of this
ClassLoader URLs from its ClassLoader. This resulted resulting in Java
agents that are added to the system class loader via the -javaagent
launch option being available on both the system class loader and the
created class loader. Java agents are intended to always be loaded by
the system class loader. Making them available on another class loader
breaks this model.
This is the same problem that was in ExecutableArchiveLauncher and
that was fixed in ee08667e (see gh-863).
This commit updates PropertiesLauncher so that it skips the URLs of
any Java agents (found by examining the JVM’s input arguments) when
copying URLs over to the new ClassLoader, thereby ensuring that Java
agents are only ever loaded by the system class loader.
Closes gh-4911
This commit completes the changes to consistently used static final
fields for Log instances that were started in ec2f33f9. Specifically it:
- Removes this. when accessing logger fields that are now static
- Renames some fields from log to logger
- Makes some logger fields static
See gh-4784
Update exit code support to allow the ExitCodeGenerator interface to
be placed on an Exception. Any uncaught exception implementing the
interface and returning a non `0` status will now trigger a System.exit
with the code.
Fixes gh-4803
Some libraries like aspectj are using findResource to see the raw
bytecode of a class. It will even call findResource for every method of
every class of beans that are post processed. This can be significant
performance hit on startup when LaunchedURLClassLoader and there are a
lot of nested jars.
See gh-3640
Fixes gh-4557
Some libraries like aspectj are using findResource to see the raw
bytecode of a class. It will even call findResource for every method of
every class of beans that are post processed. This can be significant
performance hit on startup when LaunchedURLClassLoader and there are a
lot of nested jars.
See gh-3640
Fixes gh-4557
Previously, JarFileArchive would always unpack any entries marked for
unpacking to ${java.io.tmpdir}/spring-boot-libs. This could cause
problems if multiple Spring Boot applications were running on the same
host:
- If the apps are run as different users the first application would
create the spring-boot-libs directory and the second and subsequent
applications may not have write permissions to that directory
- Multiple apps may overwrite each others unpacked libs. At best this
will mean one copy of a jar is overwritten with another identical
copy. At worst the jars may have different contents so that some of
the contents of the original jar disappear unexpectedly.
This commit updates JarFileArchive to use an application-specific
location when unpacking libs. A directory beneath ${java.io.tmpdir} is
still used but it's now named <jar-file-name>-spring-boot-libs-<uuid>.
A loop, limited to 1000 attempts, is used to avoid problems caused by
the uuid clashing.
Closes gh-4124
When nested jars are being used, hasMoreElements requires opening a
connection for an entry in every nested jar. If that entry doesn't
exist, a FileNotFoundException is thrown to indicate that a particular
jar doesn't contain the requested entry. This exception is used to
indicate the lack of an entry and is then swallowed, i.e. its stack
trace is of no importance. This means that the performance of
hasMoreElements can be improved by switching on fast exceptions while
it's being called. When fast exceptions are switched on a general
purpose pre-initialized FileNotFoundException is thrown rather than
creating a new FileNotFoundException instance each time.
In certain situations, the use of fast exceptions as described above
can improve performance fairly significantly. The JRE's default SAAJ
implementation uses META-INF/services-based discovery for _every_
request that's handled by Spring Web Services. Each discovery attempt
results in hasMoreElements being called making its performance
critical to throughput.
See gh-3640
I think this is safe, judging by the integration tests, but I'm not
putting it in 1.2.x until we've had some feedback on it. The
integration tests actually had a bug that was masking this problem
because they were merging Properties from the whole classpath instead
of picking the first available resource (which is generally what
we do in Spring Boot applications for application.properties for
instance).
Fixes gh-3048
The format is rather unusual.
The time is 16 bits: 5 bits for the hour, 6 bits for the minutes, and 5
bits for the seconds. 5 bits only allows 32 values (0-31) so the number
must be doubled, meaning that the time is only accurate to the nearest
two seconds. Also, the JDK rounds this down by subtracting one. The
doubling and rounding is performed by shifting one place to the left
and masking off the right-most bit respectively.
The date is 16 bits: 7 bits for the year, 4 bits for the month, and 5
bits for the day. The year is from 1980, i.e. the earliest date that
can be represented is 1980-01-01.
See http://mindprod.com/jgloss/zip.html for more details of the format.
Fixes gh-2826
Running the invoker plugin with multiple threads against an empty
Maven cache results in strange build failures where Maven claims that
it cannot find a jar or pom file for an artifact that it should be
able to find. It would appear that Maven is unable to cope with
concurrent writes to its cache.
This commit removes the usage of multiple threads that was introduced
in 4e907f1.
Fixes gh-2389
If user runs an executable archive then it and its lib directory will be
on the classpath. Entries from loader.path take precedence in a way that
should make sense to users (earlier wins like in CLASSPATH env var).
Also added new integration tests to verify the behaviour (big improvement
on the old ones, which probably aought to be beefed up to the same
standard).
Fixes gh-2314
Previously, WarLauncher included its root on the classpath. It also used
a filtered version of its root archive to hide both the WEB-INF and
META-INF directories. This meant that files in WEB-INF and META-INF
could be found by the classloader (as they were on the classpath) but
could not be read as the filtered archive was hiding them.
This commit updates WarLauncher to remove the root of the war file from
the classpath. It also removes the filtering of the archive, thereby
allowing files in META-INF and WEB-INF to be accessed via the
ServletContext.
Closes gh-1792
* Windows: allow absolute file paths without file:/// prefix
* All: only add nested archives (not directories), so loader.path=lib/*
behaves the same as -classpath=lib/* (except for adding zip files)
Fixes gh-1352
The ExplodedArchive would erroneously always attempt to filter
its contents (and thereby shield them from a classloader that wrapped
it) even if they haven't been explicitly provided.
See gh-1352
Use Java 7 `registerAsParallelCapable` and `getClassLoadingLock` methods
when possible. This should improve performance when running on JDK 7+
whilst still remaining JDK 6 compatible.
Closes gh-1284
Fix 'fat jar' support for windows to correctly deal with URL and path
slash issues. The root cause of the original problem was caused by JAR
URLs not including a root slash (ie `file:C:/Users` vs `file:/C:/Users`)
Fixes gh-1145
Update ExecutableArchiveLauncher so that `-cp` URLs are not added
when they are already contained as nested JARs. This prevents a
SecurityException "signer information does not match error" when using
signed jars. The root cause of the issue was that the primary JAR file
was on the default classpath with the URL "file:....jar" and in the
main URL set as "jar:file:....jar". It is now filtered so that only
the "jar:" variant is added.
Fixes gh-1134
Update the executable JAR code to automatically unpack any entries
which include an entry comment starting `UNPACK:` to the temp folder.
The existing Maven and Gradle plugins have been updated with new
configuration options and the `spring-boot-tools` project has been
updated to write the appropriate entry comment based on a flag passed
in via the `Library` class.
This support has been added to allow libraries such a JRuby (which
assumes that `jruby-complete.jar` is always accessible as file) to work
with Spring Boot executable jars.
Fixes gh-1070
Update JarURLConnection to allow the resolution of items within a nested
jar, even if the jarFile passed to the connection is several levels up.
This prevent a connection from incorrectly resolving an entry against
the wrong jar file.
See gh-1070
Tweak 'fat jar' handling to generally improve performance:
- Allow JarURLConnection to throw a static FileNotFoundException when
loading classes. This exception is thrown many times when attempting
to load a class and is silently swallowed so there is no point in
providing the entry name.
- Expose JarFile.getJarEntryData(AsciiBytes) and store AsciiBytes in
the JarURLConnection. Previously AsciiBytes were created, discarded
then created again.
- Use EMPTY_JAR_URL for the JarURLConnection super constructor. The URL
is never actually used so we can improve performance by using a
constant.
- Extract JarEntryName for possible caching. The jar entry name
extracted from the URL is now contained in an inner JarEntryName
class. This could be cached if necessary (although currently it is
not because no perceivable performance benefit was observed)
Fixes gh-1119
Update JarFile to reuse the previously parsed entries when creating
filtered jars. This saves needing to re-scan the underlying file to
recreate a subset of entries.
See gh-1119
Drop JarEntryFilter arguments from the JarFile constructor and the
getNestedJarFile methods. Filtered JarFiles can still be obtained by
using the getFilteredJarFile() method.
This helps simplify the code a little and will make it easier to add
caching.
See gh-1119
Update `spring-boot-loader` ZIP processing code to support prefixed
bytes within the fat jar. This technique allows a bash script to be
embedded at the start of the JAR whilst still allowing `java -jar`
execution.
Fixes gh-1073
Unify the versions used in integration tests launched by the
maven-invoker-plugin. Allows for already cached local copies to be
used, hopefully speeding up the build.
Unify the versions used in integration tests launched by the
maven-invoker-plugin. Allows for already cached local copies to be
used, hopefully speeding up the build.
ExecutableArchiveLauncher creates a ClassLoader that is used by the
Launcher to load an application’s classes. During the creation of this
ClassLoader URLs from another ClassLoader are copied over. This was
resulting in Java agents that are added to the system class loader
via the -javaagent launch option being available on both the system
class loader and the created class loader. Java agents are intended to
always be loaded by the system class loader. Making them available on
another class loader breaks this model.
This commit updates ExecutableArchiveLauncher so that it skips the URLs
of any Java agents (found by examining the JVM’s input arguments) when
copying URLs over to the new classloader, thereby ensuring that Java
agents are only ever loaded by the system class loader.
Fixes#863
The problem all along has been in AsciiBytes, so the fix in
commit ce3aaf was just a stop gap for a system where multi-byte
characters are supported but the default encoding is not UTF-8 (e.g.
most Windows systems). The real solution is not to leave it to
chance and always pick an encoding for the JarEntry names (i.e.
in AsciiBytes).
(Cherry picked from commit 06e364a9ff)
Fixes gh-764
The problem all along has been in AsciiBytes, so the fix in
commit ce3aaf was just a stop gap for a system where multi-byte
characters are supported but the default encoding is not UTF-8 (e.g.
most Windows systems). The real solution is not to leave it to
chance and always pick an encoding for the JarEntry names (i.e.
in AsciiBytes).
Fixes gh-764
The encoding of UTF-8 (et al.) chars in the
JarUrlConnection has to be made explicit, otherwise
Wdinows apparently does not pick the default(?).
Fixes gh-711, Fixes gh-753
The encoding of UTF-8 (et al.) chars in the
JarUrlConnection has to be made explicit, otherwise
Wdinows apparently does not pick the default(?).
Fixes gh-711, Fixes gh-753
Reverting arguments in assertEquals where constant was placed on
the "actual" place. Replacing assertEquals with assertFalse, assertTrue
and assertNull where applicable.
Fixes gh-735
Update the spring-boot-loader JarURLConnection class to decode entry
names in the same way as the stock JDK class. This allows encoded
entry names in the form `%c3%ab` to be loaded.
Fixes gh-556
It is sufficient for most purposes (e.g. the ones PropertieLauncher needs)
to only read the META-INF directory (not the whole file tree). So a quick
fix is to make META-INF a special case when initializing non-recursive
entries.
Fixes gh-520
Remove README files that have been since been migrated to the reference
documentation. Also updated remaining markdown files to asciidoctor to
save having a mix of different formats.
Fixed gh-503
The source of the exception is in sun.misc (so hard to track down precisely)
but it's clear that the LaunchedJarURLClassLoader needs to be more
defensive and return null from findResource() if it can't find it.
Fixes gh-486
This turns out to affect JPA, but only because it looks for a URL for the
root of the classpath using ClassLoader.getResource("") which barfs in
an app launched from an executable JAR. It's easy to make a special case
for "" in the class loader, so I went ahead and did that. Possibly need
to think what the implication of getResources("") is as well (not
tested in an app yet).
Fixes gh-420
It turns out that loader.path=. was pathological and before this
change ended up making the classpath empty (loader.path=.,lib/
would have fixed it). With this change the old behaviour is still
supported, but if the only user-supplied path entry is "." (or
empty) then it is now kept, and translates into the root of the
current archive if running as "java -jar ...".
Fixes gh-270
Restore previous behavior where JarFile URLs are always prefixed with
"jar:". I believe that the prefix is required in order to remain
compatible with standard JAR URLs.
This reverts commit 825fc2f7df.
Jetty apparently does it differently (different version of
Jasper maybe), so you need a unique jarFileURL for each
nested JAR (previously they were all set to the parent
archive URL).
Also added the root of the main archive as a valid
document root.
For gh-367
Update the executable JAR `Handler` to fallback to the JVM handler if
the jar cannot be opened. This prevents exceptions when trying to
open URLs in the form "jar:jndi:/localhost...".
Fixes gh-347
Change CLI generated JARs to use the standard `JarLauncher` instead of
a custom `JarRunner`. The `PackagedSpringApplicationLauncher` is used
as the `Start-Class` which in turn calls `SpringApplication.run()`.
A new command, jar, has been added to the CLI. The command can be
used to create a self-contained executable JAR file from a CLI app.
Basic usage is:
spring jar <jar-name> <source-files>
For example:
spring jar my-app.jar *.groovy
The resulting jar will contain the classes generated by compiling the
source files, all of the application's dependencies, and entries
on the application's classpath.
By default a CLI application has the current working directory on
its classpath. This can be overridden using the --classpath option.
Any file that is referenced directly by the classpath is always
included in the jar. Any file that is found a result of being
contained within a directory that is on the classpath is subject to
filtering to determine whether or not it should be included. The
default includes are public/**, static/**, resources/**,
META-INF/**, *. The default excludes are .*, repository/**, build/**,
target/**. To be included in the jar, a file must match one of the
includes and none of the excludes. The filters can be overridden using
the --include and --exclude options.
Closes#241
Update JarFile to allow the custom registration of a JAR
`URLStreamHandler` that allows `jar:` URLs to be constructed from
Strings. This removes the previous requirement that all nested JAR URLs
be created with a 'context'.
To supported nested JARs the `java.protocol.handler.pkgs` system
property is changed so that our custom URLHandler is picked for 'jar'
protocols in preference to the Java default.
Fixes gh-269
Fix JarEntryData to re-read the local header, rather than relying on
the central directory record.
This protects against the situation where a JAR file is written with an
'Extra Field Length' that is different in the local header to the
central directory header.
This appears to be the case with aspectj 1.7.4 which contains the
following central directory file header for ProceedingJoinPoint:
50 4B 01 02 signature
14 03 version made by
0A 00 version required
00 00 general
08 00 compress methods
0E 40 59 43 last modified
2D 59 20 70 crc
EC 00 00 00 csize
8D 01 00 00 size
2A 00 fname len
00 00 ext field len
00 00 file comment len
00 00 disk num
00 00 int file att
00 00 A4 81 ext file att
97 F3 00 00 relative offset of the local file header
... file name
and the following local header:
50 4B 03 04 signature
0A 00 version required
00 00 general
08 00 compress method
0E 40 59 43 last modified
2D 59 20 70 crc
EC 00 00 00 csize
8D 01 00 00 size
2A 00 fname len
14 00 ext field len
... file name
... extra field
Note that the 'ext field len' is 0x00 in the central record but 0x14 in
the local record.
Fixes gh-203