@Resource กับ @Autowired


380

ซึ่งคำอธิบายประกอบ@Resource ( jsr250 ) หรือ@Autowired (ฤดูใบไม้ผลิที่เฉพาะเจาะจง) ผมควรจะใช้ในการ DI?

ฉันใช้งานได้สำเร็จทั้งในอดีต@Resource(name="blah")และ@Autowired @Qualifier("blah")

สัญชาตญาณของฉันคือติดกับ@Resourceแท็กเนื่องจากมันได้รับการยอมรับจากคน jsr
ใครมีความคิดที่แข็งแกร่งในเรื่องนี้?


FYI - ฉันลบ 'อัปเดต' แล้วคำถามนั้นควรถูกถามแยกต่างหาก ตามความคิดเห็นที่ถูกปฏิเสธ "การแก้ไขนี้เบี่ยงเบนไปจากความตั้งใจดั้งเดิมของการโพสต์แม้แต่การแก้ไขที่ต้องทำการเปลี่ยนแปลงอย่างรุนแรงควรพยายามรักษาเป้าหมายของเจ้าของโพสต์"
mlo55

คำตอบ:


194

ในฤดูใบไม้ผลิ pre-3.0 มันไม่สำคัญว่าอันไหน

ในฤดูใบไม้ผลิ 3.0 มีการสนับสนุนมาตรฐาน ( JSR-330 ) คำอธิบายประกอบ@javax.inject.Inject- @Qualifierการใช้งานได้ด้วยการรวมกันของ โปรดทราบว่าฤดูใบไม้ผลิในขณะนี้ยังรองรับการเพิ่ม@javax.inject.Qualifierคำอธิบายประกอบ:

@Qualifier
@Retention(RUNTIME)
public @interface YourQualifier {}

ดังนั้นคุณสามารถมี

<bean class="com.pkg.SomeBean">
   <qualifier type="YourQualifier"/>
</bean>

หรือ

@YourQualifier
@Component
public class SomeBean implements Foo { .. }

แล้ว:

@Inject @YourQualifier private Foo foo;

สิ่งนี้ทำให้การใช้ชื่อสตริงน้อยลงซึ่งสามารถสะกดผิดและยากต่อการดูแลรักษา


สำหรับคำถามเดิม: ทั้งสองโดยไม่ต้องระบุคุณลักษณะใด ๆ ของคำอธิบายประกอบทำการฉีดตามประเภท ความแตกต่างคือ:

  • @Resource อนุญาตให้คุณระบุชื่อของถั่วที่ฉีด
  • @Autowired อนุญาตให้คุณทำเครื่องหมายว่าไม่บังคับ

นี่อาจดูเหมือนคำถามงี่เง่า แต่เมื่อคุณใช้การฉีดแบบนี้คุณจำเป็นต้องมีเซทเทอร์เตอร์สาธารณะfooหรือคอนสตรัคเตอร์SomeBeanร่วมกับFooพารามิเตอร์หรือไม่
Snekse

@Snekse - ได้รับคำตอบของฉัน: stackoverflow.com/questions/3536674/…
Snekse

Nope คุณไม่ต้องการสิ่งใดเลย แค่ลงสนาม (ฤดูใบไม้ผลิเติมผ่านการสะท้อนแสง)
Bozho

@Bozho คำตอบนี้จริง ๆ แล้วไม่ได้แสดงความแตกต่างระหว่าง@Resourceและ@Autowiredคำตอบที่แท้จริงคือคำตอบที่ @Ichthyo ฉันคิดว่าต้องอัปเดต
Boris Treukhov

1
ใช่. ในความเป็นจริงบางครั้งฉันตอบคำถามด้วยการเสนอทางเลือกที่ดีกว่าให้กับแนวทาง แต่ฉันได้รวมคำตอบของคำถามเดิมไว้ด้านล่างเพื่อความสมบูรณ์
Bozho

509

ทั้ง@Autowired(หรือ@Inject) และ@Resourceทำงานได้ดีพอ ๆ กัน แต่มีความแตกต่างทางแนวคิดหรือความแตกต่างในความหมาย

  • @Resourceวิธีการรับฉันทรัพยากรที่รู้จักกันในชื่อ ชื่อถูกแยกออกจากชื่อของ setter หรือฟิลด์ที่มีหมายเหตุประกอบหรือนำมาจากชื่อพารามิเตอร์
  • @Injectหรือ@Autowiredพยายามที่จะสายในองค์ประกอบอื่น ๆ ที่เหมาะสมตามประเภท

