Toples Tipis dengan Spring Boot

1. Perkenalan

Dalam tutorial ini, kita akan melihat bagaimana membangun proyek Spring Boot menjadi file JAR tipis, menggunakan proyek spring-boot-thin-launcher .

Spring Boot dikenal dengan penerapan JAR "gemuk", di mana satu artefak yang dapat dieksekusi berisi kode aplikasi dan semua dependensinya.

Boot juga banyak digunakan untuk mengembangkan layanan mikro. Hal ini terkadang bertentangan dengan pendekatan "JAR gemuk" karena menyertakan dependensi yang sama berulang kali di banyak artefak dapat menjadi pemborosan sumber daya yang penting.

2. Prasyarat

Pertama-tama, kami membutuhkan proyek Spring Boot, tentunya. Dalam artikel ini, kita akan melihat build Maven, dan build Gradle dalam konfigurasi yang paling umum.

Tidak mungkin untuk mencakup semua sistem build dan konfigurasi build di luar sana, tetapi, mudah-mudahan, kita akan melihat cukup banyak prinsip umum sehingga Anda dapat menerapkannya ke penyiapan spesifik Anda.

2.1. Proyek Maven

Dalam proyek Boot yang dibangun dengan Maven, kita harus memiliki plugin Spring Boot Maven yang dikonfigurasi di file pom.xml proyek kita , induknya, atau salah satu leluhurnya:

 org.springframework.boot spring-boot-maven-plugin 

Versi dependensi Spring Boot biasanya ditentukan dengan menggunakan BOM atau mewarisi dari POM induk seperti dalam proyek referensi kami:

 org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE  

2.2. Proyek Gradle

Dalam proyek Boot yang dibuat dengan Gradle, kita akan memiliki plugin Boot Gradle:

buildscript { ext { springBootPlugin = 'org.springframework.boot:spring-boot-gradle-plugin' springBootVersion = '2.2.2.RELEASE' } repositories { mavenCentral() } dependencies { classpath("${springBootPlugin}:${springBootVersion}") } } // elided apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' springBoot { mainClassName = 'com.baeldung.DemoApplication' }

Perhatikan bahwa, dalam artikel ini, kami hanya akan mempertimbangkan Boot 2.x dan proyek yang lebih baru. Thin Launcher juga mendukung versi sebelumnya, tetapi memerlukan konfigurasi Gradle yang sedikit berbeda yang kami hilangkan demi kesederhanaan. Silakan lihat beranda proyek untuk lebih jelasnya.

3. Bagaimana cara membuat stoples tipis?

Spring Boot Thin Launcher adalah pustaka kecil yang membaca dependensi artefak dari file yang dibundel dalam arsip itu sendiri, mengunduhnya dari repositori Maven dan akhirnya meluncurkan kelas utama aplikasi.

Jadi, ketika kita membangun sebuah proyek dengan perpustakaan, kita mendapatkan file JAR dengan kode kita, sebuah file yang menghitung ketergantungannya, dan kelas utama dari perpustakaan yang melakukan tugas-tugas di atas.

Tentu saja, hal-hal sedikit lebih bernuansa daripada penjelasan kita yang disederhanakan; kami akan membahas beberapa topik secara mendalam nanti di artikel.

4. Penggunaan Dasar

Sekarang mari kita lihat bagaimana membuat JAR "tipis" dari aplikasi Spring Boot biasa.

Kami akan meluncurkan aplikasi dengan java -jar biasa , dengan argumen baris perintah tambahan opsional yang mengontrol Thin Launcher. Kami akan melihat beberapa di antaranya di bagian berikut; beranda proyek berisi daftar lengkap.

4.1. Proyek Maven

Dalam proyek Maven, kita harus memodifikasi deklarasi plugin Boot (lihat bagian 2.1) untuk menyertakan ketergantungan pada tata letak "tipis" kustom:

 org.springframework.boot spring-boot-maven-plugin    org.springframework.boot.experimental spring-boot-thin-layout 1.0.11.RELEASE   

Peluncur akan membaca dependensi dari file pom.xml yang disimpan Maven di JAR yang dihasilkan di direktori META-INF / maven .

Kami akan melakukan build seperti biasa, misalnya dengan mvn install .

Jika kami ingin dapat menghasilkan build thin dan fat (misalnya dalam project dengan banyak modul), kami dapat mendeklarasikan tata letak kustom dalam profil Maven khusus.

4.2. Maven dan Dependencies: thin.properties

Kami juga dapat meminta Maven untuk membuat file thin.properties selain pom.xml . Dalam hal ini, file akan berisi daftar lengkap dependensi, termasuk yang transitif, dan peluncur akan lebih memilihnya daripada pom.xml .

Mojo (plugin) untuk melakukannya adalah spring-boot-thin-maven-plugin: properties, dan secara default, ia mengeluarkan file thin.properties di src / main / resources / META-INF , tetapi kita dapat menentukan lokasinya dengan yang thin.output properti:

$ mvn org.springframework.boot.experimental:spring-boot-thin-maven-plugin:properties -Dthin.output=.

Harap dicatat bahwa direktori keluaran harus ada agar tujuan berhasil, bahkan jika kita menyimpan yang default.

4.3. Proyek Gradle

Dalam proyek Gradle, sebagai gantinya, kami menambahkan plugin khusus:

