Boot dirimu, Spring akan datang (Bagian 2)

Evgeny EvgenyBorisov Borisov (NAYA Technologies) dan Kirill tolkkv Tolkachev (Cyan.Finance, Twitter ) terus berbicara tentang penggunaan Spring Boot untuk menyelesaikan masalah Iron Bank Braavos yang imajiner. Pada bagian kedua, kita akan fokus pada profil dan seluk beluk dari meluncurkan aplikasi.






Bagian pertama artikel dapat ditemukan di sini .


Jadi, sampai saat ini, pelanggan datang dan hanya meminta untuk mengirim gagak. Sekarang situasinya telah berubah. Musim dingin telah tiba, tembok telah runtuh.


Pertama, prinsip pemberian pinjaman berubah. Jika sebelumnya dengan probabilitas 50% yang mereka berikan kepada semua orang kecuali Starks, sekarang mereka hanya memberikan kepada mereka yang membayar utang. Oleh karena itu, kami mengubah aturan untuk mengeluarkan pinjaman dalam logika bisnis kami. Tetapi hanya untuk cabang-cabang bank, yang terletak di mana musim dingin telah tiba, semuanya tetap seperti sebelumnya. Saya mengingatkan Anda bahwa ini adalah layanan yang memutuskan apakah akan memberikan pinjaman atau tidak. Kami hanya akan melakukan layanan lain yang hanya akan bekerja di musim dingin.


Kami pergi ke logika bisnis kami:


public class WhiteListBasedProphetService implements ProphetService {  @Override  public boolean willSurvive(String name) {    return false;  } } 

Kami sudah memiliki daftar orang-orang yang membayar utang.


 spring: application.name: money-raven jpa.hibernate.ddl-auto: validate ironbank: ---:   -  : -: ,   : true 

Dan ada kelas yang sudah dikaitkan dengan properti - .


 public class ProphetProperties { List<String> ; } 

Seperti di waktu sebelumnya, kami cukup menyuntikkannya di sini:


 public class WhiteListBasedProphetService implements ProphetService { private final ProphetProperties prophetProperties; @Override public boolean willSurvive(String name) {   return false; } } 

Ingat tentang injeksi konstruktor (tentang anotasi ajaib):


 @Service @RequiredArgsConstructor public class WhiteListBasedProphetService implements ProphetService { private final ProphetProperties prophetProperties; @Override public boolean willSurvive(String name) {   return false; } } 

Hampir selesai.


Sekarang kita harus memberikan hanya kepada mereka yang membayar hutang:


 @Service @RequiredArgsConstructor public class WhiteListBasedProphetService implements ProphetService { private final ProphetProperties prophetProperties; @Override public boolean willSurvive(String name) { return prophetProperties.get().contains(name); } } 

