TLTD


  1. удалил jar из сборки проекта
  2. заменил его таском, который быстрее в 7 раз


Детали и результат под катом.


О проекте


Веб сервис на java, который отдает наружу rest api и websockets, а внутри умеет ходить в распределенную бд и распределенный кеш.


Проект использует embedded jetty для старта, запускается через public status void method.


Доставляется на сервер в виде fat jar и запускается через java -jar myapp.jar app.yaml


Профилируем


Gradle отличный иструмент, который из коробки дает профайлер. Запустим билд с параметром --profile и подождем результат.


./gradlew clean build --profile

Думаю, результат в комментировании не нуждается:



Изучаем проблему


Первым делом я решил посмотреть как сейчас создается fat jar:


jar {
    manifest {
        attributes "Main-Class": "com.baeldung.fatjar.Application"
    }

    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

Прописываем в манифесте класс с main методом и распаковываем jar dependencies в корневую папку jar архива.


Это можно проверить, если сделать распаковав jar unzip myapp.jar и посмотреть дерево текущией папки tree .


Неудивительно, что это медленно, много мелких файлов нужно сначало распаковать, а потом обратно запаковать.


Оптимизируем


Далее, я попровал нагуглить более быстрый вариант создания jar файла.


Я попробовал плагины для gradle:


gradle-fatjar-plugin — больше не поддерживается
shadow — удалось собрать им, но он использует тот же способ, как и выше, поэтому это не дало прироста в скорости
gradle-one-jar — вообще не смог запустить, честно скажу, возможно нужно было просто потратить больше времени


Тут мне пришла идея, даже можно сказать вызов. А как запустить приложения без jar? У меня как раз был распакованных архив, для того, чтобы попробовать это.


Оказалось не сложно:


java -cp . com.example.Main app.yml

Проект отлично запустился, подхватил нужный конфиг.


Параметр -cp это classpath, который говорит java процессу, где лежат все классы проекта.


Получается, проект может жить без jar? Воспользовавшись небольшой помощью gradle community, я получил таск, который создает exploded версию jar:


task explodedJar(type: Copy) {
    with jar
    into "${buildDir}/exploded"
    into('lib') {
        from configurations.runtimeClasspath
    }
}
jar.enabled = false
assemble.dependsOn explodedJar

Таск


  1. кладет все классы и ресурсы в exploded папку
  2. кладет все runtime зависимости в папку lib
  3. дабавляет explodedJar и исключает jar таск из ./gradle build

Запускаем еще раз


./gradlew build --profile

Наслаждаемся результатом


Думаю, комментарии тут опять не нужны.



Тут возможно еще стоит продублировать гистограмму из начала статьи, но я этого делать не буду.


Но как деплоить?


Чтобы не делать эту статью очень длинной, просто оставлю одну команду для копирования проекта на сервер:


rsync --delete -r build/exploded api.example.com:/opt/myapp

Итог


  • Проект стал проще из-за того, что мы убрали из него такую сущность как jar
  • Всегда можно посмотреть, что конкретно попадает в нашу сборку, просто открыв папку build/exploded
  • И конечно же, проект стал быстрее собираться и делоиться

Комментарии (9)


  1. UbuRus
    20.03.2018 17:17
    +1

    build.gradle:


    apply(plugin: "application")
    
    mainClassName = "name"

    terminal:


    ./gradlew installDist
    ./build/project_name/install/bin/project_name


  1. aleksandy
    20.03.2018 20:01
    +1

    Тут мне пришла идея, даже можно сказать вызов. А как запустить приложения без jar?

    Какой вызов? Об этом пишут в любом учебнике по Java.


    1. nsiniakevich Автор
      20.03.2018 21:09
      -1

      В учебниках много всего было, но то, что не используется в реальной жизни быстро забывается. Я очень смутно помнил, как это делается, пришлось потратить несколько минут на гугл и чтения man java.


      1. nsiniakevich Автор
        21.03.2018 16:48

        опа, минусы)
        Давайте разбираться, с чем вы не согласны?

        Еще раз повторю свою позицию: учебники нужны, но помнить все, что в них написано нереально. Если мне нужна информация, которую я когда-то читал, но помню смутно из-за того, что давно не использовал, то я пользуюсь гуглом.


        1. aleksandy
          21.03.2018 21:58

          Так всё помнить и не надо. Но как запускать программу в консоли без IDE — это основа основ.

          Любой HelloWorld в любом источнике состоит плюс-минус из одних и тех же шагов:

          1. Создать файл HelloWorld.java.
          2. Описать в нём класс HelloWorld с main-методом.
          3. Скомпилировать, выполнив javac HelloWorld.java
          4. Запустить, выполнив java HelloWorld


          И каждый шаг расписывается «что», «как» и «почему».

          Мне на ум приходит единственный вариант, при котором это знание было Вами утеряно: Вы не написали ни одной программы, не используя IDE, maven/gradle/ant/etc. Я не говорю о чём-то масштабном, хотя бы банальный сумматор двух аргументов командной строки. С целью пощупать и понять, что же творится под капотом любой IDE.


          1. nsiniakevich Автор
            21.03.2018 23:29

            Все верно. Я использую intellij idea и сборщики проектов всегда, в том числе и на домашних проектах. Ну бывает еще atom или textmate.

            Да, когда я учил джаву, я компилировал и запускал в консоле. Но сейчас у меня нет такой необходимости и эти знания потихоньку теряются.


  1. axmetishe
    20.03.2018 22:44

    Блин, круто, а можно вообще сырцы кидать на хост и компилить там…
    *сарказм*


    1. bores
      21.03.2018 09:30
      +3

      Я видал как томкату класс-файлы подкладывали. А потом через несколько лет оказалось, что это всё работает, только в двух местах: в IDE разраба и на проде. Даже пересобрать не удалось.
      Так что ваш способ ещё не самый юморной :)


      1. axmetishe
        21.03.2018 22:35

        Хы… я тоже такое видел, только не в развернутую варку, а в джарку, упакованную в варку — библиотеку — классик впиливали =)))

        Вообще, меня всегда удивляет, когда берут достаточно жирную тулу, читать как комбайн, а затем для ускорения сборки отключают zip — это как купить автомобиль для повседневной езды, но для снижения времени разгона выкинуть сиденья или для повышения устойчивости сделать жесткую подвеску в ущерб комфорту.

        Мое мнение, если хочется сделать эту сборку быстрой, нужно убрать оверхед удобства.
        Как-то на тренинге я сравнивал время сборки примитивной варки тулами Ant+Ivy, Maven, Gradle. Скорость сборки чистого прогона, но с прогретым кэшем зависимостей, была 3 сек, 7 сек, 19 сек соответственно.
        Я более чем уверен, что если написать майк файл, варка соберется гораздо быстрее.

        Либо шашечки, либо ехать.