Perbedaan antara manajemen ketergantungan dan dependensi dalam Maven

766

Apa perbedaan antara dependencyManagementdan dependencies? Saya telah melihat dokumen di situs web Apache Maven. Tampaknya ketergantungan yang ditentukan di bawah dependencyManagementdapat digunakan dalam modul turunannya tanpa menentukan versi.

Sebagai contoh:

Proyek induk (Pro-par) mendefinisikan ketergantungan di bawah dependencyManagement:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8</version>
    </dependency>
 </dependencies>
</dependencyManagement>

Kemudian pada anak Pro-par, saya dapat menggunakan junit:

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </dependency>
 </dependencies>

Namun, saya bertanya-tanya apakah perlu mendefinisikan junit di pom induk? Mengapa tidak mendefinisikannya langsung di modul yang dibutuhkan?

hguser
sumber

Jawaban:

464

Manajemen Ketergantungan memungkinkan untuk mengkonsolidasikan dan memusatkan pengelolaan versi ketergantungan tanpa menambahkan ketergantungan yang diwarisi oleh semua anak. Ini sangat berguna ketika Anda memiliki satu set proyek (yaitu lebih dari satu) yang mewarisi orang tua yang sama.

Kasus penggunaan lain yang sangat penting dependencyManagementadalah kontrol versi artefak yang digunakan dalam dependensi transitif. Ini sulit dijelaskan tanpa contoh. Untungnya, ini diilustrasikan dalam dokumentasi.

Thivent Pascal
sumber
17
Jadi, perlu mendeklarasikan dependensi dalam pom proyek anak meskipun jika mereka menyatakan dalam pom proyek induk di bagian <dependencyManagement>? Apakah mungkin membuat semacam warisan ketergantungan?
johnny-b-goode
55
Ya, Anda masih perlu mendefinisikannya di POM anak untuk menunjukkan bahwa Anda menggunakannya. Mereka tidak benar-benar dimasukkan dalam proyek anak hanya karena mereka berada di <dependencyManagement>dalam POM induk. Menutupi dependensi dalam <dependencyManagement>manajemen versi, ruang lingkup, dan pengecualian yang terpusat untuk setiap dependensi, jika dan ketika Anda memutuskan untuk menggunakannya. Panduan Maven untuk manajemen ketergantungan masuk ke semua detail.
hotshot309
2
Paragraf kedua ( dependencyManagementjuga mengontrol dependensi transitif) hanya benar ketika dependensi diatur secara eksplisit: stackoverflow.com/questions/28312975/…
Robert Metzger
2
@ johnny-b-goode Apa yang masih bisa Anda lakukan adalah membuat dependenciesbagian baru di pom orang tua Anda. Kami melakukan itu sehingga semua proyek anak memiliki beberapa apache-commons secara default dan tidak menyatakannya sepanjang waktu.
рüффп
771

Saya sangat terlambat untuk pertanyaan ini, tetapi saya pikir itu layak respon yang lebih jelas daripada yang diterima (yang benar, tetapi tidak menekankan bagian penting yang sebenarnya, yang perlu Anda simpulkan sendiri).

Di POM induk, perbedaan utama antara <dependencies>dan <dependencyManagement>adalah:

Artefak yang ditentukan dalam <dependencies>bagian ini SELALU akan dimasukkan sebagai ketergantungan modul anak.

Artefak yang ditentukan dalam <dependencyManagement>bagian, hanya akan dimasukkan dalam modul anak jika mereka juga ditentukan dalam <dependencies>bagian dari modul anak itu sendiri. Mengapa ada baiknya Anda bertanya? karena Anda menentukan versi dan / atau ruang lingkup di induknya, dan Anda dapat mengabaikannya ketika menentukan dependensi dalam POM anak. Ini dapat membantu Anda menggunakan versi terpadu untuk dependensi untuk modul anak, tanpa menentukan versi di setiap modul anak.

