Kata pengantar
Untuk analisis prinsip startup boot musim semi itu sendiri, silakan merujuk ke: http://www.vevb.com/article/141478.htm
Hubungan warisan ClassLoader di Spring Boot dapat menjalankan demo yang disediakan di bawah ini, dan menjalankannya dalam skenario yang berbeda. Anda dapat mengetahui hubungan warisan ClassLoader dari aplikasi boot musim semi dalam skenario yang berbeda.
https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-classloader-context
Ada tiga situasi:
Di IDE, fungsi utama run secara langsung menjalankan classloader spring secara langsung SystemClassLoader. URL ClassLoader berisi semua stoples dan target/kelas mereka sendiri
========= Aplikasi boot musim semi URL ClassLoader ================
URL ClassLoader: sun.misc.launcher$appclassloader@2a139a55
File:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/kelas/
file: /users/hengyunabc/.m2/repository/org/springframework/cloud/spring-cloud-starter/1.1.9.release/spring-cloud-starter-1.1.9.release.jar
file: /users/hengyunabc/.m2/repository/org/springframework/boot/spring-boot-starter/1.4.7.release/spring-boot-starter-1.4.7.release.jar
...
Jalankan sebagai toples gemuk
mvn clean packagejava -jar target/demo-classloader-context-0.0.1-snapshot.jar
ClassLoader yang mengeksekusi fungsi utama aplikasi diluncurkanArlClassLoader, dan induknya adalah SystemClassLoader.
========== ClassLoader Tree ================
org.springframework.boot.loader.launchedUrlClassloader@1218025c
- sun.misc.launcher$appclassloader@6bc7c054
- sun.misc.launcher$extClassLoader@85ede7b
Dan LaunchedURLClassLoader的urls adalah BOOT-INF/classes!/ Direktori di fat jar dan semua toples di boot-inf/lib.
========= Aplikasi boot musim semi URL ClassLoader ================
URL ClassLoader: org.springframework.boot.loader.launchedUrlClassloader@1218025c
jar: file: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-snapshot.jar!/boot-inf/kelas!/
jar: file: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-snapshot.jar! /boot-inf/lib/spring-boot-1.4.7.7.7.release!
jar: file: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-snapshot.jar! /boot-inf/lib/spring-web-4.3.9.9
...
URL SystemClassLoader adalah demo-classloader-context-0.0.1-SNAPSHOT.jar itu sendiri.
========== URL ClassLoader Sistem ================
URL ClassLoader: sun.misc.launcher$appclassloader@6bc7c054
file: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-snapshot.jar
Jalankan sebagai direktori dekompresi
mvn clean packageCd targetunzip demo-classloader-context-0.0.1-snapshot.jar -d demojava org.springframework.boot.loader.propertieslauncher
ClassLoader yang mengeksekusi fungsi utama aplikasi LaunchedURLClassLoader , dan induknya adalah SystemClassLoader .
========== ClassLoader Tree ================
org.springframework.boot.loader.launchedUrlClassloader@4AA298B7
- sun.misc.launcher$appclassloader@2a139a55
- sun.misc.launcher$extClassLoader@1b6d3586
URL dari LaunchedURLClassLoader adalah paket JAR di bawah BOOT-INF/classes/ dan /BOOT-INF/lib/ di direktori dekompresi.
========= Aplikasi boot musim semi URL ClassLoader ================
URL ClassLoader: org.springframework.boot.loader.launchedUrlClassloader@4aa298b7
File:/Users/Hengyunabc/Code/Java/Spring-Boot-Inside/Demo-Classloader-Context/Target/Demo/Boot-Inf/Kelas/
jar: file: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-inth/lib/bcpkix-jdk15on-1.55.jar!/
jar: file: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-inth/lib/bcprov-jdk15on-1.55.jar!/
jar: file: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-intr
URL SystemClassLoader hanya memiliki direktori saat ini:
========== URL ClassLoader Sistem ================
URL ClassLoader: sun.misc.launcher$appclassloader@2a139a55
File:/Users/Hengyunabc/Code/Java/Spring-Boot-Inside/Demo-Classloader-Context/Target/Demo/
Bahkan, ada dua cara lain untuk dijalankan: mvn spring-boot:run dan mvn spring-boot:run -Dfork=true , tetapi jarang digunakan dan tidak akan dibahas secara terpisah. Jika Anda merasa tertarik, Anda dapat berlari sendiri.
Ringkasan Hubungan Warisan ClassLoader di Spring Boot
Saat fungsi utama dieksekusi dalam IDE, hanya ada satu classloader, yaitu, SystemClassLoader
Saat berjalan sebagai toples lemak, ada peluncuran luncur
URL LaunchedUrlClassLoader adalah guci di bawah boot-inf/kelas dan boot-inf/lib dalam stoples gemuk. URL dari SystemClassloader adalah toples gemuk itu sendiri.
Saat menjalankan direktori yang belum di -zip, mirip dengan toples lemak, tetapi URL dalam bentuk direktori. Format direktori akan memiliki kompatibilitas yang lebih baik.
Versi boot musim semi 1.3. dan 1.4.
Di Spring Boot 1.3.* Versi
Kelas loader boot pegas ditempatkan di toples lemak
Perubahan struktur pengemasan boot musim semi 1.4 diperkenalkan oleh komit ini
https://github.com/spring-projects/spring-boot/commit/87fe0b2adeef85c842c009bfeebac1c84af8a5d7
Tujuan asli dari komit ini adalah untuk menyederhanakan hubungan warisan classloader, mengimplementasikan LaunchedUrlClassloader dengan cara orang tua-pertama yang intuitif, dan pada saat yang sama, struktur pengemasan lebih dekat dengan aplikasi paket perang tradisional.
Namun, perubahan ini menyebabkan banyak masalah kompleks. Dari atas kami menganalisis hubungan warisan classloader sedikit pusing.
Beberapa dampak dari hubungan warisan classloader saat ini
Ada banyak pengguna yang mungkin menemukan bahwa beberapa kode berjalan dengan baik di IDE tetapi tidak berfungsi saat benar -benar digunakan. Sering kali disebabkan oleh struktur classloader. Inilah beberapa kasus.
demo.jar!/boot-inf/kelas!/dengan cara ini URL tidak berfungsi
Karena Spring Boot memperluas protokol toples standar, yang memungkinkannya untuk mendukung toples multi-lapisan dalam toples dan direktori dalam toples. Lihat Analisis Prinsip Startup Aplikasi Boot Spring
Meskipun akan ada Jar dalam Jar di Spring Boot 1.3, beberapa kode yang relatif kuat dapat menangani situasi ini, seperti Tomcat8 sendiri mendukung Jar dalam toples.
Namun, sebagian besar kode tidak akan mendukung beberapa URL seperti demo.jar!/BOOT-INF/classes!/ , Jadi di Spring Boot1.4, banyak kode perpustakaan akan tidak valid.
Masalah Sumber Daya di bawah Demo.Jar!/Meta-Inf/Resources
Dalam spesifikasi Servlet 3.0, aplikasi dapat menempatkan sumber daya statis di bawah meta-inf/sumber daya, dan wadah servlet akan mendukung pembacaan. Tetapi dari hasil warisan di atas, kita dapat menemukan masalah:
Ini menciptakan beberapa fenomena aneh:
Selain itu, contoh JSSP resmi Spring Boot hanya mendukung format pengemasan perang dan tidak mendukung toples lemak, yang juga disebabkan oleh ini.
Masalah dengan nilai pengembalian GetResource ("") dan GetResources ("")
Semantik GetResource ("") akan mengembalikan URL pertama dari URL ClassLoader. Sering kali pengguna berpikir bahwa ini adalah direktori kelas mereka sendiri, atau URL JAR.
Tetapi pada kenyataannya, karena Classloader memuat daftar URLS, itu acak, yang terkait dengan implementasi OS tingkat rendah, dan tidak dapat menjamin bahwa urutan URL adalah sama. Oleh karena itu, hasil yang dikembalikan oleh GetResource ("") seringkali berbeda.
Namun, banyak perpustakaan, atau aplikasi bergantung pada kode ini untuk menemukan sumber daya pemindaian, sehingga mereka tidak akan bekerja di bawah boot musim semi.
Selain itu, perlu dicatat bahwa boot musim semi berjalan dalam tiga bentuk yang berbeda, dan hasilnya yang dikembalikan oleh GetResources ("") juga berbeda. Pengguna dapat mengubah kode dalam demo sendiri dan mencetak hasilnya.
Singkatnya, jangan mengandalkan kedua API ini, yang terbaik adalah menempatkan sumber daya untuk menemukannya sendiri. Atau secara langsung menggunakan mekanisme pemindaian sumber daya yang disediakan oleh Spring itu sendiri.
Masalah Klasifikasi Liar Mirip dengan ClassPath*: **-Service.xml
Pengguna memiliki beberapa modul kode, dan beberapa file konfigurasi pegas *-service.xml ditempatkan di bawah modul yang berbeda.
Jika pengguna menggunakan wildcard seperti ClassPath*: **-service.xml untuk memuat sumber daya, sangat mungkin bahwa ia dapat memuat dengan benar saat berjalan di IDE, tetapi tidak dapat memuat di bawah toples lemak.
Anda dapat melihat analisis yang relevan dari dokumentasi Spring sendiri:
https://docs.spring.io/spring/docs/4.3.9.release/javadoc-api/org/springframework/core/io/support/pathmatchingResourcePatternresolver.html
PERINGATAN: Perhatikan bahwa "ClassPath:" ketika dikombinasikan dengan pola gaya semut hanya akan bekerja dengan andal dengan setidaknya satu direktori root sebelum pola dimulai, kecuali file target yang sebenarnya berada di sistem file. Ini berarti bahwa pola seperti "classpath:*. Xml" tidak akan mengambil file dari akar file jar tetapi hanya dari root direktori yang diperluas. Ini berasal dari batasan dalam metode ClassLoader.getResources () JDK yang hanya mengembalikan lokasi sistem file untuk string kosong yang dilewatkan (menunjukkan akar potensial untuk mencari). Implementasi ResourcePatternResolver ini mencoba mengurangi batasan pencarian JAR Root melalui UrlClassloader Pendahuluan dan evaluasi manifes "java.class.path"; Namun, tanpa jaminan portabilitas.
Dengan kata lain, saat menggunakan ClassPath* untuk mencocokkan paket toples lainnya, perlu ada lapisan direktori di depan, jika tidak itu tidak akan cocok. Ini disebabkan oleh fungsi classloader.getResources ().
Karena ketika berjalan di IDE, modul lain yang diandalkan aplikasi biasanya merupakan direktori kelas, jadi biasanya tidak ada masalah.
Namun, ketika berjalan dengan toples lemak, modul lain dikemas sebagai toples dan ditempatkan di bawah boot-inf/lib, sehingga distribusi liar akan gagal saat ini.
Meringkaskan
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.