ดังนั้นโดยพื้นฐานแล้วสิ่งเหล่านี้เป็นแนวคิดที่แตกต่างกันสองประการ น่าเสียดายที่ Spring-Implementation ของ@Resourceมี fallback ในตัวซึ่งเริ่มทำงานเมื่อการแก้ปัญหาด้วยชื่อล้มเหลว ในกรณีนี้มันกลับไปที่@Autowired-kind resolution by-type ในขณะที่ทางเลือกนี้สะดวก แต่ IMHO ทำให้เกิดความสับสนอย่างมากเนื่องจากผู้คนไม่ทราบถึงความแตกต่างทางแนวคิดและมีแนวโน้มที่จะใช้@Resourceสำหรับการบันทึกอัตโนมัติตามประเภท


81
ใช่นี่คือสิ่งที่ควรได้รับคำตอบ ตัวอย่างเช่นหากคุณมี@Resourceฟิลด์ที่มีคำอธิบายประกอบและชื่อฟิลด์ตรงกับ id ของ bean ในคอนเทนเนอร์ดังนั้น Spring จะส่ง org.springframework.beans.factory.BeanNotOfRequiredTypeExceptionหากประเภทของพวกเขาแตกต่างกัน - นี่เป็นเพราะถั่วถูกจับคู่ครั้งแรกโดยชื่อใน@Resourceคำอธิบายประกอบไม่ใช่ตามประเภท แต่ถ้าชื่อของคุณสมบัติไม่ตรงกับชื่อของถั่ว Spring จะทำการเชื่อมต่อตามประเภท
Boris Treukhov

คุณสามารถอ้างอิงโพสต์อื่นที่บอกถึงความแตกต่างระหว่างสองสิ่งนี้เมื่อคุณพยายามใช้ MAP อย่างง่าย stackoverflow.com/questions/13913752/…
Anver Sadhat

4
+1 สำหรับการตอบคำถามจริง ๆ ไม่ใช่เพียงแค่แนะนำ "วิธีปฏิบัติที่ดีที่สุด" ที่แตกต่างอย่างสิ้นเชิงตามที่ได้รับการยอมรับ ฉันยังพบโพสต์บล็อกนี้ซึ่งแสดงผลลัพธ์ของสถานการณ์ทั่วไปหลายอย่างที่มีรูปแบบคำอธิบายประกอบทั้งสามแบบมีประโยชน์: blogs.sourceallies.com/2011/08/…
Jules

1
สำหรับผู้อ่านโปรดหาบทสรุปของบทความที่ชี้โดย @Jules ที่นี่: stackoverflow.com/a/23887596/363573
Stephan

3
สิ่งหนึ่งที่เกี่ยวข้องกับสิ่งนี้: เมื่อคุณต้องการฉีดแผนที่ / รายการถั่ว@Autowireไม่สามารถและไม่ทำงาน คุณจะต้องใช้@Resourceในกรณีนั้น
Ricardo van den Broek

76

ความแตกต่างหลักคือ@Autowiredเป็นคำอธิบายประกอบในฤดูใบไม้ผลิ ในขณะ@Resourceที่ JSR-250 ระบุไว้ในขณะที่คุณชี้ให้เห็นตัวเอง ดังนั้นหลังจึงเป็นส่วนหนึ่งของ Java ในขณะที่ก่อนหน้านี้มีเฉพาะฤดูใบไม้ผลิ

ดังนั้นคุณมีความถูกต้องในการแนะนำว่าในแง่หนึ่ง ฉันพบคนใช้@Autowiredด้วย@Qualifierเพราะมันมีประสิทธิภาพมากขึ้น การย้ายจากเฟรมเวิร์กไปสู่เฟรมอื่นนั้นถือว่าไม่น่าเป็นไปได้มากหากไม่ใช่ตำนานโดยเฉพาะในกรณีของ Spring


7
1 เพราะ@Autowiredมี@Qualifierจริงๆคือมีประสิทธิภาพมากขึ้นกว่ามาตรฐาน JSR @Resourceคำอธิบายประกอบ (คิดว่าการอ้างอิงตัวเลือกสำหรับอินสแตนซ์ที่มี@Autowired(required=false). คุณไม่สามารถทำเช่นนั้นด้วย@Resource)
สเตฟาน Haberl

70

ฉันต้องการเน้นหนึ่งความคิดเห็นจาก@Julesในคำตอบของคำถามนี้ ความคิดเห็นที่นำการเชื่อมโยงที่มีประโยชน์: ฤดูใบไม้ผลิฉีดกับ @Resource, @Autowired และ @Inject ฉันขอแนะนำให้คุณอ่านทั้งหมด แต่นี่เป็นบทสรุปโดยย่อเกี่ยวกับประโยชน์:

หมายเหตุประกอบเลือกการใช้งานที่ถูกต้องอย่างไร

@Autowired และ @Inject

  1. จับคู่ตามประเภท
  2. จำกัด ตามคุณสมบัติ
  3. ตรงกับชื่อ

@Resource

  1. ตรงกับชื่อ
  2. จับคู่ตามประเภท
  3. จำกัด โดย Qualifiers (ละเว้นหากพบชื่อที่ตรงกัน)

ฉันควรใช้คำอธิบายประกอบ (หรือรวมกัน) ใดในการฉีดถั่ว

  1. ตั้งชื่อองค์ประกอบของคุณอย่างชัดเจน [@Component ("beanName")]

  2. ใช้@Resourceกับnameแอตทริบิวต์ [@Resource (name = "beanName")]

ทำไมฉันจึงไม่ควรใช้@Qualifier?

หลีกเลี่ยง@Qualifierคำอธิบายประกอบเว้นแต่ว่าคุณต้องการสร้างรายการถั่วที่คล้ายกัน ตัวอย่างเช่นคุณอาจต้องการทำเครื่องหมายชุดของกฎด้วย@Qualifierคำอธิบายประกอบที่เฉพาะเจาะจง วิธีนี้ทำให้ง่ายต่อการแทรกกลุ่มของคลาสของกฎลงในรายการที่สามารถใช้สำหรับการประมวลผลข้อมูล

การฉีดถั่วทำให้โปรแกรมของฉันช้าลงหรือไม่?

[context:component-scan base-package="com.sourceallies.person"]แพคเกจเฉพาะสแกนหาส่วนประกอบ ขณะนี้จะส่งผลให้component-scanการกำหนดค่ามากขึ้นมันช่วยลดโอกาสที่คุณจะเพิ่มองค์ประกอบที่ไม่จำเป็นในบริบทฤดูใบไม้ผลิของคุณ


การอ้างอิง: Spring Injection ด้วย @Resource, @Autowired และ @Inject


39

นี่คือสิ่งที่ฉันได้รับจากคู่มืออ้างอิงของSpring 3.0.x : -

ปลาย

หากคุณตั้งใจจะแสดงการฉีดโดยใช้คำอธิบายประกอบโดยชื่ออย่าใช้ @Autowired เป็นหลักแม้ว่าจะมีความสามารถทางเทคนิคในการอ้างอิงชื่อถั่วผ่านค่า @Qualifier ให้ใช้คำอธิบายประกอบ JSR-250 @Resource แทนซึ่งถูกกำหนดแบบ semantically เพื่อระบุองค์ประกอบเป้าหมายที่เฉพาะเจาะจงด้วยชื่อที่ไม่ซ้ำกันโดยที่ประเภทที่ประกาศไม่เกี่ยวข้องกับกระบวนการจับคู่

เนื่องจากผลลัพธ์เฉพาะของความแตกต่างทางความหมายนี้ถั่วที่กำหนดไว้เป็นคอลเล็กชันหรือชนิดของแผนที่ไม่สามารถฉีดผ่าน @Autowired เนื่องจากการจับคู่ประเภทนั้นใช้ไม่ได้กับพวกเขา ใช้ @Resource สำหรับ beans ดังกล่าวอ้างอิงถึงคอลเล็กชันหรือ map ที่ระบุเฉพาะด้วยชื่อเฉพาะ

@Autowired นำไปใช้กับเขตข้อมูลคอนสตรัคเตอร์และวิธีการหลายอาร์กิวเมนต์ช่วยให้การแคบลงผ่านคำอธิบายประกอบ qualifier ที่ระดับพารามิเตอร์ ในทางตรงกันข้าม @Resource ได้รับการสนับสนุนเฉพาะสำหรับเขตข้อมูลและวิธี setter คุณสมบัติถั่วด้วยอาร์กิวเมนต์เดียว ดังนั้นให้ติดกับตัวระบุหากเป้าหมายการฉีดของคุณเป็นตัวสร้างหรือวิธีการหลายอาร์กิวเมนต์


สำหรับรุ่นปัจจุบันดูdocs.spring.io/spring/docs/current/spring-framework-reference/… (เคล็ดลับได้รับการอัปเดตแล้ว)
Lu55

28

@Autowired + @Qualifier จะทำงานเฉพาะกับฤดูใบไม้ผลิ DI หากคุณต้องการใช้ DI อื่นในอนาคต @Resource เป็นตัวเลือกที่ดี

