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

в 13:04, , рубрики: gradle, java

TLTD

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

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

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

О проекте

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

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

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

Профилируем

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

./gradlew clean build --profile

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

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

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

Первым делом я решил посмотреть как сейчас создается 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

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

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

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

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

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

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

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

Итог

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

Автор: pull

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js