dcoder
sumber
1
Tapi bukan juga sedikit overhead, menggunakan <dependencyManagement>lebih <dependencies>dalam akar .pom? Anak pombisa jauh lebih pendek.
Janez Kuhar
18
Itu benar. Menggunakan <dependency> alih-alih <dependencyManagement> akan membuat pom anak yang lebih pendek. Namun, ia datang dengan biaya - itu berarti bahwa dependensi tersebut akan SELALU ditentukan untuk SEMUA modul anak. Jika hanya beberapa modul anak memerlukan dependensi tertentu, daripada menggunakan "<dependencyManagement>" sebagai gantinya akan memungkinkan Anda untuk memilih modul anak mana yang akan memiliki dependensi itu, dan masih sedikit efisien dengan mengatur versi dependensi hanya di pom induk.
dcoder
2
@JanezKuhar Masuk akal bagi saya bahwa jika Anda menentukan ketergantungan pada modul anak itu akan menimpa yang ada di orangtua, tapi saya akui saya tidak ingat. Saya harus memeriksa dokumen pakar itu ketika saya mendapat kesempatan. Meskipun mungkin lebih mudah untuk hanya menyiapkan proyek orangtua-anak yang sederhana dan memverifikasi :)
dcoder
26
Penjelasan yang bagus untuk konsep yang sederhana - mengapa begitu sulit bagi Maven untuk menjelaskan alat mereka sendiri dengan mudah?
jimmy_terra
1
Saya ingin menambahkan Artifacts specified in the <dependencies> section will ALWAYS be included as a dependency of the child module(s)bahwa mereka termasuk dalam orangtua juga. Tampaknya tidak mungkin untuk menetapkan ketergantungan untuk anak-anak, tetapi tidak untuk orang tua.
caduceus
54

The dokumentasi di situs Maven mengerikan. Apa yang dilakukan dependencyManagement hanyalah memindahkan definisi dependensi Anda (versi, pengecualian, dll) ke pom induk, kemudian di pom anak Anda hanya perlu meletakkan groupId dan artifactId. Itu saja (kecuali untuk rantai pom induk dan sejenisnya, tapi itu tidak terlalu rumit juga - dependensiManajemen menang atas ketergantungan pada tingkat induk - tetapi jika memiliki pertanyaan tentang itu atau impor, dokumentasi Maven sedikit lebih baik).

Setelah membaca semua sampah 'a', 'b', 'c' di situs Maven dan menjadi bingung, saya menulis ulang contoh mereka. Jadi jika Anda memiliki 2 proyek (proj1 dan proj2) yang memiliki ketergantungan yang sama (betaShared), Anda dapat memindahkan ketergantungan itu ke pom induk. Ketika Anda berada di sana, Anda juga dapat naik ke dependensi lain (alpha dan charlie) tetapi hanya jika masuk akal untuk proyek Anda. Jadi untuk situasi yang dijabarkan dalam kalimat sebelumnya, berikut adalah solusinya dengan dependensiManajemen di pom induk:

<!-- ParentProj pom -->
<project>
  <dependencyManagement>
    <dependencies>
      <dependency> <!-- not much benefit defining alpha here, as we only use in 1 child, so optional -->
        <groupId>alpha</groupId>
        <artifactId>alpha</artifactId>
        <version>1.0</version>
        <exclusions>
          <exclusion>
            <groupId>zebra</groupId>
            <artifactId>zebra</artifactId>
          </exclusion>
        </exclusions>
      </dependency>
      <dependency>
        <groupId>charlie</groupId> <!-- not much benefit defining charlie here, so optional -->
        <artifactId>charlie</artifactId>
        <version>1.0</version>
        <type>war</type>
        <scope>runtime</scope>
      </dependency>
      <dependency> <!-- defining betaShared here makes a lot of sense -->
        <groupId>betaShared</groupId>
        <artifactId>betaShared</artifactId>
        <version>1.0</version>
        <type>bar</type>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

<!-- Child Proj1 pom -->
<project>
  <dependencies>
    <dependency>
      <groupId>alpha</groupId>
      <artifactId>alpha</artifactId>  <!-- jar type IS DEFAULT, so no need to specify in child projects -->
    </dependency>
    <dependency>
      <groupId>betaShared</groupId>
      <artifactId>betaShared</artifactId>
      <type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
    </dependency>
  </dependencies>
</project>

<!-- Child Proj2 -->
<project>
  <dependencies>
    <dependency>
      <groupId>charlie</groupId>
      <artifactId>charlie</artifactId>
      <type>war</type> <!-- This is not a jar dependency, so we must specify type. -->
    </dependency>
    <dependency>
      <groupId>betaShared</groupId> 
      <artifactId>betaShared</artifactId> 
      <type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
    </dependency>
  </dependencies>