ความแตกต่างอื่น ๆ ที่ฉันพบว่ามีความสำคัญมากคือ @Qualifier ไม่รองรับการเดินสายถั่วแบบไดนามิกเนื่องจาก @Qualifier ไม่รองรับตัวยึดตำแหน่งในขณะที่ @Resource ทำงานได้ดีมาก

ตัวอย่างเช่น: หากคุณมีอินเตอร์เฟสที่มีการใช้งานหลายอย่างเช่นนี้

interface parent {

}
@Service("actualService")
class ActualService implements parent{

}
@Service("stubbedService")
class SubbedService implements parent{

}

ด้วย @Autowired & @Qualifier คุณจำเป็นต้องตั้งค่าการใช้งานลูกที่เฉพาะเจาะจงเช่น

@Autowired
@Qualifier("actualService") or 
@Qualifier("stubbedService") 
Parent object;

ซึ่งไม่ได้ให้ตัวยึดตำแหน่งในขณะที่ @Resource คุณสามารถใส่ตัวยึดตำแหน่งและใช้ไฟล์คุณสมบัติเพื่อฉีดการใช้งานลูกที่เฉพาะเจาะจงเช่น

@Resource(name="${service.name}")
Parent object;  

โดยที่ service.name ตั้งอยู่ในไฟล์คุณสมบัติเป็น

#service.name=actualService
 service.name=stubbedService

หวังว่าจะช่วยให้ใครบางคน :)


16

ทั้งสองอย่างนั้นดีพอ ๆ กัน ข้อดีของการใช้ทรัพยากรในอนาคตถ้าคุณต้องการกรอบ DI อื่นนอกเหนือจากสปริงการเปลี่ยนรหัสของคุณจะง่ายกว่ามาก การใช้รหัสอัตโนมัติของคุณควบคู่กับสปริง DI อย่างแน่นหนา


17
ไม่เคยจะเกิดขึ้น และแม้ว่าจะเป็นเช่นนั้นการทำค้นหา / แทนที่ชื่อคำอธิบายประกอบจะเป็นปัญหาของคุณน้อยที่สุด
Daniel Alexiuc

13

เมื่อคุณวิเคราะห์ช่วงวิกฤตจากคลาสพื้นฐานของคำอธิบายประกอบทั้งสองนี้คุณจะตระหนักถึงความแตกต่างดังต่อไปนี้

@Autowiredใช้AutowiredAnnotationBeanPostProcessor ในการฉีดพึ่งพา
@Resourceใช้CommonAnnotationBeanPostProcessorในการฉีดพึ่งพา

แม้ว่าพวกเขาจะใช้คลาสโพสต์โพสต์โพรเซสเซอร์ต่างกัน แต่พวกมันก็เกือบจะเหมือนกัน ความแตกต่างสำคัญอยู่ที่เส้นทางการปฏิบัติซึ่งฉันได้เน้นไว้ด้านล่าง

@Autowired / @Inject

1. จับคู่ตามประเภท
2. จำกัด ตามตัว
ระบุ 3. จับคู่ตามชื่อ

@Resource

1. จับคู่ตามชื่อ
2. จับคู่ตามประเภท
3. ขีด จำกัด โดยตัวระบุ (ละเว้นหากตรงกับชื่อ)


6

กับ @Resourceคุณสามารถทำการฉีดด้วยตนเองของถั่วคุณอาจจำเป็นต้องเรียกใช้ตรรกะเพิ่มเติมทั้งหมดที่เพิ่มโดยตัวประมวลผลโพสต์ของถั่วเช่นทรานแซคชันหรือสิ่งที่เกี่ยวข้องกับความปลอดภัย

ด้วย Spring 4.3+ @Autowiredยังสามารถทำสิ่งนี้ได้


2

@Resourceมักใช้โดยวัตถุระดับสูงที่กำหนดผ่าน JNDI @Autowiredหรือ@Injectจะใช้โดยถั่วทั่วไป

เท่าที่ฉันรู้มันไม่ได้เป็นสเปคหรือแม้แต่การประชุม มันเป็นมากกว่าวิธีตรรกะรหัสมาตรฐานจะใช้คำอธิบายประกอบเหล่านี้


0

ตามหมายเหตุที่นี่: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContextและSpringBeanAutowiringSupport.processInjectionBasedOnServletContext ไม่ทำงานกับ@Resource คำอธิบายประกอบ ดังนั้นจึงมีความแตกต่าง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.