
We speed up the assembly and delivery of java web applications
TLTD
- removed jar from project build
- replaced it with task, which is 7 times faster
Details and result under the cut.
about the project
A web service in java that gives out rest api and websockets , but inside it can go to a distributed database and distributed cache .
The project uses embedded jetty to start, runs through public status void method
.
It is delivered to the server as fat jar and is launched through java -jar myapp.jar app.yaml
We profile
Gradle is a great tool that comes out of the box with a profiler. Run the build with the parameter --profile
and wait for the result.
./gradlew clean build --profile
I think the result does not need commenting:
We study the problem
First of all, I decided to see how fat jar is being created:
jar {
manifest {
attributes "Main-Class": "com.baeldung.fatjar.Application"
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
In the manifest, write the class with the main method and unpack the jar dependencies into the root folder of the jar archive.
This can be checked if you do it by unpacking the jar unzip myapp.jar
and see the tree of the current foldertree .
It is not surprising that this is slow, many small files need to be unpacked first, and then backed up.
Optimize
Next, I tried to google a faster version of creating a jar file.
I tried gradle plugins:
gradle-fatjar-plugin -
shadow is no longer supported - they managed to assemble them, but it uses the same method as above, so this did not give an increase in speed
gradle-one-jar - could not start at all, honestly, maybe it was necessary just spend more time
Then I got an idea, you can even say a challenge. And how to run applications without jar? I just had the unpacked archive, in order to try this.
It turned out not difficult:
java -cp . com.example.Main app.yml
The project started perfectly, picked up the desired config.
The -cp parameter is a classpath that tells java the process where all the project classes are located.
So the project can live without jar? Using a little help from the gradle community, I got a task that creates an exploded version of the jar:
task explodedJar(type: Copy) {
with jar
into "${buildDir}/exploded"
into('lib') {
from configurations.runtimeClasspath
}
}
jar.enabled = false
assemble.dependsOn explodedJar
Task
- puts all classes and resources in a
exploded
folder - puts all runtime dependencies in the lib folder
- adds explodedJar and excludes task jar from ./gradle build
Run again
./gradlew build --profile
Enjoy the result
I think comments are not needed here again.
Here it may still be worth duplicating the histogram from the beginning of the article, but I will not do this.
But how to deploy?
In order not to make this article very long, just leave one command to copy the project to the server:
rsync --delete -r build/exploded api.example.com:/opt/myapp
Total
- The project has become easier due to the fact that we removed from it such an entity as
jar
- You can always see what exactly gets into our assembly by simply opening the folder
build/exploded
- And of course, the project began to assemble and share faster