The JVM has become a standard execution environment for a lot of server code. It’s no longer only Java, but also languages such as Scala, Kotlin and Clojure that target the JVM.
However, for creating everyday command line tools I have quite often used languages such as bash, python or ruby, because it is much easier to run such scripts. There are a couple of solutions to bundle JVM executables. In the world of the server side fat jars are the de-facto standard. The major drawback here is the fat. Even for small changes a full new fatjar has to be assembled, which takes time. Also, it slows down the deployment of patches and uses a lot of space in the file system (How many copies of the Scala runtime do you want to keep on your disk?). Another solution is to use something like the maven exec plugin. However this suffers from the problem that it re-resolves dependencies whenever you execute. This is takes time and not deterministic. It also has the disadvantage that it needs to start a JVM before it starts the actual code we are interested in.
The two goals for a JVM launch mechanism would be:
- Deterministic behaviour
- Quick start-up
- Quick compilation
With these goals in mind I started prototyping JLauncher. It allows to run JVM code that is distributed via maven infrastructure in a reliable and fast way.
JLauncher starts a JVM with a defined classpath using a “j-manifest” file. This manifest contains the fully resolved list of dependencies (using maven coordinates). This manifest is ideally created at build time and can be bundled into the jar file.
One could think of it as fat jar without the fat or a shavenmaven for the runtime.
Currently it is a prototype implemented as ruby gem. The reason for this was that ruby comes with batteries included and doesn’t have the JVM start-up tax.
There also is an “install” subcommand that puts an executable script into a dedicated bin directory that can be included in the path.
I also implemented a maven plugin and an sbt plugin to generate the manifest files.
Future work could be done around specifying JVM version and parameters in the manifest as well as making JLauncher support application class data sharing which could speed up the JVM start-up by having pre-compiled class files on the path.
Suggestions, feedback and pull requests are welcome!