Tapi di sini kita punya masalah kecil. Sekarang kami memiliki dua implementasi: layanan lama dan layanan baru.


 Description Parameter 1 of constructor in com.ironbank.moneyraven.service.TransferMoneyProphecyBackend… - nameBasedProphetService: defined in file [/Users/tolkv/git/conferences/spring-boot-ripper… - WhileListBackendProphetService: defined in file [/Users/tolkv/git/conferences/spring-boot-ripper... 

Adalah logis untuk membagi kacang ini menjadi profil yang berbeda. Profil dan profil . Biarkan layanan baru kami berjalan hanya di profil :


 @Service @Profile(ProfileConstants.) @RequiredArgsConstructor public class WhiteListBasedProphetService implements ProphetService { private final ProphetProperties prophetProperties; @Override public boolean willSurvive(String name) {   return prophetProperties.get().contains(name); } } 

Dan layanan lama di .


 @Service @Profile(ProfileConstants.) public class NameBasedProphetService implements ProphetService { @Override public boolean willSurvive(String name) {   return !name.contains("Stark") && ThreadLocalRandom.current().nextBoolean(); } } 

Tapi musim dingin datang perlahan. Di kerajaan di sebelah tembok yang rusak, itu sudah musim dingin. Tetapi di suatu tempat di selatan - belum. Yaitu Aplikasi yang berlokasi di berbagai cabang dan zona waktu harus bekerja secara berbeda. Menurut kondisi tugas kami, kami tidak dapat menghapus implementasi lama di mana musim dingin telah datang dan menggunakan kelas baru. Kami ingin karyawan bank tidak melakukan apa pun: kami akan mengirimkan mereka aplikasi yang akan bekerja dalam mode musim panas hingga musim dingin tiba. Dan ketika musim dingin tiba, mereka hanya memulai kembali dan hanya itu. Mereka tidak perlu mengubah kode, menghapus kelas apa pun. Oleh karena itu, kami awalnya memiliki dua profil: bagian dari tempat sampah dibuat saat musim panas, dan bagian tempat sampah dibuat saat musim dingin.


Tetapi masalah lain muncul:




Sekarang kami tidak memiliki satu kacang, karena kami menetapkan dua profil, dan aplikasi dimulai pada profil default.


Jadi kami memiliki persyaratan baru dari pelanggan.


Hukum Besi 2. Tidak ada profil yang diizinkan




Kami tidak ingin meningkatkan konteks jika profil tidak diaktifkan, karena musim dingin telah tiba, semuanya menjadi sangat buruk. Ada hal-hal tertentu yang harus terjadi atau tidak, tergantung pada apakah atau . Juga, lihat pengecualian, teks yang diberikan di atas. Dia tidak menjelaskan apa pun. Profil tidak ditentukan, oleh karena itu tidak ada implementasi layanan ProphetService . Pada saat yang sama, tidak ada yang mengatakan bahwa perlu menetapkan profil.


Oleh karena itu, kami sekarang ingin memasukkan potongan tambahan ke starter kami, yang, ketika membangun konteks, akan memeriksa apakah beberapa profil sudah diatur. Jika tidak disetel, kami tidak akan naik dan melempar hanya pengecualian seperti itu (dan bukan pengecualian tentang kurangnya tempat sampah).


Bisakah kita melakukan ini dengan pendengar aplikasi kita? Tidak. Dan ada tiga alasan untuk ini:


  • Pendengar tanggung jawab tunggal bertanggung jawab untuk membuat gagak terbang. Pendengar tidak boleh memeriksa apakah profil telah diaktifkan karena mengaktifkan profil tidak hanya memengaruhi pendengar itu sendiri, tetapi juga lebih banyak lagi.
  • Ketika sebuah konteks dibangun, hal-hal yang berbeda terjadi. Dan kami tidak ingin mereka mulai terjadi jika profil belum ditetapkan.
  • Pendengar bekerja di bagian paling akhir ketika konteks diselesaikan. Dan fakta bahwa tidak ada profil, kita tahu jauh sebelumnya. Mengapa menunggu ini bersyarat lima menit sampai layanan hampir naik, dan kemudian semuanya jatuh.

Selain itu, saya masih tidak tahu bug apa yang akan muncul karena fakta bahwa kami mulai naik tanpa profil (misalkan saya tidak tahu logika bisnis). Karena itu, dengan tidak adanya profil, Anda perlu menurunkan konteks pada tahap yang sangat awal. Omong-omong, jika Anda menggunakan Spring Cloud apa pun, ini menjadi lebih relevan bagi Anda, karena aplikasi melakukan banyak hal pada tahap awal.


Untuk menerapkan persyaratan baru, ada ApplicationContextInitializer . Ini adalah antarmuka lain yang memungkinkan kita untuk memperluas beberapa titik Spring dengan menetapkannya di spring.factories.




Kami mengimplementasikan antarmuka ini, dan kami memiliki Context Initializer, yang memiliki ConfigurableApplicationContext :


 public class ProfileCheckAppInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext applicationContext) { } } 

Dengan itu, kita bisa mendapatkan lingkungan - hal yang disiapkan SpringApplication untuk kita. Semua properti yang kami berikan kepadanya tiba di sana. Antara lain, mereka juga mengandung profil.


Jika tidak ada profil di sana, maka kami harus mengeluarkan pengecualian yang mengatakan bahwa Anda tidak dapat bekerja seperti itu.


 public class ProfileCheckAppInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext applicationContext) { if applicationContext.getEnvironment().getActiveProfiles().length == 0 {     throw new RuntimeException("  !");   } } } 

