Что такое толстая банка?

Я слышал, как люди говорят, что они создают толстый JAR и развертывают его. Что они на самом деле означают?


person erwaman    schedule 03.10.2013    source источник
comment
когда вы хотите отправить свой продукт в виде jar-файла, вы обычно хотите поместить классы во всех зависимых jar-файлах в один большой файл jar.   -  person nishu    schedule 03.10.2013
comment
Исходный ответ указывал на эту ссылку: javacodegeeks.com/2012/11/   -  person George Stocker    schedule 30.10.2014
comment
Интересно, является ли толстая банка Java-эквивалентом статической ссылки в c   -  person Sridhar Sarnobat    schedule 23.07.2017


Ответы (6)


Толстая банка - это банка, которая содержит классы из всех библиотек, от которых зависит ваш проект, и, конечно же, классы текущего проекта.

В разных системах сборки fat jar создается по-разному, например, в Gradle его можно создать с помощью (инструкция):

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
}

В Maven это делается так (после настройки обычной банки):

<pluginRepositories>
   <pluginRepository>
        <id>onejar-maven-plugin.googlecode.com</id>
        <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
   </pluginRepository>

<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>
person Dmitry Ginzburg    schedule 28.04.2015
comment
Так толстая банка - это просто еще одно название убер-банки? - person gturri; 18.11.2015
comment
@gturri Да, именно так. - person Dmitry Ginzburg; 25.11.2015
comment
Зачем использовать какой-то сторонний плагин, если есть плагин сборки maven с его сборкой jar-with-dependencies? - person MeTTeO; 10.04.2016
comment
@MeTTeO вы можете добавить свой ответ без использования плагина. - person Dmitry Ginzburg; 10.04.2016
comment
Я думаю, что Uber-jar - это конкретная реализация концепции комплектации, тогда как толстая банка - это просто сама концепция. - person Sridhar Sarnobat; 10.07.2016
comment
Плохая идея использовать fatJar в Gradle, как вы описали: в этом случае у вас будет множество повторяющихся зависимостей (если они есть). Лучше использовать подходящий плагин: github.com/johnrengelman/shadow - person WhiteAngel; 17.10.2018

Различные имена - это просто способы упаковки Java-приложений.

Тощий - содержит ТОЛЬКО фрагменты, которые вы буквально вводите в редактор кода, и НИЧЕГО больше.

Тонкий - содержит все вышеперечисленное, ПЛЮС прямые зависимости приложения от вашего приложения (драйверы баз данных, служебные библиотеки и т. д.).

Hollow - противоположность Thin - содержит только биты, необходимые для запуска вашего приложения, но НЕ содержит самого приложения. По сути, это предварительно упакованный «сервер приложений», на котором вы можете позже развернуть свое приложение, в том же стиле, что и традиционные серверы приложений Java EE, но с важными отличиями.

Fat / Uber - содержит бит, который вы буквально пишете сами ПЛЮС прямые зависимости вашего приложения ПЛЮС биты, необходимые для запуска вашего приложения «на его собственный".

Источник: Статья из Dzone

Визуальное представление типов JAR

person Mark Han    schedule 21.08.2019
comment
Лучший ответ IMO, поскольку он также дает сравнение с другими типами банок. - person Grizz; 05.09.2019
comment
Разве полость не была бы противоположностью худощавости, а не тонкости? Обратным к thin не будет ни ваш код, ни все зависимости, которые ваш код не использует. :-) - person greymatter; 31.10.2019

Fat jar или uber jar - это jar, который содержит все файлы классов проекта и ресурсы, упакованные вместе со всеми их зависимостями. Есть разные методы достижения такого эффекта:

  • jar-файлы зависимостей копируются в основной jar-файл, а затем загружаются с помощью специального загрузчика классов (onejar, spring-boot-plugin: repackage)
  • jar-файлы зависимостей извлекаются наверху основной иерархии jar-файлов (maven-assembly-plugin с его сборкой jar-with-dependencies)
  • jar-файлы зависимостей распаковываются наверху основной иерархии jar-файлов, а их пакеты переименовываются (maven-shade-plugin с целью затенения)

Ниже пример конфигурации подключаемого модуля сборки jar-with -зависимости:

<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>

Для более подробного объяснения: Uber-JAR на imagej.net

person MeTTeO    schedule 11.04.2016
comment
Одна вещь, о которой следует быть осторожной с банками FAT: конфликтующие версии одних и тех же классов в разных банках зависимостей. Вы можете получить действительно РАЗНЫЕ (и часто очень разочаровывающие) эффекты в зависимости от того, какой подход вы выберете (например, полностью взорвите все банки и затем снова соберите их в одну банку, а не в банку с банками). Ни один из подходов не обязательно лучше. В большинстве систем сборки есть своего рода обозреватель обратной зависимости, который может предупреждать вас о конфликтах версий. - person Charles Roth; 14.02.2019
comment
Да, распаковка нескольких банок имеет важные недостатки. Еще одна проблема связана с файлами META-INF, такими как файлы подписи или файлы SPI (services / package.Class), которые по умолчанию перезаписываются плагином сборки. В плагине Shade есть специальные преобразователи, которые при необходимости могут объединять файлы. - person MeTTeO; 12.02.2020

В случае исполняемого jar-файла другой способ представить себе толстый jar-файл - это тот, который вы можете выполнить, вызвав:

java -jar myFatLibrary.jar

без необходимости использовать -cp / --classpath или даже дважды щелкнуть значок банки.

person Sridhar Sarnobat    schedule 10.07.2016
comment
Имейте в виду, что -jar требует заголовка основного класса в MANIFEST.MF: docs.oracle.com/javase/tutorial/deployment/jar/run.html - person MeTTeO; 04.08.2017
comment
Это касается даже обезжиренных банок, поэтому на самом деле это не актуально. - person Sridhar Sarnobat; 06.08.2017
comment
какой флаг mvn мы можем использовать, чтобы пропустить сборку файла fat jar? - person Alexander Mills; 27.01.2019
comment
По умолчанию он не будет жирным. Вы должны явно использовать jar-with-dependencies, uberjar или shadow для mvn install, чтобы поместить туда что-либо, кроме ваших сгенерированных файлов классов - person Sridhar Sarnobat; 27.01.2019

Толстая банка просто содержит те же классы, что и классическая баночка + классы из всех их зависимостей времени выполнения.

С помощью Jeka (https://jeka.dev) вы можете добиться этого программно:

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"));

или просто параметрировав плагин Java:

javaPlugin.getProject().getMaker().defineMainArtifactAsFatJar(true);
person Jerome Angibaud    schedule 09.07.2019

из документации Gradle

В пространстве Java приложения и их зависимости обычно упаковывались как отдельные JAR-файлы в одном дистрибутивном архиве. Это все еще происходит, но есть другой подход, который теперь стал распространенным: размещение классов и ресурсов зависимостей непосредственно в JAR приложения, создание так называемого Uber или толстого JAR.

вот демонстрация uberJar задачи в build.gradle файле:

task uberJar(type: Jar) {
    archiveClassifier = 'uber'

    from sourceSets.main.output

    dependsOn configurations.runtimeClasspath
    from {
        configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
    }
}

В этом случае мы берем зависимости проекта во время выполнения - configurations.runtimeClasspath.files - и обертываем каждый из файлов JAR методом zipTree(). В результате получается коллекция деревьев ZIP-файлов, содержимое которых копируется в Uber JAR вместе с классами приложений.

person roottraveller    schedule 15.10.2019