buildscript { ext { //... thinPlugin = 'org.springframework.boot.experimental:spring-boot-thin-gradle-plugin' thinVersion = '1.0.11.RELEASE' } //... dependencies { //... classpath("${thinPlugin}:${thinVersion}") } } //elided apply plugin: 'maven' apply plugin: 'org.springframework.boot.experimental.thin-launcher'

Untuk mendapatkan thin build, kami akan memberi tahu Gradle untuk menjalankan tugas thinJar :

~/projects/baeldung/spring-boot-gradle $ ./gradlew thinJar

4.4. Gradle dan Dependensi: pom.xml

Dalam contoh kode di bagian sebelumnya, kami telah mendeklarasikan plugin Maven sebagai tambahan dari Thin Launcher (serta plugin Boot dan Manajemen Ketergantungan yang telah kita lihat di bagian Prasyarat).

Itu karena, seperti dalam kasus Maven yang telah kita lihat sebelumnya, artefak akan berisi dan menggunakan file pom.xml yang menghitung dependensi aplikasi. File pom.xml dihasilkan oleh tugas yang disebut thinPom , yang merupakan dependensi implisit dari tugas jar apa pun.

Kami dapat menyesuaikan file pom.xml yang dihasilkan dengan tugas khusus. Di sini, kami hanya akan mereplikasi apa yang sudah dilakukan plugin tipis secara otomatis:

task createPom { def basePath = 'build/resources/main/META-INF/maven' doLast { pom { withXml(dependencyManagement.pomConfigurer) }.writeTo("${basePath}/${project.group}/${project.name}/pom.xml") } }

To use our custom pom.xml file, we add the above task to the jar task's dependencies:

bootJar.dependsOn = [createPom]

4.5. Gradle and Dependencies: thin.properties

We can also have Gradle generate a thin.properties file rather than pom.xml, as we did earlier with Maven.

The task that generates the thin.properties file is called thinProperties, and it's not used by default. We can add it as a dependency of the jar task:

bootJar.dependsOn = [thinProperties]

5. Storing Dependencies

The whole point of thin jars is to avoid bundling the dependencies with the application. However, dependencies don't magically disappear, they're simply stored elsewhere.

In particular, the Thin Launcher uses the Maven infrastructure to resolve dependencies, so:

  1. it checks the local Maven repository, which by default lies in ~/.m2/repository but can be moved elsewhere;
  2. then, it downloads missing dependencies from Maven Central (or any other configured repository);
  3. finally, it caches them in the local repository, so that it won't have to download them again the next time we run the application.

Of course, the download phase is the slow and error-prone part of the process, because it requires access to Maven Central through the Internet, or access to a local proxy, and we all know how those things are generally unreliable.

Fortunately, there are various ways of deploying the dependencies together with the application(s), for example in a prepackaged container for cloud deployment.

5.1. Running the Application for Warm-up

The simplest way to cache the dependencies is to do a warm-up run of the application in the target environment. As we've seen earlier, this will cause the dependencies to be downloaded and cached in the local Maven repository. If we run more than one app, the repository will end up containing all the dependencies without duplicates.

Since running an application can have unwanted side effects, we can also perform a “dry run” that only resolves and downloads the dependencies without running any user code:

$ java -Dthin.dryrun=true -jar my-app-1.0.jar

Note that, as per Spring Boot conventions, we can set the -Dthin.dryrun property also with a –thin.dryrun command line argument to the application or with a THIN_DRYRUN system property. Any value except false will instruct the Thin Launcher to perform a dry run.

5.2. Packaging the Dependencies During the Build

Another option is to collect the dependencies during the build, without bundling them in the JAR. Then, we can copy them to the target environment as part of the deployment procedure.

This is generally simpler because it's not necessary to run the application in the target environment. However, if we're deploying multiple applications, we'll have to merge their dependencies, either manually or with a script.

The format in which the Thin Plugin for Maven and Gradle packages the dependencies during a build is the same as a Maven local repository:

root/ repository/ com/ net/ org/ ...

In fact, we can point an application using the Thin Launcher to any such directory (including a local Maven repository) at runtime with the thin.root property:

$ java -jar my-app-1.0.jar --thin.root=my-app/deps

We can also safely merge multiple such directories by copying them one over another, thus obtaining a Maven repository with all the necessary dependencies.

5.3. Packaging the Dependencies With Maven

To have Maven package the dependencies for us, we use the resolve goal of the spring-boot-thin-maven-plugin. We can invoke it manually or automatically in our pom.xml:

 org.springframework.boot.experimental spring-boot-thin-maven-plugin ${thin.version}    resolve  resolve  false   

After building the project, we'll find a directory target/thin/root/ with the structure that we've discussed in the previous section.

5.4. Packaging the Dependencies With Gradle

If we're using Gradle with the thin-launcher plugin, instead, we have a thinResolve task available. The task will save the application and its dependencies in the build/thin/root/ directory, similarly to the Maven plugin of the previous section:

$ gradlew thinResolve

Please note that, at the time of writing, the thin-launcher plugin has a bug that prevents the dependencies to be saved if thin.properties is used: //github.com/dsyer/spring-boot-thin-launcher/issues/53.

6. Conclusions and Further Reading

Pada artikel ini, kami telah melihat cara membuat toples tipis kami. Kami juga telah melihat cara menggunakan infrastruktur Maven untuk mengunduh dan menyimpan dependensinya.

Beranda thin launcher memiliki beberapa lagi panduan CARA untuk skenario seperti penerapan cloud ke Heroku, serta daftar lengkap argumen baris perintah yang didukung.

Penerapan semua contoh Maven dan cuplikan kode dapat ditemukan di proyek GitHub - sebagai proyek Maven, jadi semestinya mudah untuk mengimpor dan menjalankan apa adanya.

Demikian pula, semua contoh Gradle merujuk ke proyek GitHub ini.