Sekarang Anda perlu mendaftarkan barang ini di spring.factories.


 org.springframework.boot.context.properties.EnableConfigurationProperties=com.ironbank.moneyraven.starter.IronConfiguration org.springframework.context.ApplicationContextInitializer=com.ironbank.moneyraven.starter.ProfileCheckAppInitializer 

Dari penjelasan di atas, Anda dapat menebak bahwa ApplicationContextInitializer adalah titik ekstensi. ApplicationContextInitializer berfungsi ketika konteksnya baru mulai dibangun, belum ada nampan.


Timbul pertanyaan: jika kita menulis ApplicationContextInitializer , mengapa tidak, sebagai pendengar, ditulis dalam konfigurasi yang membentang? Jawabannya sederhana: karena harus bekerja jauh lebih awal ketika tidak ada konteks dan tidak ada konfigurasi. Yaitu itu belum bisa disuntikkan. Karena itu, kami meresepkannya sebagai bagian terpisah.


Upaya untuk meluncurkan menunjukkan bahwa semuanya telah jatuh cukup cepat dan melaporkan bahwa kami mulai tanpa profil. Sekarang mari kita coba untuk menentukan beberapa profil, dan semuanya berfungsi - gagak dikirim.


ApplicationContextInitializer - memenuhi ketika konteks telah dibuat, tetapi tidak ada yang lain di dalamnya selain lingkungan.




Siapa yang menciptakan lingkungan? Carlson - SpringBootApplication . Dia mengisinya dengan berbagai meta-informasi, yang kemudian dapat ditarik keluar dari konteks. Sebagian besar hal dapat disuntikkan melalui @value , sesuatu dapat diperoleh dari lingkungan, karena kami baru saja mendapatkan profil.


Misalnya, berbagai properti datang ke sini:


  • Spring Boot mana yang bisa dibangun;
  • yang pada saat startup ditransmisikan melalui baris perintah;
  • sistemik;
  • dijabarkan sebagai variabel lingkungan;
  • ditentukan dalam properti aplikasi;
  • terdaftar di beberapa file properti lainnya.

Semua ini dikumpulkan dan diatur menjadi objek lingkungan. Ini juga berisi informasi tentang profil mana yang aktif. Objek lingkungan adalah satu-satunya hal yang ada pada saat Boot Musim Semi mulai membangun konteks.


Saya ingin menebak secara otomatis profil apa yang akan terjadi jika orang lupa bertanya dengan tangan mereka (kami melakukan segalanya sehingga karyawan bank yang tidak berdaya tanpa programmer dapat meluncurkan aplikasi sehingga semuanya bekerja untuk mereka, tidak peduli apa). Untuk melakukan ini, kami akan menambah starter kami hal yang akan menebak profil - atau tidak - tergantung pada suhu di jalan. Dan antarmuka sihir baru lainnya akan membantu kita semua dengan ini - EnvironmentPostProcessor , karena kita perlu melakukan ini sebelum ApplicationContextInitializer berfungsi. Dan sebelum ApplicationContextInitializer hanya ada EnvironmentPostProcessor .


Kami sekali lagi menerapkan antarmuka baru. Hanya ada satu metode, yang dengan cara yang sama ConfigurableEnvironment melempar di SpringApplication , karena kita belum memiliki ConfigurableContext (itu sudah ada di SpringInitializer tidak ada di sini; hanya ada lingkungan).


 public class ResolveProfileEnvironmentPostProcessor implements EnvironmentPostProcessor { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { } } 

Di lingkungan ini, kita dapat mengatur profil. Tetapi pertama-tama Anda perlu memeriksa bahwa belum ada yang menginstalnya sebelumnya. Karena itu, kita getActiveProfiles perlu memeriksa getActiveProfiles . Jika orang tahu apa yang mereka lakukan dan mereka membuat profil, maka kami tidak akan mencoba menebaknya. Tetapi jika tidak ada profil, maka kami akan mencoba memahami cuaca.


Dan yang kedua - kita harus mengerti jika kita memiliki cuaca musim dingin atau musim panas sekarang. Kami akan mengembalikan suhu -300 .


 public class ResolveProfileEnvironmentPostProcessor implements EnvironmentPostProcessor { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { if (environment.getActivePrifiles().length == 0 && getTemperature() < -272) {   } } public int getTemperature() { return -300; } } 

