I've heard people say that they create a fat JAR and deploy it. What do they actually mean ?
The fat jar is the jar, which contains classes from all the libraries, on which your project depends and, of course, the classes of current project.
In different build systems fat jar is created differently, for example, in Gradle one would create it with (instruction):
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'com.example.Main'
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
In Maven it's being done this way (after setting up regular jar):
<pluginRepositories>
<pluginRepository>
<id>onejar-maven-plugin.googlecode.com</id>
<url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
</pluginRepository>
</pluginRepositories>
<!-- ... -->
<plugin>
<groupid>org.dstovall</groupid>
<artifactid>onejar-maven-plugin</artifactid>
<version>1.4.4</version>
<executions>
<execution>
<configuration>
<onejarversion>0.97</onejarversion>
<classifier>onejar</classifier>
</configuration>
<goals>
<goal>one-jar</goal>
</goals>
</execution>
</executions>
</plugin>
The different names are just ways of packaging Java applications.
Skinny – Contains only the bits you literally type into your code editor, and nothing else.
Thin – Contains all of the above plus the application’s direct dependencies of your application (db drivers, utility libraries, etc.).
Hollow – The inverse of thin. It contains only the bits needed to run your application but does not contain the application itself. Basically a pre-packaged “application server” to which you can later deploy your application, in the same style as traditional Java EE application servers, but with important differences.
Fat/Uber – Contains the bit you literally write yourself plus the direct dependencies of your application PLUS the bits needed to run your application “on its own”.
Source: Article from Dzone
The fat jar is the jar, which contains classes from all the libraries, on which your project depends and, of course, the classes of current project.
In different build systems fat jar is created differently, for example, in Gradle one would create it with (instruction):
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'com.example.Main'
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
In Maven it's being done this way (after setting up regular jar):
<pluginRepositories>
<pluginRepository>
<id>onejar-maven-plugin.googlecode.com</id>
<url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
</pluginRepository>
</pluginRepositories>
<!-- ... -->
<plugin>
<groupid>org.dstovall</groupid>
<artifactid>onejar-maven-plugin</artifactid>
<version>1.4.4</version>
<executions>
<execution>
<configuration>
<onejarversion>0.97</onejarversion>
<classifier>onejar</classifier>
</configuration>
<goals>
<goal>one-jar</goal>
</goals>
</execution>
</executions>
</plugin>
Fat jar or uber jar is a jar which contains all project class files and resources packed together with all it's dependencies. There are different methods for achieving such effect:
- dependencies' jars are copied into main jar and then loaded using special class loader (onejar, spring-boot-plugin:repackage)
- dependencies' jars are extracted at the top of main jar hierarchy (maven-assembly-plugin with it's jar-with-dependencies assembly)
- dependencies' jars are unpacked at the top of main jar hierarchy and their packages are renamed (maven-shade-plugin with shade goal)
Below sample assembly plugin configuration jar-with-dependencies:
<project>
<!-- ... -->
<build>
<!-- ... -->
<plugins>
<plugin>
<!-- NOTE: We don't need a groupId specification because the group is
org.apache.maven.plugins ...which is assumed by default.
-->
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<classifier>
</configuration>
<!-- ... -->
</project>
For more detailed explanation: Uber-JAR at imagej.net
In the case of an executable jar, another way to think about a fat jar is one you can execute by invoking:
java -jar myFatLibrary.jar
without the need for -cp
/ --classpath
, or even double clicking the jar icon.
From the Gradle documentation:
In the Java space, applications and their dependencies typically used to be packaged as separate JARs within a single distribution archive. That still happens, but there is another approach that is now common: placing the classes and resources of the dependencies directly into the application JAR, creating what is known as an uber or fat JAR.
Here is a demonstrated of uberJar
task in build.gradle
file:
task uberJar(type: Jar) {
archiveClassifier = 'uber'
from sourceSets.main.output
dependsOn configurations.runtimeClasspath
from {
configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
}
}
In this case, we’re taking the runtime dependencies of the project — configurations.runtimeClasspath.files
— and wrapping each of the JAR files with the zipTree()
method. The result is a collection of ZIP file trees, the contents of which are copied into the uber JAR alongside the application classes.
A fat jar simply contains same classes as a classical jar + classes from all of their runtime dependencies.
With Jeka ( https://jeka.dev) you can achieve it programmatically :
JkPathTreeSet.of(Paths.get("classes")).andZips(
Paths.get("bouncycastle-pgp-152.jar"),
Paths.get("classgraph-4.8.41.jar"),
Paths.get("ivy-2.4.0.jar")
).zipTo(Paths.get("fat.jar"));
or just by parametring Java plugin :
javaPlugin.getProject().getMaker().defineMainArtifactAsFatJar(true);
© 2022 - 2024 — McMap. All rights reserved.