<context:annotation-config>
digunakan untuk mengaktifkan anotasi dalam kacang yang sudah terdaftar dalam konteks aplikasi (tidak peduli apakah itu didefinisikan dengan XML atau dengan pemindaian paket).
<context:component-scan>
juga dapat melakukan apa yang <context:annotation-config>
dilakukan tetapi <context:component-scan>
juga memindai paket untuk menemukan dan mendaftarkan kacang dalam konteks aplikasi.
Saya akan menggunakan beberapa contoh untuk menunjukkan perbedaan / kesamaan.
Mari kita mulai dengan pengaturan dasar tiga jenis kacang A
, B
dan C
, dengan B
dan C
disuntikkan A
.
package com.xxx;
public class B {
public B() {
System.out.println("creating bean B: " + this);
}
}
package com.xxx;
public class C {
public C() {
System.out.println("creating bean C: " + this);
}
}
package com.yyy;
import com.xxx.B;
import com.xxx.C;
public class A {
private B bbb;
private C ccc;
public A() {
System.out.println("creating bean A: " + this);
}
public void setBbb(B bbb) {
System.out.println("setting A.bbb with " + bbb);
this.bbb = bbb;
}
public void setCcc(C ccc) {
System.out.println("setting A.ccc with " + ccc);
this.ccc = ccc;
}
}
Dengan konfigurasi XML berikut:
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A">
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
</bean>
Memuat konteks menghasilkan output berikut:
creating bean B: com.xxx.B@c2ff5
creating bean C: com.xxx.C@1e8a1f6
creating bean A: com.yyy.A@1e152c5
setting A.bbb with com.xxx.B@c2ff5
setting A.ccc with com.xxx.C@1e8a1f6
OK, ini adalah output yang diharapkan. Tapi ini adalah "gaya lama" Musim Semi. Sekarang kita memiliki anotasi jadi mari kita gunakan itu untuk menyederhanakan XML.
Pertama, mari kita autowire bbb
dan ccc
properti pada kacang A
seperti:
package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import com.xxx.B;
import com.xxx.C;
public class A {
private B bbb;
private C ccc;
public A() {
System.out.println("creating bean A: " + this);
}
@Autowired
public void setBbb(B bbb) {
System.out.println("setting A.bbb with " + bbb);
this.bbb = bbb;
}
@Autowired
public void setCcc(C ccc) {
System.out.println("setting A.ccc with " + ccc);
this.ccc = ccc;
}
}
Ini memungkinkan saya untuk menghapus baris berikut dari XML:
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
XML saya sekarang disederhanakan menjadi ini:
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
Ketika saya memuat konteks saya mendapatkan output berikut:
creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf
OK, ini salah! Apa yang terjadi? Mengapa properti saya tidak disiarkan otomatis?
Ya, anotasi adalah fitur yang bagus tetapi dengan sendirinya mereka tidak melakukan apa pun. Mereka hanya membubuhi keterangan hal. Anda memerlukan alat pemrosesan untuk menemukan anotasi dan melakukan sesuatu dengannya.
<context:annotation-config>
untuk menyelamatkan. Ini mengaktifkan tindakan untuk anotasi yang ditemukan pada kacang yang didefinisikan dalam konteks aplikasi yang sama di mana itu sendiri didefinisikan.
Jika saya mengubah XML saya ke ini:
<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
ketika saya memuat konteks aplikasi saya mendapatkan hasil yang tepat:
creating bean B: com.xxx.B@15663a2
creating bean C: com.xxx.C@cd5f8b
creating bean A: com.yyy.A@157aa53
setting A.bbb with com.xxx.B@15663a2
setting A.ccc with com.xxx.C@cd5f8b
OK, ini bagus, tapi saya sudah menghapus dua baris dari XML dan menambahkan satu. Itu bukan perbedaan yang sangat besar. Gagasan dengan anotasi adalah bahwa seharusnya menghapus XML.
Jadi mari kita hapus definisi XML dan ganti semuanya dengan anotasi:
package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class B {
public B() {
System.out.println("creating bean B: " + this);
}
}
package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class C {
public C() {
System.out.println("creating bean C: " + this);
}
}
package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.xxx.B;
import com.xxx.C;
@Component
public class A {
private B bbb;
private C ccc;
public A() {
System.out.println("creating bean A: " + this);
}
@Autowired
public void setBbb(B bbb) {
System.out.println("setting A.bbb with " + bbb);
this.bbb = bbb;
}
@Autowired
public void setCcc(C ccc) {
System.out.println("setting A.ccc with " + ccc);
this.ccc = ccc;
}
}
Sementara di XML kami hanya menyimpan ini:
<context:annotation-config />
Kami memuat konteks dan hasilnya adalah ... Tidak ada. Tidak ada kacang yang dibuat, tidak ada kacang yang diotomatiskan. Tidak ada!
Itu karena, seperti yang saya katakan di paragraf pertama, <context:annotation-config />
hanya bekerja pada kacang yang terdaftar dalam konteks aplikasi. Karena saya menghapus konfigurasi XML untuk tiga kacang tidak ada kacang dibuat dan <context:annotation-config />
tidak memiliki "target" untuk bekerja.
Tapi itu tidak akan menjadi masalah <context:component-scan>
yang dapat memindai paket untuk "target" untuk dikerjakan. Mari kita ubah konten konfigurasi XML menjadi entri berikut:
<context:component-scan base-package="com.xxx" />
Ketika saya memuat konteks saya mendapatkan output berikut:
creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff
Hmmmm ... ada yang hilang. Mengapa?
Jika Anda melihat tertutup di kelas, kelas A
memiliki paket com.yyy
tetapi saya telah menentukan dalam <context:component-scan>
paket menggunakan com.xxx
sehingga ini benar-benar merindukan A
kelas saya dan hanya mengambil B
dan C
yang ada di com.xxx
paket.
Untuk memperbaikinya, saya menambahkan paket lain ini juga:
<context:component-scan base-package="com.xxx,com.yyy" />
dan sekarang kami mendapatkan hasil yang diharapkan:
creating bean B: com.xxx.B@cd5f8b
creating bean C: com.xxx.C@15ac3c9
creating bean A: com.yyy.A@ec4a87
setting A.bbb with com.xxx.B@cd5f8b
setting A.ccc with com.xxx.C@15ac3c9
Dan itu dia! Sekarang Anda tidak memiliki definisi XML lagi, Anda memiliki anotasi.
Sebagai contoh terakhir, menjaga kelas beranotasi A
, B
dan C
dan menambahkan yang berikut ke XML, apa yang akan kita dapatkan setelah memuat konteks?
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Kami masih mendapatkan hasil yang benar:
creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87
Bahkan jika kacang untuk kelas A
tidak diperoleh dengan pemindaian, alat pemrosesan masih diterapkan oleh <context:component-scan>
semua kacang yang terdaftar dalam konteks aplikasi, bahkan A
yang kacang itu secara manual terdaftar dalam XML.
Tetapi bagaimana jika kita memiliki XML berikut, apakah kita akan mendapatkan duplikat kacang karena kita telah menentukan keduanya <context:annotation-config />
dan <context:component-scan>
?
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Tidak, tidak ada duplikasi, Kami kembali mendapatkan hasil yang diharapkan:
creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87
Itu karena kedua tag mendaftarkan alat pemrosesan yang sama ( <context:annotation-config />
dapat dihilangkan jika <context:component-scan>
ditentukan) tetapi Spring hanya menjalankannya sekali.
Bahkan jika Anda mendaftarkan alat pemrosesan sendiri beberapa kali, Spring masih akan memastikan mereka melakukan sihir mereka hanya sekali; XML ini:
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
<bean id="bla" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla1" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla2" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla3" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
akan tetap menghasilkan hasil sebagai berikut:
creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@25d2b2
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87
OK, itu tentang mengetuknya.
Saya harap informasi ini bersama dengan tanggapan dari @Tomasz Nurkiewicz dan @Sean Patrick Floyd adalah semua yang Anda butuhkan untuk memahami bagaimana
<context:annotation-config>
dan <context:component-scan>
bekerja.