Dalam kondisi ini, kami mengalami musim dingin, dan kami dapat membuat profil baru. Kami ingat bahwa profil ini disebut :


 public class ResolveProfileEnvironmentPostProcessor implements EnvironmentPostProcessor { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {   if (environment.getActivePrifiles().length == 0 && getTemperature() < -272) { environment.setActiveProfiles("");   } else { environment.setActiveProfiles("");   } } public int getTemperature() { return -300; } } 

Sekarang kita perlu menentukan EnvironmentPostProcessor di spring.factories.


 org.springframework.boot.context.properties.EnableConfigurationProperties=com.ironbank.moneyraven.starter.IronConfiguration org.springframework.context.ApplicationContextInitializer=com.ironbank.moneyraven.starter.ProfileCheckAppInitializer org.springframework.boot.env.EnvironmentPostProcessor=com.ironbank.moneyraven.starter.ResolveProfileEnvironmentPostProcessor 

Akibatnya, aplikasi dimulai tanpa profil, kami mengatakan itu adalah produksi, dan memeriksa di mana profil itu dimulai dengan kami. Secara ajaib, kami menyadari bahwa profil kami adalah . Dan aplikasi tidak jatuh, karena ApplicationContextInitializer , yang memeriksa apakah ada profil, datang berikutnya.
Hasilnya:


 public class ResolveProfileEnvironmentPostProcessor implements EnvironmentPostProcessor { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {   if (getTemperature() < -272) {     environment.setActiveProfiles("");   } else {     environment.setActiveProfiles("");   } } private int getTemperature() {   return -300; } } 

Kami berbicara tentang EnvironmentPostProcessor , yang berjalan sebelum ApplicationContextInitializer . Tapi siapa yang menjalankannya?




Orang aneh ini memulainya, yang, tampaknya, adalah anak tidak sah dari ApplicationListener dan EnvironmentPostProcessor , karena ia diwarisi dari ApplicationListener dan EnvironmentPostProcessor . Ini disebut ConfigFileApplicationListener (mengapa "ConfigFile" - tidak ada yang tahu).


Dia adalah Carlson kita, mis. Aplikasi Musim Semi menyediakan lingkungan yang disiapkan untuk mendengarkan dua acara: ApplicationPreparedEvent dan ApplicationEnvironmentPreparedEvent . Kami tidak akan menganalisis siapa yang melempar peristiwa ini sekarang. Ada satu lapisan lagi (menurut saya itu sudah benar-benar berlebihan, setidaknya pada tahap pengembangan Spring), yang melempar peristiwa bahwa lingkungan mulai dibangun (Application.yml, properti, variabel lingkungan diurai, dll. )
Setelah menerima ApplicationEnvironmentPreparedEvent , pendengar mengerti bahwa Anda perlu mengonfigurasi lingkungan - temukan semua EnvironmentPostProcessor dan biarkan mereka bekerja.




Setelah itu, ia memberi tahu SpringFactoriesLoader untuk mengirimkan semua yang Anda pesan, yaitu semua EnvironmentPostProcessor , ke spring.factories. Kemudian memasukkan seluruh EnvironmentPostProcessor ke dalam satu Daftar.




dan mengerti bahwa dia juga adalah Proposor EnvironmentPostProcessor (bersamaan), oleh karena itu dia mendorong dirinya sendiri ke sana,

pada saat yang sama memilah mereka, naik dengan mereka dan memanggil postProcessEnvironment masing-masing metode.


Dengan cara ini, semua postProcessEnvironment dimulai pada tahap awal sebelum SpringApplicationInitializer . Dalam hal ini, EnvironmentPostProcessor tidak dapat dipahami yang disebut ConfigFileApplicationListener juga dimulai.


Ketika lingkungan diatur, semuanya kembali ke Carlson lagi.


Jika lingkungan sudah siap, Anda dapat membangun konteks. Dan Carlson mulai membangun konteks dengan ApplicationInitializer . Di sini kita memiliki karya kita sendiri, yang memeriksa bahwa dalam konteksnya ada lingkungan di mana ada profil aktif. Jika tidak, kita jatuh, karena kalau tidak kita masih akan memiliki masalah nanti. Kemudian starter bekerja, dengan semua konfigurasi yang sudah biasa.


