<context:annotation-config>
ใช้เพื่อเปิดใช้งานคำอธิบายประกอบใน beans ที่ลงทะเบียนแล้วในบริบทแอปพลิเคชัน (ไม่ว่าจะถูกกำหนดด้วย XML หรือโดยการสแกนแพคเกจ)
<context:component-scan>
ยังสามารถทำสิ่งที่<context:annotation-config>
ทำได้ แต่<context:component-scan>
สแกนแพ็กเกจเพื่อค้นหาและลงทะเบียน beans ภายในบริบทของแอปพลิเคชัน
ฉันจะใช้ตัวอย่างเพื่อแสดงความแตกต่าง / ความคล้ายคลึงกัน
ให้เริ่มต้นด้วยการตั้งค่าพื้นฐานของสามถั่วชนิดA
, B
และC
ด้วยB
และถูกฉีดเข้าไปในC
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;
}
}
ด้วยการกำหนดค่า XML ต่อไปนี้:
<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>
การโหลดบริบทสร้างผลลัพธ์ต่อไปนี้:
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
ตกลงนี่คือผลลัพธ์ที่คาดหวัง แต่นี่คือ "แบบเก่า" ฤดูใบไม้ผลิ ตอนนี้เรามีคำอธิบายประกอบดังนั้นให้ใช้สิ่งเหล่านี้เพื่อทำให้ XML เป็นเรื่องง่ายขึ้น
ก่อนอื่นให้ autowire bbb
และccc
คุณสมบัติบน bean A
ดังนี้:
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;
}
}
สิ่งนี้ทำให้ฉันสามารถลบแถวต่อไปนี้ออกจาก XML:
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
XML ของฉันง่ายขึ้นในตอนนี้:
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
เมื่อฉันโหลดบริบทฉันจะได้ผลลัพธ์ต่อไปนี้:
creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf
ตกลงนี่ผิด! เกิดอะไรขึ้น? เหตุใดคุณสมบัติของฉันจึงไม่ได้รับการตอบรับอัตโนมัติ
คำอธิบายประกอบเป็นคุณสมบัติที่ดี แต่พวกเขาไม่ทำอะไรเลย พวกเขาแค่ใส่คำอธิบายประกอบ คุณต้องใช้เครื่องมือประมวลผลเพื่อค้นหาคำอธิบายประกอบและทำอะไรกับมัน
<context:annotation-config>
ช่วยเหลือ. สิ่งนี้จะเปิดใช้งานการดำเนินการสำหรับคำอธิบายประกอบที่พบใน beans ที่กำหนดไว้ในบริบทแอปพลิเคชันเดียวกันกับที่กำหนดไว้
ถ้าฉันเปลี่ยน XML เป็น:
<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
เมื่อฉันโหลดบริบทของแอปพลิเคชันฉันได้รับผลลัพธ์ที่ถูกต้อง:
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
ตกลงนี่เป็นสิ่งที่ดี แต่ฉันได้ลบสองแถวออกจาก XML และเพิ่มหนึ่งแถว นั่นไม่ใช่ความแตกต่างที่ใหญ่มาก แนวคิดที่มีคำอธิบายประกอบคือควรลบ XML
ดังนั้นให้ลบนิยาม XML และแทนที่ทั้งหมดด้วยคำอธิบายประกอบ:
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;
}
}
ในขณะที่อยู่ใน XML เราจะเก็บสิ่งนี้ไว้เท่านั้น:
<context:annotation-config />
เราโหลดบริบทและผลลัพธ์คือ ... ไม่มีอะไร ไม่มีการสร้างถั่วไม่มีการสร้างถั่วอัตโนมัติ ไม่มีอะไร!
นั่นเป็นเพราะอย่างที่ฉันได้กล่าวไว้ในย่อหน้าแรกการ<context:annotation-config />
ทำงานกับ bean ที่ลงทะเบียนภายในบริบทของแอปพลิเคชันเท่านั้น เนื่องจากฉันลบการกำหนดค่า XML สำหรับถั่วสามตัวไม่มีการสร้าง bean และ<context:annotation-config />
ไม่มี "เป้าหมาย" เพื่อทำงาน
แต่นั่นจะไม่เป็นปัญหา<context:component-scan>
ที่สามารถสแกนแพคเกจสำหรับ "เป้าหมาย" เพื่อทำงาน มาเปลี่ยนเนื้อหาของการกำหนดค่า XML เป็นรายการต่อไปนี้:
<context:component-scan base-package="com.xxx" />
เมื่อฉันโหลดบริบทฉันจะได้ผลลัพธ์ต่อไปนี้:
creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff
อืม ... มีบางอย่างขาดหายไป ทำไม?
ถ้าคุณมอง closelly ที่เรียนชั้นA
มีแพคเกจcom.yyy
แต่ฉันได้ระบุไว้ใน<context:component-scan>
การใช้แพคเกจcom.xxx
เพื่อให้สมบูรณ์พลาดของฉันนี้A
ระดับและมีเพียงหยิบขึ้นมาB
และC
ที่อยู่ในcom.xxx
แพคเกจ
ในการแก้ไขปัญหานี้ฉันเพิ่มแพ็คเกจอื่นด้วย:
<context:component-scan base-package="com.xxx,com.yyy" />
และตอนนี้เราได้รับผลลัพธ์ที่คาดหวัง:
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
และนั่นมัน! ตอนนี้คุณไม่มีคำจำกัดความของ XML อีกต่อไปคุณมีคำอธิบายประกอบ
เป็นตัวอย่างสุดท้ายทำให้เรียนข้อเขียนA
, B
และC
และการเพิ่มต่อไปนี้เพื่อ XML สิ่งที่เราจะได้รับหลังจากที่โหลดบริบท?
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
เรายังคงได้รับผลลัพธ์ที่ถูกต้อง:
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
แม้ว่า bean สำหรับคลาสA
ไม่ได้รับจากการสแกนเครื่องมือประมวลผลจะยังคงใช้<context:component-scan>
กับ bean ทั้งหมดที่ลงทะเบียนในบริบทของแอปพลิเคชันแม้จะA
ลงทะเบียนด้วยตนเองใน XML
แต่ถ้าเรามี XML ต่อไปนี้จะเราได้รับถั่วซ้ำเพราะเราได้ระบุไว้ทั้งสอง<context:annotation-config />
และ<context:component-scan>
?
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
ไม่ไม่ซ้ำเราได้ผลลัพธ์ที่คาดหวังอีกครั้ง:
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
นั่นเป็นเพราะแท็กทั้งสองลงทะเบียนเครื่องมือประมวลผลเดียวกัน ( <context:annotation-config />
สามารถละเว้นได้หาก<context:component-scan>
ระบุไว้) แต่สปริงจะดูแลการเรียกใช้เพียงครั้งเดียว
แม้ว่าคุณจะลงทะเบียนเครื่องมือประมวลผลด้วยตัวเองหลายครั้ง แต่สปริงก็ยังทำให้แน่ใจได้ว่าพวกเขาใช้เวทมนตร์เพียงครั้งเดียว XML นี้:
<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" />
จะยังคงสร้างผลลัพธ์ต่อไปนี้:
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
ตกลงว่าจะเคาะมันขึ้นมา
ฉันหวังว่าข้อมูลนี้มาพร้อมกับการตอบสนองจาก @Tomasz Nurkiewicz และ @Sean แพทริคฟลอยด์เป็นสิ่งที่คุณต้องเข้าใจวิธีการ
<context:annotation-config>
และ<context:component-scan>
การทำงาน