Pull to refresh

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

Reading time 2 min
Views 6.4K

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
  • И конечно же, проект стал быстрее собираться и делоиться
Tags:
Hubs:
+14
Comments 9
Comments Comments 9

Articles