</project>
MattC
sumber
2
Agak di luar topik pertanyaan: apa arti tipe ketergantungan "bar"? Saya melihat dalam contoh pom pada dokumentasi Maven tetapi tidak dapat menemukan definisi. Saya berasumsi itu adalah kesalahan ketik "perang" atau "guci", tetapi saya melihatnya dalam contoh lain seperti milik Anda.
NobodyMan
NobodyMan - Jadi itu hanya pengganti untuk jenis arsip lain. Suka menggunakan 'foo'. Atau dapat digunakan jika seseorang membuat jenis khusus dengan ekstensi 'bilah'. Dan ada banyak jenis arsip yang tidak jelas di luar sana. Seperti sar, yang merupakan arsip layanan JBoss.
MattC
Contoh Anda cukup jelas, dan menegaskan kembali apa yang telah saya baca sendiri dari dokumentasi. Sudahkah Anda mengirimkannya ke proyek Maven? Setelah mempelajari contoh Anda, saya sedang bersiap untuk menyederhanakan POM yang memiliki keduanya, dan hanya membutuhkan deklarasi Ketergantungan, karena proyek yang terkait tidak memiliki anak.
David A. Gray
Yah, saya akan menjatuhkan node DependencyManagement, sampai saya sadar bahwa membiarkannya memungkinkan saya untuk membuat versi minimum untuk setiap POM anak yang menemukan jalan mereka ke pohon dependensi secara tidak langsung. Sebagai contoh, dalam mengejar javax.cache.cache-apI, saya menemukan versi yang jauh lebih baru 1.0.0 (dibandingkan 0.3.0) yang mungkin juga dapat digunakan di seluruh.
David A. Gray
Penjelasan ini sempurna.
Smart Coder
45

Seperti yang Anda katakan; dependencyManagementdigunakan untuk menarik semua informasi ketergantungan ke file POM umum, menyederhanakan referensi dalam file POM anak.

Ini menjadi berguna ketika Anda memiliki banyak atribut yang Anda tidak ingin mengetik ulang di bawah beberapa proyek anak-anak.

Akhirnya, dependencyManagementdapat digunakan untuk menentukan versi standar artefak untuk digunakan di berbagai proyek.

Pran
sumber
4
Jadi, dependensi tidak diwarisi? Perlu dideklarasikan di pom project anak?
johnny-b-goode
6
Ya, Anda harus mendeklarasikannya dalam proyek anak-anak, tetapi tanpa menentukan versi.
Pavel Vlasov
Skenario ini berguna ketika Anda ingin memiliki tata kelola versi di beberapa proyek java yang memiliki hubungan orangtua-anak.
Anuj Kumar
43

Masih ada satu hal yang tidak cukup disorot, menurut pendapat saya, dan itu adalah warisan yang tidak diinginkan .

Berikut ini contoh tambahan:

Saya menyatakan di parentpom saya :

<dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>
</dependencies>

ledakan! Saya memilikinya di modul saya Child A, Child Bdan Child C:

  • Implicilty diwarisi oleh pom anak
  • Satu tempat untuk dikelola
  • Tidak perlu mendeklarasikan ulang apa pun di pom anak
  • Saya masih dapat menata ulang dan mengganti ke version 18.0dalam Child Bjika saya mau.

Tetapi bagaimana jika saya akhirnya tidak membutuhkan jambu biji Child C, dan juga di masa depan Child Ddan Child Emodul?

Mereka masih akan mewarisinya dan ini tidak diinginkan! Ini seperti bau kode Java God Object, di mana Anda mewarisi beberapa bit berguna dari sebuah kelas, dan sejumlah hal yang tidak diinginkan juga.

Di sinilah <dependencyManagement>berperan. Ketika Anda menambahkan ini ke pom orang tua Anda, semua modul anak Anda BERHENTI melihatnya . Dan dengan demikian Anda dipaksa untuk masuk ke setiap modul individu yang TIDAK membutuhkannya dan mendeklarasikannya lagi ( Child Adan Child B, tanpa versi sekalipun).

Dan, jelas, Anda tidak melakukannya untuk itu Child C, dan dengan demikian modul Anda tetap ramping.

Andrejs
sumber
Apakah dependensi yang disebutkan dalam <dependencyManagement> downloded untuk proyek parent pom?
Jaspreet Jolly
Apakah Anda yakin bahwa jika kami menggunakan <dependencyManagement>pom induk maka dependensi default tidak akan diwarisi di pom anak? Karena dalam dokumen: maven.apache.org/guides/introduction/... saat menjelaskan penggunaan kedua <dependencyManagement>sepertinya akan diwarisi secara default. Pada satu baris mereka mengatakan bahwa: "Ketika maven dijalankan pada proyek B, versi 1.0 artefak a, b, c, dan d akan digunakan terlepas dari versi yang ditentukan dalam pom mereka" meskipun "b" tidak digunakan dalam proyek B
chirag soni
Cobalah sendiri
Andrejs
17

