First of all Spring Boot is awesome. What might make it even more awesome? Have the Maven plugin package a .jar without all the dependencies; resolving them at first run. See https://github.com/puniverse/capsule. Perhaps Spring Boot could provide a flag for doing such?
Comment From: joshlong
Hmm - Isn't that just a .jar? Just comment out the build plugin and do mvn dependency:copy-dependencies and then make sure the jar has those libs on the CLASSPATH. Or is hat last bit what you're after?
Comment From: joshlong
Oooh - just looked at capsule. I dig it! That would be cool..
Comment From: thomasdarimont
Interesting - what happens if some dependencies can't be resolved? I guess in this case you'd end up with a broken app...
But the idea is really interesting - you could also use that or automatic update checks at startup... Regarding spawning a new JVM, can you also plug something in like: drip?https://github.com/ninjudd/drip
Comment From: fastnsilver
How often are you NOT able to resolve an artifact? A good deal of time (on build) is due to config and/or networking. Yes, there is chance of a broken app (when dependencies aren't completely resolved), but isn't that something that a smoke test or test run after deployment would catch? I'm just thinking out loud here.
Comment From: philwebb
Someone actually started a contribution for this (see https://github.com/patrikbeno/spring-boot/blob/MvnLauncher/spring-boot-docs/src/main/asciidoc/mvnlauncher.adoc). We had a brief email conversation and this was my response at the time:
Providing on-demand download support is something that we have considered in the past and I think it is an interesting approach, however, I have a few reservations. My primary concern is that packaged applications become much more brittle when they need to download dependencies during production deployment. Do you find the larger self-contained JARs problematic? Is the main goal to reduce duplication by allowing multiple applications to share the same download cache? Does your operations team like the approach?
I think it would be worth trying to find a way to support the MvnLauncher
without needing to add too many additional classes to the spring-boot-loader project. Since classes from spring-boot-loader get repackaged into use projects I’m very keen to keep its size fairly small. I’m not sure that on-demand loading will be something that the majority of users will want to use (although I’m happy to be proved wrong if we get enough votes for the feature) so I’d like to not impact people who might not want it.
Comment From: philwebb
I still feel that on-demand downloading is a risky thing to support out of the box.
Comment From: odrotbohm
The actual problem caused with fat-JAR deployments is that — especially if the end of you CI pipeline installs the artifact into a repository — you basically accumulate a lot of artifacts that have other artifacts wrapped in them. Other artifacts that are actually also available in the repository.
What if the resolution process was something to opt in via e.g. a command line flag and you could express that you might want to run the resolution against a well known local folder (e.g. .m2/repository
only)? /cc @ewolff
Comment From: ewolff
In addition it would be great if such a .m2/repository
could be created by Spring Boot.
Comment From: odrotbohm
I guess we' have to use means to invoke Maven (or $buildSystem
in general) for the artifact resolution. Manually replacing artifacts in an already existing repository is probably a tricky thing, esp. considering that multiple of those resolutions could run in parallel.
I know that the actual list of dependencies could be precomputed so that the calculation doesn't have to be done at resolution time but even downloading manually those artifacts might cause issues with the artifact metadata (or we'd have to replicate the update of that metadata, which is even worse).
Comment From: ewolff
Maybe I wasn't clear. I imagine mvn spring-boot:package-dependencies
would give me all dependencies needed in a single repository.zip
that I could unpack on a machine to prepare it for the application.
When I start the application java -jar myjar.jar
it should somehow use them and download additional artifacts if needed. That way I can prepare a Docker base image that already includes the dependencies.
Comment From: odrotbohm
Where'd you store the packaged ZIP then? Wouldn't (that have to) be deployed into the repository, too?
Comment From: ewolff
I'd extract it into the Docker base image.
Comment From: dsyer
I had a look at this and threw together something that works. It could be tidied up a bit, but it seems like a useful direction: https://github.com/scratches/launcher.
Comment From: wilkinsona
If we're going to do something with lighter weight packaging, @dsyer's thin launcher looks to be the way to go. Before we can consider making it part of Boot we need to get some feedback on it. So, if you're interested in this functionality, please check out what Dave has done and let us know how well it works for you.
Comment From: odrotbohm
I've just added the thin launcher to a branch in Spring Restbucks. Very easy setup, works just fine. However, I couldn't get any output about what it's doing using the advertised command line flags and filed a ticket.
Comment From: fastnsilver
Really nice work @dsyer! You considered and solved for quite a few more use cases than I had originally thought of. I will definitely recommend this packaging approach going forward. Seems like it should be baked into Spring Boot Maven Plugin rather than as a separate dependency. But I certainly understand why.
I like that you can target a Maven repo with thin.root
. One thought occurred to me... and that's if a settings.xml
in that location refers to an artifact management repository, like Nexus or Artifactory (that is responsible for resolving "in-house/private" artifacts). If you happen to deploy an artifact (e.g., executable .jar), that has dependencies on "in-house" artifacts, to a target deployment environment (e.g., VM or container), some care should be taken. I'm thinking of a scenario where e.g., Artifactory resides in a separate (potentially unreachable) network than where the artifact will be running. In that case some kind of mirroring or proxying must be setup in the target environment to minimize exposing any "ip". << Definitely outside the concern of this implementation.
That said I see you can enable thin.dryrun
so if you package your .jar in a container you could run this first when packaging. So, the result is that you have all the dependencies baked into your image anyway, just in a Maven repo, and not in your "thin jar". Looks like you are doing something similar in the fork of java-buildpack
for Cloud Foundry.
Comment From: dsyer
@fastnsilver I believe your settings.xml
should work out of the box (we use the maven libraries to resolve dependencies). Try it and post a new issue in the thin-launcher repo if not.
Comment From: philwebb
Closing this one in favor of the thin jar launcher
Comment From: statsmind
thin plugin is great, but, most of my projects are multi-module ones, I don't want to deploy the project modules to a private maven repository, is there any way I can pack the project-module jars into the thin jar?
Comment From: philwebb
@jameshugit You'd have to raise a request at https://github.com/spring-projects-experimental/spring-boot-thin-launcher/issues
Comment From: dsyer
Like https://github.com/spring-projects-experimental/spring-boot-thin-launcher/issues/78 or https://github.com/spring-projects-experimental/spring-boot-thin-launcher/issues/15 (ie no need for a new issue there).
Comment From: Kylin824
thin plugin is great, but, most of my projects are multi-module ones, I don't want to deploy the project modules to a private maven repository, is there any way I can pack the project-module jars into the thin jar?
i have the same question