Catatan: Kata -kata berikut seperti "jembatan", "konversi", dan "mengikat" pada dasarnya adalah konsep yang sama.
Log4j-over-SLF4J dan SLF4J-LOG4J12 adalah dua paket JAR yang terkait dengan sistem log Java. Ketika mereka muncul di bawah classpath pada saat yang sama, mereka dapat menyebabkan pengecualian overflow. Informasi pengecualian kira-kira sebagai berikut (dikutip dari dokumen situs web resmi SLF4J mendeteksi baik log4j-over-slf4j.jar dan slf4j-log4j12.jar di jalur kelas, mendahului stackoverflowerror):
Pengecualian di Thread "Main" Java.lang.Stackoverflowerror
di java.util.hashtable.containskey (hashtable.java:306)
di org.apache.log4j.log4jloggerfactory.getlogger (log4jloggerfactory.java:36)
di org.apache.log4j.logmanager.getLogger (LogManager.java:39)
di org.slf4j.impl.log4jloggerFactory.getLogger (log4jloggerfactory.java:73)
di org.slf4j.loggerfactory.getlogger (LoggerFactory.java:249)
di org.apache.log4j.category. <inin> (Category.java:53)
di org.apache.log4j.logger .. <inin> (logger.java:35)
di org.apache.log4j.log4jloggerfactory.getlogger (log4jloggerfactory.java:39)
di org.apache.log4j.logmanager.getLogger (LogManager.java:39)
di org.slf4j.impl.log4jloggerFactory.getLogger (log4jloggerfactory.java:73)
di org.slf4j.loggerfactory.getlogger (LoggerFactory.java:249)
di org.apache.log4j.category .. <init> (Category.java:53)
di org.apache.log4j.logger .. <inin> (logger.java:35)
di org.apache.log4j.log4jloggerfactory.getlogger (log4jloggerfactory.java:39)
di org.apache.log4j.logmanager.getLogger (LogManager.java:39)
Garis selanjutnya dihilangkan ...
Sistem logging yang ada
Sebelum menganalisis alasan spesifik untuk pengecualian ini, perlu dengan cepat memahami sistem penebangan Java yang ada. Gambar berikut adalah diagram sistem logging Java yang ada:
Gambar di atas tidak terlalu akurat, tetapi dapat dengan jelas menampilkan struktur utama dari sistem log Java yang ada. Sistem logging Java dapat dibagi secara kasar menjadi tiga bagian: antarmuka log fasad, jembatan, dan kerangka log spesifik.
Ada banyak jenis kerangka kerja logging Java. Yang paling sederhana adalah java.util.logging Java sendiri, dan yang paling klasik adalah log4j. Kemudian, logback dengan kinerja yang lebih baik daripada log4j yang muncul, sehingga kerangka log lainnya tidak terlalu umum digunakan. Tentunya dimungkinkan bagi aplikasi untuk secara langsung menggunakan API dari kerangka log spesifik ini untuk memenuhi persyaratan output log, tetapi karena API antara setiap kerangka log biasanya tidak kompatibel, melakukan hal itu membuat aplikasi kehilangan fleksibilitas untuk mengganti kerangka log.
Opsi yang lebih masuk akal daripada secara langsung menggunakan API kerangka log spesifik adalah dengan menggunakan antarmuka log fasad. Antarmuka log fasad menyediakan serangkaian API yang tidak tergantung pada kerangka log spesifik. Aplikasi dapat memisahkan dari kerangka log spesifik dengan menggunakan API independen ini, yang mirip dengan JDBC. Antarmuka log fasad paling awal adalah genangan commons, tetapi yang paling populer saat ini adalah SLF4J.
Antarmuka log fasad itu sendiri biasanya tidak memiliki kemampuan output log aktual. Masih perlu memanggil API kerangka log spesifik di bagian bawah, yaitu, sebenarnya perlu digunakan dalam kombinasi dengan kerangka log spesifik. Karena ada banyak kerangka log spesifik dan sebagian besar tidak kompatibel satu sama lain, jika antarmuka log fasad dikombinasikan dengan kerangka log apa pun, itu mungkin memerlukan jembatan yang sesuai, seperti kombinasi antara JDBC dan berbagai database yang berbeda memerlukan driver JDBC yang sesuai.
Perlu dicatat bahwa seperti yang disebutkan sebelumnya, gambar di atas tidak akurat, ini hanya bagian utama, dan situasi sebenarnya tidak selalu merupakan garis satu arah sederhana "antarmuka log fasad-> jembatan-> kerangka log". Faktanya, jembatan independen kadang -kadang tidak diperlukan, dan bukan hanya jembatan yang mengubah API log fasad menjadi API kerangka log tertentu. Ada juga jembatan yang mengonversi Log Framework API ke Log Fasade API.
Terus terang, yang disebut "jembatan" tidak lebih dari implementasi semu dari serangkaian API tertentu. Implementasi ini tidak secara langsung menyelesaikan fungsi yang dinyatakan oleh API, tetapi memanggil API lain dengan fungsi yang sama. Ini melengkapi transisi dari "satu set API" ke "API lainnya". Jika ada dua jembatan, a-to-b.jar dan b-to-a.jar, maka Anda dapat membayangkan apa yang akan terjadi ketika aplikasi mulai memanggil API atau B. Ini adalah prinsip dasar dari pengecualian overflow tumpukan yang pertama kali diperkenalkan.
Slf4j Forwarding Binding
Di atas hanyalah penjelasan umum dari sistem logging Java yang ada, dan tidak mungkin untuk menjelaskan masalah secara rinci. Kita perlu lebih memahami situasi menjembatani antara SLF4J dan kerangka log spesifik.
Slf4j Bridges ke bingkai log tertentu
Gambar berikut berasal dari dokumen situs web resmi SLF4J yang mengikat dengan kerangka kerja logging pada waktu penempatan:
Anda dapat melihat bahwa ada banyak solusi untuk digabungkan dengan kerangka log spesifik. Tentu saja, lapisan paling atas (lapisan aplikasi hijau) dari setiap solusi disatukan. Mereka secara langsung memanggil API yang disediakan oleh SLF4J (lapisan API abstrak biru muda) dan mengandalkan slf4j-api.jar. Kemudian, jika Anda melakukan API SLF4J ke bawah, itu akan sangat gratis, dan Anda dapat menggunakan hampir semua kerangka kerja logging tertentu. Perhatikan bahwa lapisan kedua pada gambar berwarna biru muda. Melihat legenda di sudut kiri bawah, kita dapat melihat bahwa ini mewakili API log abstrak, yang berarti bahwa mereka bukan implementasi konkret. Jika lapisan yang lebih rendah tidak dikombinasikan dengan implementasi kerangka log spesifik seperti solusi pertama di sebelah kiri, maka log tidak dapat menjadi output ( tidak yakin apakah mungkin output ke output standar secara default ).
Lapisan ketiga dalam gambar jelas tidak rapi seperti lapisan pertama dan kedua, karena kerangka log spesifik telah mulai terlibat di sini.
Pertama, mari kita lihat dua blok Danau Biru di tengah lantai tiga, yang merupakan lapisan adaptor, yaitu jembatan. Jembatan slf4j-log4j12.jar di sebelah kiri dapat mengatakan bahwa itu adalah jembatan dari slf4j ke log4j berdasarkan namanya. Demikian pula, slf4j-jdk14.jar di sebelah kanan adalah jembatan yang diimplementasikan oleh SLF4J ke log asli Java. Lapisan berikutnya adalah implementasi kerangka log yang sesuai. Kode implementasi LOG4J adalah log4j.jar, dan kode implementasi JUL sudah termasuk dalam runtime JVM dan tidak memerlukan paket JAR terpisah.
Mari kita lihat sisa tiga blok biru gelap di lantai tiga. Mereka bertiga juga merupakan implementasi kerangka logging spesifik, tetapi mereka tidak memerlukan jembatan karena mereka sendiri secara langsung menerapkan API SLF4J. Tak perlu dikatakan, slf4j-simple.jar dan slf4j-nop.jar, Anda dapat mengatakan bahwa yang satu adalah implementasi sederhana dari SLF4J dan yang lainnya adalah implementasi kosong SLF4J, yang tidak terlalu berguna pada waktu normal. Alasan mengapa logback juga mengimplementasikan API SLF4J dikatakan karena Logback dan SLF4J berasal dari orang yang sama, yang juga penulis Log4j.
Semua paket toples abu -abu di lapisan ketiga memiliki kotak merah, yang berarti bahwa mereka semua secara langsung mengimplementasikan API SLF4J. Namun, implementasi API SLF4J oleh Danau Blue Bridge tidak secara langsung mengeluarkan log, tetapi sebaliknya memanggil API dari kerangka log lainnya.
Kerangka Log Lainnya API Panggilan Kembali ke SLF4J
Jika hanya jembatan di atas dari SFL4J ke kerangka log lainnya, mungkin tidak ada masalah. Namun pada kenyataannya, ada jenis jembatan lain, yang fungsinya persis kebalikan dari hal di atas, mereka mengonversi API dari kerangka log lainnya menjadi SLF4J API. Gambar berikut ini berasal dari Slf4j Official Situs Web Dokumen Jembatan Legacy API:
Gambar di atas menunjukkan ketiga kasus yang dapat dengan aman menelepon kembali ke SLF4J dari API kerangka log lainnya sejauh ini.
Mengambil kasing pertama di sudut kiri atas sebagai contoh, ketika SLF4J yang mendasari dijembatani ke kerangka logback, API kerangka log yang memungkinkan lapisan atas untuk menjembatani kembali ke SLF4J termasuk Log4j dan Jul. Meskipun JCL bukan implementasi spesifik dari kerangka kerja logging, API -nya masih dapat dipanggil kembali ke SLF4J. Untuk mengimplementasikan konversi, metode ini adalah mengganti toples bingkai log asli dengan toples jembatan spesifik yang tercantum dalam gambar. Perlu dicatat bahwa API logback ke API SLF4J tidak termasuk konversi API logback, karena logback pada awalnya merupakan implementasi API SLF4J.
Setelah membaca tiga situasi, Anda akan menemukan bahwa hampir semua API dari kerangka log lainnya, termasuk JCL API, dapat diarahkan kembali ke SLF4J sesuka hati. Tetapi hanya ada batasan bahwa kerangka log yang memanggil kembali ke SLF4J tidak dapat sama dengan kerangka log yang saat ini menjembatani SLF4J. Keterbatasan ini adalah untuk mencegah A-to-B.Jar dan B-to-A.Jar muncul di Classpath pada saat yang sama, menghasilkan A dan B secara konstan memanggil satu sama lain secara rekursif, dan akhirnya menumpuk overflow. Saat ini, pembatasan ini tidak dijamin oleh teknologi, tetapi hanya oleh pengembang itu sendiri. Inilah sebabnya mengapa situs web resmi SLF4J menekankan bahwa semua metode yang masuk akal hanya dalam tiga situasi dalam gambar di atas.
Pada titik ini, prinsip pengecualian yang ditunjukkan pada awalnya pada dasarnya jelas. Selain itu, dari gambar di atas, kita dapat melihat bahwa mungkin ada kombinasi yang mirip dengan pengecualian tidak hanya log4j-over-slf4j dan slf4j-log4j12. Situs web resmi SLF4J juga menunjukkan pasangan lain: jcl-over-slf4j.jar dan slf4j-jcl.jar.
Contoh Kode
Analisis sebelumnya adalah teoretis. Bahkan jika log4j-over-slf4j dan slf4j-log4j12 digunakan pada saat yang sama dalam kode aktual, pengecualian mungkin tidak harus terjadi. Kode berikut memanggil API SLF4J untuk mengeluarkan log, dan Slf4j dijembatani ke log4j:
Tes paket; kelas publik HelloWorld {public static void main (string [] args) {org.apache.log4j.basicconfigurator.configure (); org.slf4j.logger orger (org.slf4j.loggerfactory.getLogger (helloworld. "logger (helloWorld (helloWorld (helloWord. loggerfactory.getlogger (helloWorld (helloWorld (helloWord." hello (helloWorld (helloWorl.Konfigurasikan ClassPath untuk mengonfigurasi paket JAR (perhatikan bahwa log4j sebelum log4j-over-slf4j):
Dalam hal ini, menjalankan program pengujian dapat menghasilkan log secara normal dan tidak akan ada pengecualian overflow. Tetapi jika Anda menyesuaikan pesanan toples di classpath untuk:
Menjalankan program pengujian lagi akan menyebabkan pengecualian overflow yang mirip dengan overflow stack awal dalam artikel ini. Anda dapat melihat pengulangan periodik yang jelas:
Analisis Bagan Urutan
Gambar di atas adalah diagram kolom program panggilan terperinci dari Stack Overflow. Mulai dari panggilan 1, hubungi 1.1, 1.1.1 ... Akhirnya, ketika mencapai 1.1.1.1.1 (panggilan terakhir pada gambar), ditemukan bahwa itu persis sama dengan 1, sehingga proses selanjutnya sepenuhnya diulang.
Perlu dicatat bahwa sekering awal tidak hanya LoggerFactory.getLogger () ditunjukkan pada gambar. Ada beberapa panggilan langsung lainnya dalam aplikasi yang dapat memicu pengecualian overflow stack. Sebagai contoh, dalam kode contoh sebelumnya, pernyataan pertama org.apache.log4j.basicconfigurator.configure () sebenarnya adalah pernyataan pertama org.apache.log4j.basicconfigurator.configure (), tetapi proses panggilan rekursif mutual tak terbatas berikutnya pada dasarnya sama dengan figur sebelumnya.
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.