Ada beberapa jawaban yang menguraikan perbedaan antara <depedencies>dan <dependencyManagement>tag dengan pakar.

Namun, beberapa poin diuraikan di bawah ini dalam cara yang ringkas:

  1. <dependencyManagement>memungkinkan untuk menggabungkan semua dependensi (digunakan pada level pom anak) yang digunakan di berbagai modul - kejelasan , manajemen versi dependensi pusat
  2. <dependencyManagement>memungkinkan untuk dengan mudah meningkatkan / menurunkan ketergantungan berdasarkan kebutuhan, dalam skenario lain ini perlu dilakukan di setiap tingkat anak pom - konsistensi
  3. dependensi yang disediakan dalam <dependencies>tag selalu diimpor, sementara dependensi yang disediakan di <dependencyManagement>dalam parent pom akan diimpor hanya jika child pom memiliki entri masing-masing dalam <dependencies>tag -nya .
Amit Kaneria
sumber
17

Maaf saya sangat terlambat ke pesta.

Biarkan saya mencoba menjelaskan perbedaan menggunakan mvn dependency:treeperintah

Perhatikan contoh di bawah ini

POM Induk - Proyek Saya

<modules>
    <module>app</module>
    <module>data</module>
</modules>

<dependencies>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>19.0</version>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
    </dependencies>
</dependencyManagement>

POM anak - modul data

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
</dependencies>

POM Anak - modul aplikasi (tidak memiliki ketergantungan ekstra, sehingga membiarkan dependensi kosong)

 <dependencies>
</dependencies>

Saat menjalankan mvn dependency:treeperintah, kami mendapatkan hasil sebagai berikut

Scanning for projects...
------------------------------------------------------------------------
Reactor Build Order:

MyProject
app
data

------------------------------------------------------------------------
Building MyProject 1.0-SNAPSHOT
------------------------------------------------------------------------

--- maven-dependency-plugin:2.8:tree (default-cli) @ MyProject ---
com.iamvickyav:MyProject:pom:1.0-SNAPSHOT
\- com.google.guava:guava:jar:19.0:compile

------------------------------------------------------------------------
Building app 1.0-SNAPSHOT
------------------------------------------------------------------------

--- maven-dependency-plugin:2.8:tree (default-cli) @ app ---
com.iamvickyav:app:jar:1.0-SNAPSHOT
\- com.google.guava:guava:jar:19.0:compile

------------------------------------------------------------------------
Building data 1.0-SNAPSHOT
------------------------------------------------------------------------

--- maven-dependency-plugin:2.8:tree (default-cli) @ data ---
com.iamvickyav:data:jar:1.0-SNAPSHOT
+- org.apache.commons:commons-lang3:jar:3.9:compile
\- com.google.guava:guava:jar:19.0:compile

Google jambu biji terdaftar sebagai dependensi di setiap modul (termasuk orang tua), sedangkan apache commons terdaftar sebagai ketergantungan hanya dalam modul data (bahkan tidak dalam modul induk)

IamVickyAV
sumber
11

Jika dependensi didefinisikan dalam elemen dependensi Manajemen pom tingkat atas, proyek anak tidak harus secara eksplisit mencantumkan versi dependensi. jika proyek anak mendefinisikan suatu versi, itu akan menimpa versi yang terdaftar di bagian Manajemen ketergantungan POM tingkat atas. Artinya, versi dependensiManagement hanya digunakan ketika anak tidak mendeklarasikan versi secara langsung.

