Comments 23
Настольным приложениям намного легче с DI на базе PicoContainer или накрайняк Guice. Я бы советовал не брать туда Spring ни в коем случае.
А для сборки бинарников JavaFX приложений рекомендуется использовать jlink, IntelliJ IDEA создает готовый проект JavaFX со всем необходимым сама в File - New Project - JavaFX. И никакой Launch4j не требуется
Спасибо. Обязательно гляну на DI на базе PicoContainer, если честно не знаю что это такое. По поводу создания javaFx приложения в Idea, видел такую возможность, но если честно так и не опробовал, так как пришлось бы весь проект заново пересоздавать и в него уже засовывать свои классы. Рассматривал другие варианты, но может руки и дойдут до этого варианта.
Спасибо за комментарий!
Спринг, вероятно, вам был нужен на десктопе только из за DI и Hibernate. На что намекнули выше. А готовое приложение можно поставлять вместе с рантаймом, сейчас 300 мб архива роли не играют, зато избавитесь от проблем с зоопарком версий на машинах клиентов.
Изначально спринг заюзался потому что я в целом хотел поиграться с новой версией Spring Boot 3 и с Playwright, цели создавать десктопное приложение не было. в целом я писал об этом в самом начале, что это далеко не лучшее решение. Боялся что вообще захейтят за это. Но вижу тут полезные комментарии с которыми я полностью согласен и солидарен.
Спасибо, поставил всем лайки на коменты)))
Докину лайфхак. Можно скачать архивы под каждую платформу с https://elastic-kaizen.com/download заменить джарник и запаковать назад. Поставка готова.
А лучше сразу подключить com.github.johnrengelman.shadow, и настроить его так, как нужно. Можно сразу нужную версию FX запаковать
А если говорить совсем начистоту про DI и настольные приложения, то он там вообще вреден. Показателен пример IntellIJ IDEA, которая раньше использовала какой-никакой DI с PicoContainer, но полностью от него отказалась в пользу простейшего паттерна Service Locator, который позволил загружать сервисы лениво по надобности и не грузить все классы сервисов заранее в память на стартапе.
Для настольных приложений внезапно оказывается стартап и отзывчивость важнее, чем красивая архитектура зависимостей.
IntelliJ IDEA - Light Services.
Do not acquire service instances eagerly or store them in fields, but obtain them in the place(s) where they will be used.
graalvm Native Image для бинариков
Чтобы jlink и jpackager могли собрать нативный образ - все завивисмости вашего приложения должн быть модульными, т.е. моддерживать JPMS. Поэтому, вместо H2 рекомендую взять HSQLDB, в качестве бибилиотеки логирования - logback версии 1.3 и выше.
P.s. по сравнению с прожорливостью jlink и jpackager - Flatter и Golang выдают очень даже компактные сборки. Когда я написал небольшой таймер на JavafX + Gson + Logback, то получившейся бинарник весил целых 500 мб (500 МБ, КАРЛ!). Может я неправильно использовал эти инструменты, но это прям дохрена.
100% вы неправильно используете эти инструменты. Мои fatjar с javafx, usb, rabbitmq, postgresql, блекджеком и девушками не выходят за 50мб.
Хотя делфийское приложение с тем же функционалом - 4мб ((
Собирал свое приложение под Ubuntu 20.04 используя OpenJDK. Попробовал добавить для jlink опции --strip-debug, --no-header-files, --no-man-pages. В итоге получилось ужать образ, но только до 100 МБ. Если вам не сложно, опишите кратко как вы смогли получить ваши 50мб?
P.s. я продолжаю надеяться, что когда-нибудь, с помощью этих инструментов, можно будет собрать образ весящий не больше чем делфийские приложения. Эх, мечты)
Пишу на котлине, система сборки gradle. Для сборки использую shadowJar.
Это почти рабочий пример, за исключение некоторых nba-кусочков
plugins {
application
id("java")
kotlin("jvm") version "1.7.20"
kotlin("plugin.serialization") version "1.7.20"
id("com.github.johnrengelman.shadow") version "5.2.0"
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version")
implementation("org.jetbrains.exposed:exposed:$exposed_version")
implementation("org.postgresql:postgresql:$postgresql_version")
implementation("com.rabbitmq:amqp-client:latest.release")
implementation("org.codehaus.groovy:groovy-all:3.0.9")
implementation("ch.qos.logback:logback-classic:$logback_version")
implementation("no.tornado:tornadofx:1.7.19")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinx_serialization_version")
implementation("org.usb4java:usb4java:1.3.0")
implementation(fileTree("../libs")) // тут лежат библиотеки javafx
}
sourceSets.main {
java.srcDirs(
// тут пути к исходникам
)
resources.srcDirs(
// тут пути к ресурсам
)
}
application {
mainClassName = "ru.AAA.AAA.MainAbdKt"
}
tasks {
shadowJar {
manifest {
attributes["mainClassName"] = "ru.AAA.AAA.MainAbdKt"
attributes["Company"] = "AAA"
attributes["Implementation-Version"] = "6.0 build $build от ${formatter.format(LocalDateTime.now())}"
}
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
jvmTarget = "1.8"
Ну какие модули в 8ой жабе!?
Не удивлён 500 мегам. Вам натолкали весь JDK + всё jar-ы библиотек и все jar-ы их зависимостей. Удивлён, что оно вообще собралось.
Вот прям сейчас небольшой проект сдал. JavaFX + ControlsFX + JNA(native к железкам) + Jackson + пара моих либ + ресурсы. Итого: экзешник 120MB. Причем ОЗУ это всё жрет раз в пять меньше, чем если на Electron-е делать хех
А если только голый JavaFX c JRE то меньше 50MB должен выходить.
Читайте внимательнее, плиз. Это сборка моей программы, которая с "javafx, usb, rabbitmq, postgresql, блекджеком и девушками". Кстати, забыл, что там ещё и groovy в качестве скриптов работает .
Итого jar в данный момент 51мб . Ну плюс ещё нужна голая jre, без javafx
Если я правильно понял ваше "Итого: экзешник 120MB.", то это размер инсталяшки с jre ?
Как раз сейчас балуюсь таким же стеком.
Только пару нюансов отличается:
Javafx библиотеки подтягиваю прямо в градле из блока dependencies. Причем подтягиваю сразу 3 ОС. (Проблему с М1 это все равно пока что не решает, даже если добавить 4ый тип -mac-aarch64)
javafx { } Gradlew Task - хранит в себе версию и модули JavaFx, без строки configuration..
Сборку fat jar делаю с помощью плагина shadowJar. Обычный bootJar с задачей справился не так хорошо.
Баг с потерянными javafx зависимостями решил советами из интернета через доп класс Launcher с main() методом.
На выходе имею кросс платформенный jar ~85мб , который стартует только на системах с установленной Java.
След шаги :
Попробовать зашить Java либу в Jar, Все так же не сделав проект модульным, если это возможно.
Затестить native билды с GraalVM, опять-таки, если это в моих условиях возможно.
Попробовать повырезать лишние Spring модули для уменьшения размера.
Ну и не связанное с конфигом: сильнее разделить UI слой от реальной бизнес логики и добавить команды вызываемые из командной строки..(знал бы раньше - раньше бы так изначально и делал)
Есть какие-то весомые причины не использовать зависимости из градла, а подтягивать локальные javafx либы?
JavaFx application with Spring boot