Ускоряем время сборки и доставки java web приложения

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
  • И конечно же, проект стал быстрее собираться и делоиться
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 9

    +1

    build.gradle:


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

    terminal:


    ./gradlew installDist
    ./build/project_name/install/bin/project_name
      +3
      Тут мне пришла идея, даже можно сказать вызов. А как запустить приложения без jar?

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

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

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

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

            Любой HelloWorld в любом источнике состоит плюс-минус из одних и тех же шагов:
            1. Создать файл HelloWorld.java.
            2. Описать в нём класс HelloWorld с main-методом.
            3. Скомпилировать, выполнив javac HelloWorld.java
            4. Запустить, выполнив java HelloWorld


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

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

              Да, когда я учил джаву, я компилировал и запускал в консоле. Но сейчас у меня нет такой необходимости и эти знания потихоньку теряются.
        +2
        Блин, круто, а можно вообще сырцы кидать на хост и компилить там…
        *сарказм*
          +3

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

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

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

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

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

        Only users with full accounts can post comments. Log in, please.