Mustafa Güven
sumber
1
Saya percaya pernyataan ini mungkin tidak benar. Dalam contoh Manajemen Ketergantungan Maven (# 2), mereka mengatakan bahwa dependensi yang ditentukan dalam pom induk dengan versi, akan menimpa versi yang ditentukan dalam pom anak: "Ketika maven dijalankan pada proyek B versi 1.0 dari artefak a, b, c , dan d akan digunakan terlepas dari versi yang ditentukan dalam pom mereka. "
devdanke
@devdanke Setidaknya, masalah Eclipse M2E peringatan: override versi berhasil ... untuk ... .
GeroldBroser mengembalikan Monica
4

Di POM induk, perbedaan utama antara <dependencies>dan <dependencyManagement>adalah:

Artefak yang ditentukan dalam <dependencies>bagian ini SELALU akan dimasukkan sebagai ketergantungan modul anak.

Artefak yang ditentukan dalam bagian, hanya akan dimasukkan dalam modul anak jika mereka juga ditentukan dalam bagian dari modul anak itu sendiri. Mengapa ada baiknya Anda bertanya? karena Anda menentukan versi dan / atau ruang lingkup di induknya, dan Anda dapat mengabaikannya ketika menentukan dependensi dalam POM anak. Ini dapat membantu Anda menggunakan versi terpadu untuk dependensi untuk modul anak, tanpa menentukan versi di setiap modul anak.

Yaver
sumber
4

Hanya dengan kata-kata saya sendiri, Anda parent-projectmembantu Anda memberikan 2 jenis dependensi:

  • dependensi implisit : semua dependensi yang ditentukan di <dependencies>bagian di Anda parent-projectdiwarisi oleh semuachild-projects
  • dependensi eksplisit : memungkinkan Anda untuk memilih, dependensi untuk diterapkan di child-projects. Dengan demikian, Anda menggunakan <dependencyManagement>bagian ini, untuk menyatakan semua dependensi yang akan Anda gunakan dalam perbedaan Anda child-projects. Yang paling penting adalah bahwa, di bagian ini, Anda mendefinisikan <version>sehingga Anda tidak perlu mendeklarasikannya lagi di child-project.

Pandangan <dependencyManagement>saya (koreksi saya jika saya salah) hanya berguna dengan membantu Anda memusatkan versi dependensi Anda. Ini seperti semacam fitur pembantu.

Harry Coder
sumber
1

Di Eclipse, ada satu fitur lagi di dependencyManagement. Ketika dependenciesdigunakan tanpa itu, dependensi yang tidak ditemukan terlihat dalam file pom. Jika dependencyManagementdigunakan, dependensi yang belum terpecahkan tetap tidak diperhatikan dalam file pom dan kesalahan hanya muncul di file java. (impor dan semacamnya ...)

Gangnus
sumber
1

Perbedaan antara keduanya paling baik dibawa dalam apa yang tampaknya definisi yang diperlukan dan cukup dari elemen Manajemen ketergantungan yang tersedia di dokumen situs web Maven:

manajemen ketergantungan

"Informasi dependensi default untuk proyek-proyek yang mewarisi dari ini. Ketergantungan pada bagian ini tidak segera diselesaikan. Alih-alih, ketika POM yang diturunkan dari ini menyatakan ketergantungan yang dijelaskan oleh groupId dan artifactId yang cocok, versi dan nilai-nilai lain dari bagian ini digunakan untuk dependensi itu jika belum ditentukan. " [ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]

Itu harus dibaca bersama dengan beberapa informasi lain yang tersedia di halaman yang berbeda:

“..Set minimal informasi untuk mencocokkan referensi dependensi dengan dependensi bagian Manajemen sebenarnya {groupId, artifactId, type, classifier}. Dalam banyak kasus, dependensi ini akan merujuk pada artefak jar tanpa classifier. Ini memungkinkan kita untuk menyingkat identitas yang diatur ke {groupId, artifactId}, karena default untuk bidang isinya adalah jar, dan classifier defaultnya adalah nol. ” [ https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]

Dengan demikian, semua sub-elemen (ruang lingkup, pengecualian dll,) dari elemen dependensi - selain groupId, artifactId, tipe, classifier, bukan hanya versi - tersedia untuk penguncian / default pada titik (dan dengan demikian diwarisi dari ada seterusnya) Anda menentukan dependensi dalam dependencyElement. Jika Anda telah menentukan ketergantungan dengan sub-elemen jenis dan klasifikasi (lihat halaman web yang dikutip pertama untuk memeriksa semua sub-elemen) masing-masing bukan jar dan bukan nol, Anda akan memerlukan {groupId, artifactId, classifier, type} untuk referensi (menyelesaikan) ketergantungan itu pada titik mana pun dalam warisan yang berasal dari elemen Manajemen dependensi. Lain, {groupId, artifactId} akan cukup jika Anda tidak bermaksud untuk menimpa default untuk classifier dan tipe (masing-masing jar dan null). Jadi default adalah kata kunci yang baik dalam definisi itu; sub-elemen (selain groupId),

Jadi, setiap elemen ketergantungan di luar dependensiManagement, baik sebagai referensi ke beberapa elemen dependensiManagement atau sebagai standalone segera diselesaikan (yaitu diinstal ke repositori lokal dan tersedia untuk classpath).

rps
sumber