Suche Komprimierungsplugin für maven/gradle?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

Im Folgenden ein paar Punkte, die man in Erwägung ziehen könnte. Für die Analyse würde ich ein Tool wie 7-Zip empfehlen, mit dem man die JAR-Datei entpacken und somit ihren Inhalt anschauen kann.

1) Kompression via Maven/Gradle

Was m.E. zuerst Erwähnung finden sollte: Maven und Gradle führen beim Packen der JAR selbst eine Kompression durch, sofern nicht anders konfiguriert. Maven hat für eine Kompression den compress-Tag, Gradle das Jar.entryCompression-Property.

2) pom.xml / gradle.build aufräumen

Natürlich sollten nur die wirklich relevanten Abhängigkeiten aufgeführt werden. Dependencies für das Testen/Debugging (JUnit u.ä.) gehören in den Test-Scope.

Beispiel für Maven:

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.2</version>
  <scope>test</scope>
</dependency>

Beispiel für Gradle:

dependencies {
  testImplementation 'junit:junit:4.13.2'
}

3) Unnötigen Code entfernen

Entferne Debuginformationen / Loggings / o.ä., was für eine Releaseversion nicht benötigt wird. Achte darauf, dass nur die Dateien in die JAR wandern, die auch in sie hineingehören.

a) Ob eine class-Datei Debuginformationen beinhaltet, kann man mit javap prüfen:

javap -v path/to/class/file

Debuginformationen explizit ausschließen kann man über die Compiler-Option -g:

javac -g:none path/to/java/file

Mit Maven lässt sich die Option über das maven-compiler-plugin (debug-Tag) setzen oder beim Build über die Konsole via maven.compiler.debuglevel-Option. In Gradle sollte es so klappen:

apply plugin: 'java'

compileJava {
  options.compilerArgs << '-g:none'
}

b) Dateien u.ä. kann man über exclude-Regeln vorsätzlich aus dem Build ausschließen. Bei Maven wäre wieder einmal das Compiler-Plugin nützlich (lies hier), bei Gradle die Jar.exclude-Methode.

jar {
  exclude('file pattern 1', 'file pattern 2', /* etc. */)
}

So eine Analyse hilft im Übrigen, Buildfehler aufzudecken (bspw. wenn statt class-Dateien auch java-Dateien in der JAR landen).

4) Ressourcenkomprimierung

Das größte Problem liegt meist in den inkludierten Ressourcen (Bilder, Videos, o.ä.). Große Bilder sollten (wenn möglich) herunterskaliert werden. Wenn sie schon im Vorhinein komprimiert wurden (was in der Regel der Fall ist), kann der Algorithmus für die JAR-Kompression an dieser Stelle nur noch schwer ansetzen. Also wäre es gut, zumindest gut komprimierbare Formate mit einfachen Inhalten (z.B. mehr Flächen als Details) zu nutzen (z.B. PNG, JPG - letzteres Format verliert allerdings schnell an Qualität).

5) Software / Plugins zur Kompression

Außerdem gibt es Plugins, um eine sogenannte Uber-JAR zu erstellen. Dabei werden alle tatsächlichen Projektabhängigkeiten in eine große JAR gepackt. Externe Abhängigkeiten können entpackt werden, z.T. ist bei diesem Prozess eine Filterung möglich.

  • maven-shade-plugin (für Java 8+-Projekte kannst du zusätzlich die minimizeJar-Konfiguration nutzen)
  • shadow (die maven-shade-plugin-Alternative für Gradle)

6) Ressourcen auslagern / nachladen

Manche Ressourcen kann man evt. von Anfang an außerhalb der JAR halten (weil eine Kompression sie bspw. eher vergrößert, als verkleinert) oder bei Programmstart / zu gegebener Zeit über eine Internetverbindung nachladen. Ob und für welche Inhalte das sinnvoll wäre, müsste man allerdings je nach Projekt entscheiden. Ein Beispiel, welches mir spontan einfallen würde, wäre ein Video.

7) Dependencies analysieren und neubauen

Einige Abhängigkeiten kann man auch selbst neu bauen, um auf diesen Weg bspw. unnötige Debuginformationen o.ä. loszuwerden. Des Weiteren gibt es Tools, mit denen sich analysieren lässt, welche Abhängigkeiten tatsächlich gebraucht werden und welche nicht. Diese könnte man anschließend exkludieren.

Für die Analyse könnte man das maven-dependency-plugin einsetzen. Eine andere Alternative ist tattletale.

Da diese Maßnahme allerdings etwas aufwendiger ist und man dazu auch noch einmal die Lizenzierung prüfen sollte, würde ich diesen Schritt in der Priorität weit nach hinten packen.

Ein Schlusswort: Nicht jede dieser Maßnahmen muss zwingend zu nennenswertem Erfolg führen. Wenn du beispielsweise große Bilder in der JAR hast, die nicht komprimiert werden können, wird die JAR einfach groß bleiben, egal woran du auch schraubst. Ebenso kannst du nicht von jedem Tool die größte Effektivität erwarten. Bei Nutzung von Reflection / dynamischen Class-Loading u.ä. werden Analysetools schnell scheitern.

Wichtig ist es in diesem Zusammenhang, nach dem Build ein bestimmtes Minimum an Testfällen durchzuführen, um sicherzustellen, dass durch die vorgenommenen Konfigurationen nicht versehentlich etwas kaputt gegangen ist.