Java EE 6 @ javax.annotation.ManagedBean vs. @ javax.inject.Named เทียบกับ @ javax.faces.ManagedBean


107

ฉันรู้สึกว่ามีความยุ่งเล็กน้อยในข้อมูลจำเพาะ Java EE 6 คำอธิบายประกอบมีหลายชุด

เรามีjavax.ejbคำอธิบายประกอบเช่น@Statefulและ@Statelessสำหรับการสร้าง EJB

นอกจากนี้ยังมี@javax.annotation.ManagedBeanการสร้างถั่วจัดการ

มีคำอธิบายประกอบในjavax.enterprise.contextlike @SessionScopedและ@RequestScoped.

นอกจากนี้ยังมี@ManagedBeanและ@SessionScoped/ @RequestScopedคำอธิบายประกอบในjavax.faces.beanแพ็คเกจอีกด้วย

และเพื่อให้เหตุการณ์ต่างๆซับซ้อนขึ้นเรามีแพ็คเกจjavax.injectพร้อม@Namedคำอธิบายประกอบ

ใครช่วยอธิบายว่าพวกเขาเกี่ยวข้องกันอย่างไร

ฉันสามารถใช้@EJB, @Injectหรือ@ManagedProperyการฉีดถั่วอื่น ๆ ?


ดูเพิ่มเติม: stackoverflow.com/questions/4684112/…
Arjan Tijms

คำตอบ:


194

ก่อนอื่นให้ฉันอธิบายบางอย่าง:

คำจำกัดความของถั่วที่มีการจัดการ : โดยทั่วไปถั่วที่ได้รับการจัดการเป็นวัตถุที่วงจรชีวิตของมัน (การก่อสร้างการทำลาย ฯลฯ ) ถูกจัดการโดยคอนเทนเนอร์

ใน Java ee เรามีคอนเทนเนอร์มากมายที่จัดการวงจรชีวิตของอ็อบเจ็กต์เช่น JSF container, EJB container, CDI container, Servlet container เป็นต้น

คอนเทนเนอร์เหล่านี้ทั้งหมดทำงานแบบอิสระโดยจะบูตในการเริ่มต้นแอ็พพลิเคชันเซิร์ฟเวอร์และสแกนคลาสของอาร์ติแฟกต์ทั้งหมดรวมถึง jar, ejb-jar, war และ ear files ในเวลาการปรับใช้และรวบรวมและจัดเก็บข้อมูลเมตาบางอย่างเกี่ยวกับพวกเขาจากนั้นเมื่อคุณต้องการอ็อบเจ็กต์ ของคลาสที่รันไทม์พวกเขาจะให้อินสแตนซ์ของคลาสเหล่านั้นแก่คุณและหลังจากจบงานแล้วพวกเขาจะทำลายมัน

ดังนั้นเราสามารถพูดได้ว่าเรามี:

  • JSF จัดการถั่ว
  • ถั่วจัดการ CDI
  • ถั่วจัดการ EJB
  • และแม้แต่ Servlets ก็เป็นถั่วที่ได้รับการจัดการเพราะมันถูกสร้างอินสแตนซ์และทำลายโดยคอนเทนเนอร์ซึ่งเป็นคอนเทนเนอร์ของ servlet

ดังนั้นเมื่อคุณเห็นคำ Managed Bean คุณควรถามเกี่ยวกับบริบทหรือประเภทของมัน (JSF, CDI, EJB ฯลฯ )

จากนั้นคุณอาจถามว่าทำไมเราถึงมีคอนเทนเนอร์เหล่านี้มากมาย: พวก AFAIK, Java EE ต้องการมีเฟรมเวิร์กการฉีดพึ่งพา แต่ไม่สามารถรวบรวมข้อกำหนดทั้งหมดในข้อกำหนดเดียวได้เนื่องจากไม่สามารถคาดเดาข้อกำหนดในอนาคตได้และพวกเขาสร้าง EJB 1.0 ขึ้นมา 2.0 และ 3.0 และตอนนี้ 3.1 แต่เป้าหมายของ EJB เป็นเพียงข้อกำหนดบางอย่าง (ธุรกรรมโมเดลส่วนประกอบแบบกระจาย ฯลฯ )

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

