Saya memahami perbedaan antara waktu proses dan waktu kompilasi serta cara membedakan keduanya, tetapi saya tidak melihat kebutuhan untuk membuat perbedaan antara dependensi waktu kompilasi dan waktu proses .
Apa yang saya tersedak adalah ini: bagaimana sebuah program tidak bergantung pada sesuatu pada saat runtime yang bergantung padanya selama kompilasi? Jika aplikasi Java saya menggunakan log4j, maka ia membutuhkan file log4j.jar untuk mengkompilasi (kode saya terintegrasi dengan dan memanggil metode anggota dari dalam log4j) serta runtime (kode saya sama sekali tidak memiliki kendali atas apa yang terjadi setelah kode di dalam log4j .jar dijalankan).
Saya sedang membaca tentang alat resolusi ketergantungan seperti Ivy dan Maven, dan alat ini dengan jelas membuat perbedaan antara kedua jenis ketergantungan ini. Saya hanya tidak mengerti perlunya itu.
Adakah yang bisa memberikan penjelasan tipe "King's English" yang sederhana, lebih disukai dengan contoh nyata yang bahkan orang miskin seperti saya pun bisa mengerti?
sumber
Jawaban:
Dependensi waktu kompilasi umumnya diperlukan pada waktu proses. Di maven,
compile
dependensi yang tercakup akan ditambahkan ke classpath saat runtime (misalnya dalam perang , dependensi tersebut akan disalin ke WEB-INF / lib).Namun, itu tidak benar-benar diperlukan; misalnya, kita dapat mengompilasi terhadap API tertentu, menjadikannya dependensi waktu kompilasi, tetapi kemudian pada waktu proses menyertakan implementasi yang juga menyertakan API.
Mungkin ada kasus pinggiran di mana proyek memerlukan ketergantungan tertentu untuk dikompilasi tetapi kemudian kode yang sesuai sebenarnya tidak diperlukan, tetapi ini akan jarang terjadi.
Di sisi lain, termasuk dependensi waktu proses yang tidak diperlukan pada waktu kompilasi sangat umum terjadi. Misalnya, jika Anda menulis aplikasi Java EE 6, Anda melakukan kompilasi terhadap Java EE 6 API, tetapi saat runtime, container Java EE apa pun dapat digunakan; wadah inilah yang menyediakan implementasi.
Ketergantungan waktu kompilasi dapat dihindari dengan menggunakan refleksi. Misalnya, driver JDBC dapat dimuat dengan a
Class.forName
dan kelas yang sebenarnya dimuat dapat dikonfigurasi melalui file konfigurasi.sumber
provided
cakupan menambahkan ketergantungan waktu kompilasi tanpa menambahkan ketergantungan waktu proses dengan harapan bahwa ketergantungan akan disediakan pada waktu proses dengan cara lain (misalnya perpustakaan bersama dalam wadah).runtime
di sisi lain menambahkan ketergantungan waktu proses tanpa menjadikannya sebagai ketergantungan waktu kompilasi.Setiap dependensi Maven memiliki cakupan yang menentukan classpath tempat dependensi tersebut tersedia.
Saat Anda membuat JAR untuk sebuah proyek, dependensi tidak digabungkan dengan artefak yang dihasilkan; mereka hanya digunakan untuk kompilasi. (Namun, Anda masih bisa membuat maven menyertakan dependensi di dalam jar bawaan, lihat: Termasuk dependensi di jar dengan Maven )
Saat Anda menggunakan Maven untuk membuat file WAR atau EAR, Anda dapat mengkonfigurasi Maven untuk menggabungkan dependensi dengan artefak yang dihasilkan, dan Anda juga dapat mengkonfigurasinya untuk mengecualikan dependensi tertentu dari file WAR menggunakan cakupan yang disediakan.
Cakupan yang paling umum - Compile Scope - menunjukkan bahwa dependensi tersedia untuk project Anda di classpath kompilasi, classpath dan compile pengujian unit, dan classpath waktu proses akhirnya saat Anda menjalankan aplikasi. Dalam aplikasi web Java EE, ini berarti ketergantungan tersebut disalin ke dalam aplikasi yang Anda terapkan. Namun dalam file .jar, dependensi tidak akan disertakan dengan cakupan kompilasi ..
Runtime Scope menunjukkan bahwa dependensi tersedia untuk project Anda pada classpath eksekusi pengujian unit dan eksekusi runtime, tetapi tidak seperti cakupan kompilasi, dependensi ini tidak tersedia saat Anda mengompilasi aplikasi atau pengujian unitnya. Dependensi Runtime disalin ke dalam aplikasi yang Anda terapkan, tetapi tidak tersedia selama kompilasi! Ini bagus untuk memastikan Anda tidak salah bergantung pada perpustakaan tertentu.
Terakhir, Cakupan yang Diberikan menunjukkan bahwa wadah tempat aplikasi Anda dijalankan menyediakan ketergantungan atas nama Anda. Dalam aplikasi Java EE, ini berarti dependensi sudah ada di classpath penampung Servlet atau server aplikasi dan tidak disalin ke dalam aplikasi yang Anda terapkan. Ini juga berarti Anda memerlukan ketergantungan ini untuk mengompilasi proyek Anda.
sumber
Anda membutuhkan dependensi pada waktu kompilasi yang mungkin Anda perlukan pada waktu proses. Namun banyak pustaka yang berjalan tanpa semua kemungkinan dependensinya. yaitu sebuah perpustakaan yang dapat menggunakan empat perpustakaan XML yang berbeda, tetapi hanya membutuhkan satu untuk bekerja.
Banyak perpustakaan, membutuhkan perpustakaan lain pada gilirannya. Pustaka ini tidak diperlukan pada waktu kompilasi tetapi dibutuhkan pada waktu proses. yaitu ketika kode benar-benar dijalankan.
sumber
Secara umum Anda benar dan mungkin itu adalah situasi yang ideal jika dependensi waktu proses dan waktu kompilasi identik.
Saya akan memberi Anda 2 contoh jika aturan ini salah.
Jika kelas A bergantung pada kelas B yang bergantung pada kelas C yang bergantung pada kelas D di mana A adalah kelas Anda dan B, C dan D adalah kelas dari pustaka pihak ketiga yang berbeda, Anda hanya perlu B dan C pada waktu kompilasi dan Anda juga perlu D pada runtime. Seringkali program menggunakan pemuatan kelas dinamis. Dalam hal ini Anda tidak perlu kelas yang dimuat secara dinamis oleh perpustakaan yang Anda gunakan pada waktu kompilasi. Selain itu, sering kali pustaka memilih implementasi mana yang akan digunakan pada waktu proses. Misalnya SLF4J atau Commons Logging dapat mengubah implementasi log target saat runtime. Anda hanya perlu SSL4J itu sendiri pada waktu kompilasi.
Contoh sebaliknya ketika Anda membutuhkan lebih banyak dependensi pada waktu kompilasi daripada saat runtime. Pikirkan bahwa Anda sedang mengembangkan aplikasi yang harus bekerja di lingkungan atau sistem operasi yang berbeda. Anda memerlukan semua pustaka khusus platform pada waktu kompilasi dan hanya pustaka yang diperlukan untuk lingkungan saat ini pada waktu proses.
Saya harap penjelasan saya membantu.
sumber
Biasanya grafik dependensi statis adalah sub-grafik dari grafik dinamis, lihat misalnya entri blog ini dari penulis NDepend .
Meskipun demikian, ada beberapa pengecualian, terutama dependensi yang menambahkan dukungan compiler, yang menjadi tidak terlihat pada waktu proses. Misalnya untuk pembuatan kode melalui Lombok atau pemeriksaan tambahan melalui Kerangka Pemeriksa (tipe yang dapat dicolokkan) .
sumber
Baru saja mengalami masalah yang menjawab pertanyaan Anda.
servlet-api.jar
adalah ketergantungan sementara dalam proyek web saya dan dibutuhkan baik pada waktu kompilasi maupun waktu proses. Tetapiservlet-api.jar
juga termasuk dalam perpustakaan Tomcat saya.Solusinya di sini adalah membuat
servlet-api.jar
maven hanya tersedia pada waktu kompilasi dan tidak dikemas dalam file perang saya sehingga tidak akan bentrok dengan yangservlet-api.jar
terdapat di perpustakaan Tomcat saya.Saya harap ini menjelaskan waktu kompilasi dan dependensi Runtime.
sumber
compile
danprovided
cakupan dan bukan antaracompile
danruntime
.Compile scope
keduanya dibutuhkan pada waktu kompilasi dan dikemas dalam aplikasi Anda.Provided scope
hanya diperlukan pada waktu kompilasi tetapi tidak dikemas dalam aplikasi Anda karena ini disediakan dengan cara lain, misalnya sudah ada di server Tomcat.compile
danruntime
maven . Theprovided
lingkup adalah cara maven menangani kasus di mana ketergantungan kompilasi-kali tidak harus disertakan dalam paket runtime.Konsep umum waktu kompilasi dan runtime serta dependensi spesifik
compile
danruntime
cakupan Maven adalah dua hal yang sangat berbeda. Anda tidak dapat membandingkannya secara langsung karena keduanya tidak memiliki bingkai yang sama: konsep umum kompilasi dan runtime luas sedangkan konsep mavencompile
danruntime
cakupan secara khusus membahas ketersediaan / visibilitas dependensi sesuai dengan waktu: kompilasi atau eksekusi.Jangan lupa bahwa Maven di atas segalanya adalah a
javac
/java
wrapper dan bahwa di Java Anda memiliki classpath waktu kompilasi yang Anda tentukanjavac -cp ...
dan classpath waktu proses yang Anda tentukanjava -cp ...
.Tidak salah jika mempertimbangkan
compile
cakupan Maven sebagai cara untuk menambahkan dependensi baik dalam compile Java maupun classppath waktu proses (javac
danjava
) sementararuntime
cakupan Maven bisa dilihat sebagai cara untuk menambahkan dependensi hanya di classppath (javac
) runtime Java .Apa yang Anda gambarkan tidak memiliki hubungan
runtime
dancompile
ruang lingkup.Sepertinya lebih banyak
provided
cakupan yang Anda tentukan agar dependensi bergantung padanya pada waktu kompilasi tetapi tidak pada waktu proses.Anda menggunakannya karena Anda memerlukan dependensi untuk dikompilasi tetapi Anda tidak ingin memasukkannya ke dalam komponen yang dikemas (JAR, WAR, atau lainnya) karena dependensi tersebut sudah disediakan oleh lingkungan: dapat disertakan di server atau yang lainnya. jalur classpath yang ditentukan saat aplikasi Java dimulai.
Dalam hal ini ya. Tetapi anggaplah Anda perlu menulis kode portabel yang mengandalkan slf4j sebagai fasad di depan log4j untuk dapat beralih ke implementasi logging lain nanti (log4J 2, logback, atau lainnya).
Dalam kasus ini di you pom Anda perlu menentukan slf4j sebagai
compile
dependensi (ini adalah default) tetapi Anda akan menentukan dependensi log4j sebagairuntime
dependensi:Dengan cara ini, kelas log4j tidak dapat dirujuk dalam kode yang dikompilasi tetapi Anda masih dapat merujuk kelas slf4j.
Jika Anda menentukan dua dependensi dengan
compile
waktu, tidak ada yang akan menghalangi Anda untuk mereferensikan kelas log4j dalam kode yang dikompilasi dan Anda dapat membuat penggabungan yang tidak diinginkan dengan implementasi logging:Penggunaan umum
runtime
ruang lingkup adalah deklarasi ketergantungan JDBC. Untuk menulis kode portabel, Anda tidak ingin kode klien dapat merujuk kelas dependensi DBMS tertentu (misalnya: ketergantungan JDBC PostgreSQL) tetapi Anda ingin semua hal yang sama memasukkannya ke dalam aplikasi Anda karena pada waktu proses kelas perlu membuatnya API JDBC bekerja dengan DBMS ini.sumber
Pada waktu kompilasi, Anda mengaktifkan kontrak / api yang diharapkan dari dependensi Anda. (misalnya: di sini Anda baru saja menandatangani kontrak dengan penyedia internet broadband) Pada saat run-time sebenarnya Anda menggunakan dependensi. (mis .: di sini Anda sebenarnya menggunakan internet broadband)
sumber
Untuk menjawab pertanyaan "bagaimana sebuah program tidak bergantung pada sesuatu pada saat runtime yang bergantung padanya selama kompilasi?", Mari kita lihat contoh pemroses anotasi.
Misalkan Anda telah menulis pemroses anotasi Anda sendiri, dan anggap pemroses tersebut memiliki ketergantungan waktu kompilasi
com.google.auto.service:auto-service
sehingga dapat digunakan@AutoService
. Ketergantungan ini hanya diperlukan untuk mengompilasi pemroses anotasi, tetapi tidak diperlukan pada waktu proses: semua proyek lain yang bergantung pada pemroses anotasi Anda untuk memproses anotasi tidak memerlukan ketergantungan padacom.google.auto.service:auto-service
saat runtime (atau pada waktu kompilasi atau pada waktu lain) .Ini tidak terlalu umum, tetapi itu terjadi.
sumber
The
runtime
lingkup yang ada untuk mencegah programmer menambahkan dependensi langsung ke implementasi perpustakaan dalam kode daripada menggunakan abstraksi atau fasad.Dengan kata lain, itu memaksa untuk menggunakan antarmuka.
Contoh konkrit:
1) Tim Anda menggunakan SLF4J melalui Log4j. Anda ingin programmer Anda menggunakan SLF4J API, bukan Log4j. Log4j hanya akan digunakan oleh SLF4J secara internal. Larutan:
2) Aplikasi Anda mengakses MySQL menggunakan JDBC. Anda ingin programmer Anda membuat kode berdasarkan abstraksi JDBC standar, bukan secara langsung terhadap implementasi driver MySQL.
mysql-connector-java
(driver MySQL JDBC) sebagai dependensi waktu proses.Dependensi runtime disembunyikan selama kompilasi (memunculkan error waktu kompilasi jika kode Anda memiliki ketergantungan "langsung" padanya) tetapi disertakan selama waktu eksekusi dan saat membuat artefak yang dapat diterapkan (file WAR, file jar SHADED, dll.).
sumber