Gambar di atas mencerminkan bahwa Spring juga tidak bekerja dengan baik. Alien seperti itu bertemu secara berkala di sana, tanggung jawab tunggal tidak dihormati dan Anda perlu naik dengan hati-hati.


Sekarang kita ingin berbicara sedikit tentang sisi lain makhluk aneh ini, yaitu pendengar di satu sisi dan EnvironmentPostProcessor di sisi lain.




Seperti EnvironmentPostProcessor ia dapat memuat application.yml, properti aplikasi, semua jenis variabel lingkungan, argumen perintah, dll. Dan sebagai pendengar, dia dapat mendengarkan dua acara:


  • ApplicationPreparedEvent
  • ApplicationEnvironmentPreparedEvent

Pertanyaannya adalah:




Semua peristiwa ini terjadi di musim semi yang lama. Dan yang kami bicarakan di atas adalah acara dari Spring Boot (acara khusus yang ia tambahkan untuk siklus hidupnya). Dan ada banyak dari mereka. Ini adalah yang utama:


  • ApplicationStartingEvent
  • ApplicationEnvironmentPreparedEvent
  • ApplicationPreparedEvent
  • ContextRefreshedEvent
  • EmbeddedServletContainerInitializedEvent
  • ApplicationReadyEvent
  • ApplicationFailedEvent

Daftar ini jauh dari semua. Tetapi penting bahwa beberapa dari mereka berhubungan dengan Spring Boot, dan sebagian lagi ke Spring ( ContextRefreshedEvent , dll.) Yang baik.


Peringatannya adalah bahwa tidak semua peristiwa ini dapat diterima dalam aplikasi (manusia biasa - nenek yang berbeda - tidak bisa hanya mendengarkan peristiwa kompleks yang dilemparkan Spring Boot). Tetapi jika Anda tahu tentang mekanisme rahasia spring.factories dan menentukan Pendengar Aplikasi Anda di level spring.factories, maka peristiwa-peristiwa ini dari tahap permulaan aplikasi yang paling awal menghampiri Anda.




Sebagai hasilnya, Anda dapat memengaruhi awal aplikasi Anda pada tahap yang agak awal. Leluconnya, bagaimanapun, adalah bagian dari pekerjaan ini dilakukan di entitas lain - seperti EnvironmentPostProcessor dan ApplicationContextInitializer .


Anda bisa melakukan segalanya dengan pendengar, tetapi itu akan merepotkan dan jelek. Jika Anda ingin mendengarkan semua acara yang dilemparkan oleh Spring, dan bukan hanya ContextRefreshedEvent dan ContextStartedEvent , maka Anda tidak perlu mendaftarkan pendengar, seperti kacang, dengan cara biasa (jika tidak dibuat terlambat). Itu juga harus didaftarkan melalui spring.factories, maka itu akan dibuat lebih awal.


Ngomong-ngomong, ketika kami melihat daftar ini, tidak jelas bagi kami kapan ContextStartedEvent dan ContextStoppedEvent menyala sama sekali?




Ternyata peristiwa ini tidak pernah berhasil sama sekali. Kami telah lama bingung tentang peristiwa apa yang harus ditangkap untuk memahami bahwa aplikasi benar-benar dimulai. Dan ternyata peristiwa yang kita bicarakan sekarang muncul ketika Anda secara paksa menarik metode dari konteks:


  • ctx.start(); -> ContextStartedEvent
  • ctx.stop(); -> ContextStoppedEvent

Yaitu SpringApplication.run hanya akan datang jika kita menjalankan SpringApplication.run , dapatkan konteksnya, tarik ctx.start(); darinya ctx.start(); atau ctx.stop(); . Tidak terlalu jelas mengapa ini perlu. Tapi, sekali lagi, mereka memberi Anda titik perpanjangan.


Apakah Spring ada hubungannya dengan ini? Jika demikian, di suatu tempat harus ada pengecualian:


  • ctx.stop(); (1)
  • ctx.start(); (2)
  • ctx.close(); (3)
  • ctx.start(); (4)