หลังจากนั้น Gavin King และคนดีคนอื่น ๆ ;) สร้าง CDI ซึ่งเป็นคอนเทนเนอร์ DI ที่โตเต็มที่ที่สุดเท่าที่ฉันเคยเห็นมา CDI (ได้รับแรงบันดาลใจจาก Seam2, Guice และ Spring) ถูกสร้างขึ้นเพื่อเติมเต็มช่องว่างระหว่าง JSF และ EJB และสิ่งที่มีประโยชน์อื่น ๆ อีกมากมายเช่นการฉีดโพโจวิธีการของผู้ผลิตเครื่องสกัดกั้นผู้ตกแต่ง SPI การรวมความยืดหยุ่นมาก ฯลฯ และยังสามารถทำได้ ถั่วที่จัดการของ EJB และ JSF กำลังทำอะไรอยู่เราสามารถมีคอนเทนเนอร์ DI ที่โตเต็มที่และทรงพลังเพียงอันเดียว แต่ด้วยความเข้ากันได้ที่ล้าหลังและเหตุผลทางการเมืองพวก Java EE ต้องการรักษาไว้ !!!

คุณจะพบความแตกต่างและกรณีการใช้งานสำหรับแต่ละประเภทเหล่านี้ได้ที่นี่:

JSF Managed Beans, CDI Beans และ EJBs

JSF ได้รับการพัฒนาในขั้นต้นด้วย bean ที่มีการจัดการและกลไกการฉีดพึ่งพาซึ่งได้รับการปรับปรุงสำหรับ JSF 2.0 เพื่อรวมถั่วที่ใช้คำอธิบายประกอบ เมื่อ CDI เปิดตัวพร้อมกับ Java EE 6 ถือได้ว่าเป็นเฟรมเวิร์กถั่วที่มีการจัดการสำหรับแพลตฟอร์มนั้นและแน่นอนว่า EJB ล้าสมัยพวกเขาทั้งหมดที่มีมานานกว่าทศวรรษ

ปัญหาแน่นอนคือการรู้ว่าควรใช้อันไหนและใช้เมื่อใด

เริ่มต้นด้วยถั่วที่จัดการโดย JSF ที่ง่ายที่สุด

ถั่วจัดการ JSF

กล่าวโดยย่ออย่าใช้หากคุณกำลังพัฒนาสำหรับ Java EE 6 และใช้ CDI พวกเขามีกลไกง่ายๆสำหรับการฉีดพึ่งพาและกำหนดถั่วสำรองสำหรับหน้าเว็บ แต่มีประสิทธิภาพน้อยกว่าถั่ว CDI

สามารถกำหนดได้โดยใช้@javax.faces.bean.ManagedBeanคำอธิบายประกอบซึ่งใช้พารามิเตอร์ชื่อทางเลือก ชื่อนี้สามารถใช้เพื่ออ้างอิง bean จากเพจ JSF

ขอบเขตสามารถใช้กับ bean ได้โดยใช้หนึ่งในขอบเขตที่แตกต่างกันที่กำหนดไว้ในjavax.faces.beanแพ็คเกจซึ่งรวมถึงคำขอเซสชันแอปพลิเคชันมุมมองและขอบเขตที่กำหนดเอง

@ManagedBean(name="someBean")
@RequestScoped
public class SomeBean {
    ....
    ....
}

ถั่ว JSF ไม่สามารถผสมกับถั่วชนิดอื่นได้หากไม่มีการเข้ารหัสด้วยตนเอง

ถั่ว CDI

CDI คือเฟรมเวิร์กการจัดการ bean และการพึ่งพาการฉีดที่เผยแพร่โดยเป็นส่วนหนึ่งของ Java EE 6 และรวมถึงสิ่งอำนวยความสะดวก bean ที่มีการจัดการที่สมบูรณ์และครอบคลุม ถั่ว CDI มีความก้าวหน้าและยืดหยุ่นมากกว่าถั่วที่จัดการโดย JSF พวกเขาสามารถใช้ประโยชน์จากตัวสกัดกั้นขอบเขตการสนทนาเหตุการณ์ประเภทการฉีดแบบปลอดภัยมัณฑนากรแบบแผนและวิธีการผลิต