Bahkan, itu akan berada di baris terakhir, karena setelah ctx.close(); tidak ada yang bisa dilakukan dengan konteks. Tetapi hubungi ctx.stop(); sebelum ctx.start(); - Anda bisa (Spring mengabaikan acara-acara ini - itu hanya untuk Anda).


Tulis pendengar Anda, dengarkan diri Anda sendiri, buat hukum Anda, apa yang harus dilakukan di ctx.stop(); , dan apa yang harus dilakukan di ctx.start(); .


Secara total, diagram siklus interaksi dan aplikasi terlihat seperti ini:




Warna-warna di sini menunjukkan periode kehidupan yang berbeda.


  • Biru adalah Spring Boot, aplikasi sudah dimulai. Ini berarti bahwa permintaan layanan Tomcat yang datang kepadanya dari klien diproses, seluruh konteks pasti dinaikkan, semua kacang berfungsi, basis data terhubung, dll.
  • Hijau - acara ContextRefreshedEvent tiba dan konteksnya dibangun. Mulai saat ini, misalnya, pendengar aplikasi mulai berfungsi, yang Anda terapkan baik dengan mengatur anotasi ApplicationListener, atau melalui antarmuka eponymous dengan generik yang mendengarkan peristiwa tertentu. Jika Anda ingin menerima lebih banyak acara, Anda perlu menulis ApplicationListener yang sama di spring.factories (Spring yang biasanya berfungsi di sini). Bilah menunjukkan di mana laporan Spring Ripper dimulai.
  • Pada tahap sebelumnya, SpringApplication berfungsi, yang menyiapkan konteks untuk kita. Ini adalah tugas mempersiapkan aplikasi yang kami lakukan ketika kami adalah pengembang Spring biasa. Misalnya, mengkonfigurasi WebXML.
  • Tetapi bahkan ada tahapan sebelumnya. Ini menunjukkan siapa, di mana, dan untuk siapa ia bekerja.
  • Masih ada tahap abu-abu di mana tidak mungkin untuk mengganjal dengan cara apa pun. Ini adalah tahap di mana SpringApplication kehabisan kotak (hanya masuk ke dalam kode).

Jika Anda perhatikan, selama laporan dua bagian, kami bergerak dari kanan ke kiri: kami mulai dari awal, mengacaukan konfigurasi yang terbang dari starter, lalu menambahkan yang berikut, dll. Sekarang mari kita segera berbicara seluruh rantai di arah yang berlawanan.
Anda menulis di SpringApplication.run utama Anda. Dia menemukan pendengar yang berbeda, melemparkan mereka sebuah acara yang mulai dia bangun. Setelah itu, pendengar menemukan EnvironmentPostProcessor , biarkan mereka mengkonfigurasi lingkungan. Setelah lingkungan diatur, kita mulai membangun konteks (Carlson masuk). Carlson membangun konteks dan memungkinkan semua Penginisialisasi Aplikasi untuk melakukan sesuatu dengan konteks ini. Kami memiliki titik ekstensi. Setelah ini, konteksnya sudah dikonfigurasikan dan kemudian hal yang sama mulai terjadi seperti pada aplikasi Musim Semi yang biasa, ketika konteksnya dibangun - BeanFactoryPostProcessor , BeanPostProcessor , bean dikonfigurasi. Inilah yang biasa dilakukan Spring.


Bagaimana cara menjalankannya


Kami telah selesai membahas proses penulisan aplikasi.


Tapi kami punya satu hal lagi yang tidak disukai pengembang. Mereka tidak suka berpikir bagaimana, pada akhirnya, aplikasi mereka akan mulai. Apakah admin menjalankannya di Tomcat, JBoss atau di WebLogic? Itu hanya harus bekerja. Jika tidak berhasil, dalam kasus terburuk, pengembang harus mengkonfigurasi sesuatu lagi


Jadi apa metode peluncuran kami?


  • perang tomcat;
  • ide;
  • java -jar/war .

Tomcat bukan tren massal, kami tidak akan membicarakannya secara rinci.


Ide pada prinsipnya juga tidak terlalu menarik. Hanya sedikit lebih rumit daripada yang akan saya katakan di bawah ini. Namun dalam Idea, pada prinsipnya, seharusnya tidak ada masalah. Dia melihat ketergantungan seperti apa yang akan dibawa oleh starter.
Jika kita melakukan java -jar , masalah utamanya adalah membangun classpath sebelum kita meluncurkan aplikasi.