ในการปรับใช้ CDI beans คุณต้องวางไฟล์ชื่อ beans.xml ในโฟลเดอร์ META-INF บน classpath เมื่อคุณทำเช่นนี้ทุก bean ในแพ็คเกจจะกลายเป็น CDI bean มีคุณสมบัติมากมายใน CDI ซึ่งมีมากเกินไปที่จะกล่าวถึงที่นี่ แต่เพื่อเป็นการอ้างอิงอย่างรวดเร็วสำหรับคุณลักษณะที่คล้าย JSF คุณสามารถกำหนดขอบเขตของ CDI bean โดยใช้ขอบเขตใดขอบเขตหนึ่งที่กำหนดไว้ในjavax.enterprise.contextแพ็คเกจ (ได้แก่ คำขอการสนทนา ขอบเขตเซสชันและแอปพลิเคชัน) หากคุณต้องการใช้ CDI bean จากเพจ JSF คุณสามารถตั้งชื่อโดยใช้javax.inject.Namedคำอธิบายประกอบ ในการฉีดถั่วลงในถั่วอื่นคุณต้องใส่คำอธิบายประกอบฟิลด์ด้วยjavax.inject.Injectคำอธิบายประกอบ

@Named("someBean")
@RequestScoped
public class SomeBean {

    @Inject
    private SomeService someService;
}

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

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

CDI ยังรองรับผู้สกัดกั้นเหตุการณ์ขอบเขตการสนทนาใหม่และคุณสมบัติอื่น ๆ อีกมากมายซึ่งทำให้เป็นตัวเลือกที่ดีกว่าถั่วที่จัดการโดย JSF

EJB

EJBs มีเมล็ด CDI ก่อนหน้านี้และอยู่ในบางวันคล้ายกับถั่ว CDI และในลักษณะอื่น ๆ ที่แตกต่างกันมาก โดยพื้นฐานแล้วความแตกต่างระหว่างถั่ว CDI และ EJB คือ EJB คือ:

  • การทำธุรกรรม
  • ระยะไกลหรือในพื้นที่
  • สามารถส่งเมล็ดถั่วที่มีสถานะว่างได้โดยไม่ต้องใช้ทรัพยากร
  • สามารถใช้ตัวจับเวลาได้
  • สามารถเป็นแบบอะซิงโครนัสได้

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

การกำหนด EJB นั้นง่ายมากเพียงแค่เพิ่ม a javax.ejb.Statelessหรือjavax.ejb.Statefulคำอธิบายประกอบลงในคลาส

@Stateless
public class BookingService {

  public String makeReservation(Item Item, Customer customer) {
    ...
    ...
  }
}

ถั่วไร้สัญชาติต้องมีขอบเขตที่พึ่งพาในขณะที่ถั่วเซสชันที่มีสถานะสามารถมีขอบเขตใดก็ได้ โดยค่าเริ่มต้นจะเป็นธุรกรรม แต่คุณสามารถใช้คำอธิบายประกอบแอตทริบิวต์ธุรกรรมได้

ในขณะที่ EJB และถั่ว CDI มีความแตกต่างกันมากในแง่ของคุณสมบัติการเขียนโค้ดเพื่อรวมเข้าด้วยกันนั้นคล้ายกันมากเนื่องจากสามารถฉีดถั่ว CDI ลงใน EJBs และ EJBs สามารถฉีดเข้าไปในเมล็ด CDI ได้ ไม่จำเป็นต้องสร้างความแตกต่างใด ๆ เมื่อฉีดเข้าไปในอีกอัน อีกครั้งขอบเขตที่แตกต่างกันได้รับการจัดการโดย CDI ผ่านการใช้พร็อกซี ข้อยกเว้นประการหนึ่งคือ CDI ไม่สนับสนุนการฉีด EJB ระยะไกล แต่สามารถใช้งานได้โดยการเขียนวิธีการผลิตอย่างง่ายสำหรับมัน

javax.inject.Namedคำอธิบายประกอบเช่นเดียวกับบ่นใด ๆ ที่สามารถนำมาใช้ใน EJB เพื่อให้ตรงกับมันไปยังจุดฉีด

ควรใช้ถั่วเมื่อใด

คุณรู้ได้อย่างไรว่าเมื่อใดควรใช้ถั่วชนิดใด? เรียบง่าย

อย่าใช้ถั่วที่มีการจัดการ JSF เว้นแต่คุณจะทำงานในคอนเทนเนอร์ servlet และไม่ต้องการลองให้ CDI ทำงานใน Tomcat (แม้ว่าจะมีแม่แบบ Maven อยู่บ้างก็ตามดังนั้นจึงไม่มีข้อแก้ตัว)

โดยทั่วไปคุณควรใช้ถั่ว CDI เว้นแต่คุณต้องการฟังก์ชันขั้นสูงที่มีอยู่ใน EJB เช่นฟังก์ชันการทำธุรกรรม คุณสามารถเขียน interceptor ของคุณเองเพื่อทำธุรกรรม CDI beans ได้ แต่สำหรับตอนนี้การใช้ EJB จะง่ายกว่าจนกว่า CDI จะได้รับ CDI beans ที่ทำธุรกรรมซึ่งอยู่ใกล้ ๆ หากคุณติดอยู่ในคอนเทนเนอร์ servlet และกำลังใช้ CDI ธุรกรรมที่เขียนด้วยมือหรือตัวสกัดกั้นธุรกรรมของคุณเองจะเป็นทางเลือกเดียวที่ไม่มี EJB

หากคุณจำเป็นต้องใช้@ViewScopedใน CDI คุณควร

  • ใช้ตะเข็บหน้าหรือMyFaces CODIโมดูลเพียงเพิ่มหนึ่งในนั้นใน classpath ของคุณและ@ViewScopedจะทำงานใน CDI MyFaces CODI รองรับ @ViewScoped ที่มั่นคงยิ่งขึ้น
  • ใช้ MyFaces CODI @ViewAccessScopedซึ่งเป็นส่วนขยายที่เขียนไว้ด้านบนของ CDI โดย Apache เพียงดาวน์โหลดและใช้@ViewAccessScopedคำอธิบายประกอบแทน@ViewScopedคำอธิบายประกอบแทน
  • ใช้ CDI @ConversationScopedและทำให้ใช้งานได้นาน ดูข้อมูลเพิ่มเติมได้ที่นี่ได้ที่นี่
  • ใช้Omnifaces @ViewScoped คำอธิบายประกอบ

บางส่วนเบอร์เบิ้นจากที่นี่


3
นี่มันเยี่ยมมาก! ขอบคุณ! เพื่อให้สมบูรณ์เพียงแค่บอกวิธีการฉีด CDI หรือ EJB bean ลงใน JSF bean เป็น@ManagedProperty("#{someBean})"วิธีที่เหมาะสมหรือไม่?
Piotr Gwiazda

2
ไม่! มันจะไม่ทำงาน เพียงแค่เปลี่ยน jsf ที่มีการจัดการของคุณเป็นถั่วที่จัดการ CDI โดยใส่คำอธิบายประกอบโดยใช้@Namedและ@javax.enterprise.context.RequestScopedและใช้การฉีด CDI โดยใช้คำอธิบายประกอบ @Inject อย่าใช้ถั่วที่มีการจัดการ jsf ถ้าคุณไม่จำเป็นต้องทำ;)
Mehdi

3
> พวก JEE อยากเก็บไว้ !!! - มันละเอียดกว่านั้นเล็กน้อย CDI เสร็จสิ้นค่อนข้างช้าในรอบ Java EE 6 และทั้ง JSF 2 และ JAX-RS ได้ทำไปแล้ว พวกเขาได้รับการปรับปรุงการตอบสนอง แนะนำโรงงานถั่วที่มีการจัดการของตนเองแล้ว หาก CDI มีให้บริการก่อนหน้านี้เล็กน้อยสิ่งต่างๆอาจดูแตกต่างไป ใน Java EE 7 JSF จะใช้ CDI และ javax.faces.bean จะเลิกใช้งานในที่สุด (การเลิกใช้งานเป็นกระบวนการที่ช้าใน Java EE ซึ่งมีทั้งดีและไม่ดี)
อรัญติฌมส