Apa yang dilakukan orang pada tahun 2001? Mereka menulis java -jar yang jar harus dijalankan, lalu spasi, classpath=... dan skrip ditunjukkan di sana. Dalam kasus kami, ada 150 MB berbagai dependensi yang ditambahkan permulaan. Dan semua ini harus dilakukan secara manual. Tentu, tidak ada yang melakukan itu. Kami hanya menulis: java -jar , stoples mana yang harus dijalankan dan hanya itu. Entah bagaimana classpath masih dibangun. Kami akan membicarakan ini sekarang.


Mari kita mulai dengan persiapan file jar sehingga bahkan dapat diluncurkan tanpa Tomcat. Sebelum Anda membuat java -jar , Anda harus membuat toples. Stoples ini seharusnya tidak biasa, semacam analog perang, di mana semuanya akan berada di dalam, termasuk Tomcat yang tertanam.


 <build> <plugins>    <plugin>       <groupId>org.springframework.boot</groupId>       <artifactId>spring-boot-maven-plugin</artifactId>    </plugin> </plugins> </build> 

Ketika kami mengunduh proyek, seseorang sudah mendaftarkan plug-in di POM kami. Di sini, omong-omong, Anda bisa melempar konfigurasi, tetapi lebih lanjut tentang itu nanti. jar, Maven Gradle , jar . :




:




war-.


, .


, jar. java -jar , , , , org.springframework.boot . . org.springframework.boot package. META-INF




Spring Boot MANIFEST ( Maven Gradle), main class, jar-.


, jar- : -, main-. java -jar -jar, , main-class-.


, , MANIFEST, main-class , main ( Idea). , . class path? java -jar , main, , — main, . MANIFEST JarLauncher.




Yaitu , , JarLauncher. , main, class path.
, main? property — Start-class .


Yaitu . class path jar. , — org.springframework.boot — class path. org.springframework.boot.loader.JarLauncher main-class. , main-class . class path, BOOT-INF ( lib class , ).


RavenApplication, properties class BOOT-INF , , Tomcat , BOOT-INF/lib/ . JarLauncher classpath, — , start-class . Spring, ContextSpringApplication — flow, .


, start-class-? , . , .


, . property, mainClass , MANIFEST Start-Class , mainClass — JarLauncher.


, mainClass, ? . Spring boot plugin – mainClass:


  • – . — main class;
  • – , mainClass @SpringBootApplication , , , ;
  • — exception , main class, , jar- . Yaitu , , . , , main class.
  • @SpringBootApplication — .

JarLauncher . Tomcat WarLauncher, war- , jar-.


, java -jar . ? Kamu bisa. .


 <build> <plugins>    <plugin>       <groupId>org.springframework.boot</groupId>       <artifactId>spring-boot-maven-plugin</artifactId>       <configuration>          <executable>true</executable>       </configuration>    </plugin> </plugins> </build> 

<configuration> <executable>true</executable> Gradle , :


 springBoot { executable = true } 

jar executable jar. .


, . Windows , exe-, . Spring Boot, .. jar, . , .
?


(jar — zip-, ):




Spring Boot - .


-, jar-. , , — #!/bin/bash . .


. exit 0 - — zip-.




, zip- — 0xf4ra . , , .




(, ..).


jar :


  • — ;
  • , " bash" ( #!/bin/bash );
  • bash ;
  • exit 0 ;
  • java -jar — jar-, ;
  • java -jar zip- jar-, , , .

Kesimpulan


, Spring Boot — , , .


-, . , Spring, Spring — Spring Boot. , , — , , , . , , Spring, Spring Boot .


-, @SpringBootApplication , best practice, Spring-.


— , , . property environment variable, var arg , , JSON. @value , . configuration properties , , , . , Spring . , , .


. , . Spring, Spring Boot . - , , , .




Menit periklanan. 19-20 Joker 2018, « [Joker Edition]» , «Micronaut vs Spring Boot, ?» . , Joker . .

Source: https://habr.com/ru/post/id425333/


All Articles