3
เมื่อคุณพูดว่า: ในการปรับใช้ถั่ว CDI คุณต้องวางไฟล์ชื่อ beans.xml ในโฟลเดอร์ META-INF บน classpath เมื่อคุณทำเช่นนี้ทุก bean ในแพ็คเกจจะกลายเป็น CDI bean คุณหมายถึงถั่วทุกเมล็ดยังกลายเป็น CDI bean นอกเหนือจากที่มันเป็น? จะเกิดอะไรขึ้นถ้าฉันมี JSF ManagedBeans พร้อม ManagedBean และ ViewScoped พวกเขายังคงเป็น JSF Managed Beans ใช่ไหม?
Koray Tugay

3
มีใครสามารถอัปเดต Java EE 7 ในบทความดีๆนี้ได้บ้าง?
Martijn Burger

7

ใช่อาจทำให้สับสนได้

สำหรับบางehmเหตุผลทางประวัติศาสตร์ JSF และ CDI ใช้คำอธิบายประกอบเดียวกันสำหรับขอบเขต แต่จากแพคเกจที่แตกต่างกัน

อย่างที่คุณคาดเดาได้ว่ามาjavax.faces.beanจากข้อมูลจำเพาะ JSF และไม่เกี่ยวข้องกับ CDI อย่าใช้มันเว้นแต่คุณจะมีเหตุผลที่ดีพอที่จะทำเช่นนั้น และไม่เคยผสมกับคำอธิบายประกอบ CDI จากjavax.ejbจาก สิ่งนี้จะทำให้เกิดรายการจุดบกพร่องและความผิดปกติเล็กน้อยอย่างไม่มีที่สิ้นสุด

โดยทั่วไปฉันแนะนำให้คุณอ่านเอกสาร Weldสองสามหน้าแรก (หรือมากกว่านั้น)เอกสารเชื่อมสิ่งนี้จะทำให้คุณสามารถติดตาม Java EE 6 ได้

และโพสต์คำถามเพิ่มเติมได้ที่นี่


จริงๆแล้วฉันมีคำถามสองข้อ: 1. ฉันมักพบว่าขอบเขตการดูมีประโยชน์มาก ฉันต้องใช้คำอธิบายประกอบ JSF หรือไม่? 2. หมายความว่า@javax.annotation.ManagedBeanไม่มีประโยชน์เพราะ CDI ถือว่าทุกชั้นเรียนเป็นถั่วจัดการใช่ไหม?
Piotr Gwiazda

ไม่มาก คุณจะต้องเชื่อมขอบเขต JSF กับ CDI ด้วยเช่น Seam Faces และใช่ @ManagedBeans ไม่จำเป็นหากคุณมี bean.xml ในไฟล์ jar ที่เกี่ยวข้อง อ้อและหากคุณมีคำถามเพิ่มเติมควรเริ่มหัวข้อใหม่ก่อนที่เราจะคลายตัวเองในส่วนความคิดเห็น
jan groth

3

เนื่องจากไม่มีการตอบกลับโดยเฉพาะเกี่ยวกับ@javax.annotation.ManagedBeanนี่คือลิงค์ไปยังคำตอบของคำถามที่คล้ายกัน: ถั่วสำรอง (@ManagedBean) หรือ CDI Beans (@Named)? . ข้อมูลจำเพาะสามารถพบได้ที่http://download.oracle.com/otndocs/jcp/managed_beans-1.0-fr-eval-oth-JSpec/ สำหรับฉันดูเหมือนว่า@javax.annotation.ManagedBeanมันควรจะเป็นลักษณะทั่วไปของ@javax.faces.bean.ManagedBeanควรจะเป็นลักษณะทั่วไปของ

จากสิ่งที่ฉันรวบรวมมา JSF Managed Beans กำลังถูกเลิกใช้เพื่อสนับสนุน CDI Beans (อาจจะเลิกใช้งาน JSF 2.3?) ดังนั้นฉันเดาว่า@javax.annotation.ManagedBeanตอนนี้ยิ่งล้าสมัยไปแล้ว


@Namedจะมาแทนที่@ManagedBeanในอนาคต?
Thufir

1
ฉันได้อ่านคำแถลงของผู้เชี่ยวชาญด้าน Java EE หลายคนที่คาดการณ์ว่า@Namedถั่วCDI จะแทนที่ JSF @ManagedBeansเช่นในstackoverflow.com/questions/4347374/… BalusC กล่าวว่า "ความคาดหวังคือ @ManagedBean และเพื่อน ๆ จะเลิกใช้งานตาม Java ศ. 8. ".
Hein Blöd
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.