วิธีการเลือกขอบเขตถั่วที่เหมาะสม?


381

ฉันสังเกตเห็นว่ามีขอบเขตถั่วที่แตกต่างกันเช่น:

@RequestScoped
@ViewScoped
@FlowScoped
@SessionScoped
@ApplicationScoped

จุดประสงค์ของแต่ละคนคืออะไร? ฉันจะเลือกขอบเขตที่เหมาะสมสำหรับถั่วของฉันได้อย่างไร


courses.coreservlets.com/Course-Materials/pdf/jsf/jsf2/มีคำอธิบายในหน้า 6
Jacob

คำตอบ:


485

บทนำ

เพราะมันหมายถึงขอบเขต (อายุการใช้งาน) ของถั่ว สิ่งนี้ง่ายต่อการเข้าใจถ้าคุณคุ้นเคยกับการทำงานภายใต้ "หน้าปก" ของเว็บแอพพลิเคชัน servlet พื้นฐาน: servlets ทำงานอย่างไร instantiation เซสชันตัวแปรที่ใช้ร่วมกันและมัลติเธรด


@Request/View/Flow/Session/ApplicationScoped

@RequestScopedถั่วมีชีวิตอยู่ได้นานเท่าที่รอบ HTTP เดียวตอบสนองการร้องขอ (หมายเหตุว่านับคำขออาแจ็กซ์เป็นคำขอ HTTP เดียวเกินไป) @ViewScopedถั่วอาศัยอยู่ตราบเท่าที่คุณกำลังมีปฏิสัมพันธ์กับมุมมอง JSF เดียวกันโดย postbacks ซึ่งวิธีการดำเนินการโทรกลับnull/ voidโดยไม่ต้องนำทางใด ๆ / เปลี่ยนเส้นทาง A @FlowScopedbean มีอายุการใช้งานตราบเท่าที่คุณนำทางผ่านคอลเล็กชันมุมมองที่ระบุซึ่งลงทะเบียนในไฟล์การกำหนดค่าโฟลว์ @SessionScopedถั่วอาศัยอยู่ตราบเท่าที่เซสชั่น HTTP ที่จัดตั้งขึ้น @ApplicationScopedถั่วอาศัยอยู่ตราบเท่าที่โปรแกรมเว็บวิ่ง โปรดทราบว่า CDI @Modelนั้นเป็นแบบแผนสำหรับ@Named @RequestScopedดังนั้นจึงใช้กฎเดียวกัน

ขอบเขตการเลือกขึ้นอยู่กับข้อมูล (สถานะ) ที่เก็บและแสดงแทน ใช้@RequestScopedสำหรับรูปแบบ / งานนำเสนอที่เรียบง่ายและไม่ใช่อาแจ็กซ์ ใช้@ViewScopedสำหรับมุมมองแบบไดนามิกที่เปิดใช้งาน ajax (การตรวจสอบความถูกต้อง ajaxbased, การแสดงผล, ข้อความโต้ตอบ ฯลฯ ) ใช้@FlowScopedสำหรับรูปแบบ "วิซาร์ด" ("แบบสอบถาม") ในการรวบรวมข้อมูลอินพุตที่กระจายอยู่ในหลาย ๆ หน้า ใช้@SessionScopedสำหรับข้อมูลลูกค้าเฉพาะเช่นผู้ใช้ที่เข้าสู่ระบบและการตั้งค่าผู้ใช้ (ภาษา ฯลฯ ) ใช้@ApplicationScopedสำหรับข้อมูล / ค่าคงที่ทั้งแอปพลิเคชันเช่นรายการแบบหล่นลงที่เหมือนกันสำหรับทุกคนหรือจัดการถั่วโดยไม่มีตัวแปรอินสแตนซ์และมีวิธีการเท่านั้น

การใช้@ApplicationScopedถั่วในทางที่ผิดสำหรับเซสชัน / ดู / ขอข้อมูลที่กำหนดขอบเขตจะทำให้สามารถแบ่งปันกับผู้ใช้ทั้งหมดได้ดังนั้นผู้อื่นจะเห็นข้อมูลของกันและกันซึ่งเป็นเรื่องที่ผิดธรรมดา การใช้@SessionScopedถั่วเพื่อดู / กำหนดขอบเขตข้อมูลจะทำให้ถูกแบ่งปันระหว่างแท็บ / หน้าต่างทั้งหมดในเซสชันเบราว์เซอร์เดียวดังนั้นผู้ใช้อาจพบความไม่สอดคล้องกันเมื่อโต้ตอบกับทุกมุมมองหลังจากสลับระหว่างแท็บที่ไม่ดีสำหรับประสบการณ์ของผู้ใช้ การใช้@RequestScopedbean เพื่อดูข้อมูลที่กำหนดขอบเขตจะทำให้ข้อมูลที่กำหนดขอบเขตของมุมมองถูกกำหนดค่าเริ่มต้นเป็นค่าเริ่มต้นใหม่ในทุก ๆ โพสต์ (ajax) ทำให้เกิดรูปแบบที่ไม่ทำงาน ( ดูจุด 4 และ 5 ที่นี่ด้วย ) การใช้@ViewScopedถั่วเพื่อขอข้อมูลเซสชันหรือแอปพลิเคชันที่กำหนดขอบเขตและการใช้งานในทางที่ผิด@SessionScoped bean สำหรับข้อมูลที่มีการกำหนดขอบเขตของแอปพลิเคชันไม่ส่งผลกระทบต่อไคลเอ็นต์ แต่จะใช้หน่วยความจำของเซิร์ฟเวอร์โดยไม่จำเป็นและไม่มีประสิทธิภาพในระดับธรรมดา

หมายเหตุว่าขอบเขตควร แต่ไม่ได้รับการแต่งตั้งขึ้นอยู่กับผลกระทบประสิทธิภาพการทำงานถ้าคุณจริงๆมีรอยหน่วยความจำต่ำและต้องการที่จะไปอย่างสมบูรณ์ไร้สัญชาติ; คุณจะต้องใช้@RequestScopedถั่วและซอโดยเฉพาะกับพารามิเตอร์คำขอเพื่อรักษาสถานะของลูกค้า นอกจากนี้โปรดทราบว่าเมื่อคุณมีเพจ JSF หน้าเดียวที่มีข้อมูลที่กำหนดขอบเขตแตกต่างกันดังนั้นจึงเป็นการดีที่จะใส่ไว้ในแบ็คอัพสำรองในขอบเขตที่ตรงกับขอบเขตของข้อมูล beans สามารถเข้าถึงซึ่งกันและกันผ่านทาง@ManagedPropertyในกรณีของ beans ที่มีการจัดการ JSF หรือ@Injectในกรณีของ beans ที่มีการจัดการ CDI

ดูสิ่งนี้ด้วย:


@CustomScoped/NoneScoped/Dependent

มันไม่ได้กล่าวถึงในคำถามของคุณ แต่ (ดั้งเดิม) JSF ยังสนับสนุน@CustomScopedและ@NoneScopedซึ่งไม่ค่อยได้ใช้ในโลกแห่งความเป็นจริง @CustomScopedต้องอ้างอิงที่กำหนดเองMap<K, Bean>การดำเนินการในบางขอบเขตที่กว้างซึ่งมีแทนที่Map#put()และ / หรือMap#get()เพื่อให้มีการควบคุมที่ดีเม็ดเล็กที่มากกว่าการสร้างถั่วและ / หรือทำลาย

JSF @NoneScopedและ CDI @Dependentนั้นโดยทั่วไปแล้วจะมีชีวิตอยู่ตราบใดที่การประเมินค่า EL เดียวในถั่ว ลองนึกภาพรูปแบบการเข้าสู่ระบบที่มีช่องป้อนข้อมูลสองช่องที่อ้างถึงคุณสมบัติ bean และปุ่มคำสั่งที่อ้างถึงการกระทำ bean ดังนั้นด้วยนิพจน์ EL ทั้งหมดสามนิพจน์จากนั้นจะสร้างสามอินสแตนซ์ที่มีประสิทธิภาพ หนึ่งชุดพร้อมชื่อผู้ใช้หนึ่งชุดพร้อมรหัสผ่านและอีกหนึ่งชุดที่เรียกใช้การกระทำ โดยปกติคุณต้องการใช้ขอบเขตนี้เฉพาะในถั่วที่ควรมีชีวิตอยู่ตราบใดที่มีการฉีด ดังนั้นหาก a @NoneScopedหรือ@Dependentถูกฉีดเข้าไปใน a @SessionScopedมันจะมีชีวิตอยู่ตราบเท่าที่@SessionScopedถั่ว

ดูสิ่งนี้ด้วย:


ขอบเขตแฟลช

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

นี่ไม่สามารถใช้เป็นขอบเขตของถั่วที่ถูกจัดการได้นั่นคือไม่มีสิ่ง@FlashScopedนั้น ขอบเขตแฟลชใช้ได้เฉพาะในแผนที่ผ่านExternalContext#getFlash()ในถั่วที่ได้รับการจัดการและ#{flash}ใน EL

ดูสิ่งนี้ด้วย:


4
ฉันคิดว่าการอ้างอิงถึงคำตอบของคุณสำหรับคำถาม " ถั่วขอบเขตการดูถูกทำลายใน JSF อย่างไรและเมื่อไหร่ " มีความเกี่ยวข้องที่นี่
Lii

3
@Cold: นั่นคือขอบเขต CDI เก่าและในการแทนที่ JSF 2.2 ด้วย@FlowScoped(ไม่จำเป็นต้องเริ่ม / หยุดด้วยตนเอง)
BalusC

1
และ DeltaSpike ยังมีViewAccesscopedและWindowScoped
Kukeltje

@ BalusC ฉันคิดว่ามีปัญหาด้วยViewScopedbean ใน MyFaces 2.2 ฉันกำลังเผชิญปัญหากับViewScopedถั่วและอาแจ็กซ์ซึ่งผมได้โพสต์ที่นี่ ใน MyFaces JIRA ยังมีการอภิปรายในหัวข้อนี้
Tapas Bose

CDI กำหนดขอบเขตในตัวสี่: @RequestScoped @SessionScoped @ApplicationScoped @ConversationScoped ทำไมขอบเขตที่คุณอธิบายแตกต่างกันอย่างไร
โฮชิน Aqajani

122

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


จาก JSF 2.3 นี่คือขอบเขตที่สามารถใช้กับ JSF Backing Beans:

1.@javax.enterprise.context.ApplicationScoped : ขอบเขตแอปพลิเคชันยังคงมีอยู่ตลอดระยะเวลาของแอปพลิเคชันเว็บ ขอบเขตนั้นจะถูกใช้ร่วมกันระหว่างคำขอทั้งหมดและเซสชันทั้งหมด สิ่งนี้มีประโยชน์เมื่อคุณมีข้อมูลสำหรับทั้งแอปพลิเคชัน

2.@javax.enterprise.context.SessionScoped : ขอบเขตเซสชันยังคงอยู่นับจากเวลาที่มีการสร้างเซสชันจนกว่าการยกเลิกเซสชันจะเกิดขึ้น บริบทเซสชันถูกแชร์ระหว่างคำขอทั้งหมดที่เกิดขึ้นในเซสชัน HTTP เดียวกัน สิ่งนี้มีประโยชน์เมื่อคุณไม่บันทึกข้อมูลสำหรับไคลเอนต์ที่เฉพาะเจาะจงสำหรับเซสชันที่เฉพาะเจาะจง

3.@javax.enterprise.context.ConversationScoped : ขอบเขตการสนทนายังคงอยู่ในลักษณะล็อกขณะที่ bean ยังมีชีวิตอยู่ ขอบเขตมี 2 วิธี: และConversation.begin() Conversation.end()วิธีการเหล่านี้ควรเรียกอย่างชัดเจนไม่ว่าจะเริ่มต้นหรือจบชีวิตของถั่ว

4.@javax.enterprise.context.RequestScoped : ขอบเขตของคำขอมีอายุสั้น มันเริ่มต้นเมื่อมีการส่งคำขอ HTTP และสิ้นสุดลงหลังจากการตอบกลับถูกส่งกลับไปยังลูกค้า หากคุณวางถั่วที่ได้รับการจัดการลงในขอบเขตคำขออินสแตนซ์ใหม่จะถูกสร้างขึ้นพร้อมกับคำขอแต่ละรายการ ควรพิจารณาขอบเขตคำขอหากคุณมีความกังวลเกี่ยวกับต้นทุนของการจัดเก็บขอบเขตเซสชัน

5.@javax.faces.flow.FlowScoped : ขอบเขตการไหลยังคงอยู่ตราบใดที่ Flow ยังมีชีวิตอยู่ การไหลอาจถูกกำหนดให้เป็นชุดของหน้า (หรือมุมมอง) ที่มีหน่วยงาน การกำหนดขอบเขตของโฟลว์นั้นใช้งานได้ตราบใดที่ผู้ใช้นำทางด้วยในโฟลว์

6.@javax.faces.view.ViewScoped : bean ในขอบเขตการดูยังคงอยู่ในขณะที่หน้า JSF เดียวกันแสดงขึ้นมาใหม่ ทันทีที่ผู้ใช้นำทางไปยังหน้าอื่น bean ออกนอกขอบเขต


คำตอบเดิมต่อไปนี้ใช้เวอร์ชัน JSF ก่อน 2.3

ตั้งแต่ JSF 2.x มีขอบเขต 4 Bean:

  • @SessionScoped
  • @RequestScoped
  • @ApplicationScoped
  • @ViewScoped

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

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

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

ViewScope: เพิ่มขอบเขตการดูใน JSF 2.0 bean ในมุมมองยังคงอยู่ในขณะที่หน้า JSF เดียวกันแสดงขึ้นมาใหม่ (ข้อมูลจำเพาะ JSF ใช้มุมมองคำสำหรับหน้า JSF) ทันทีที่ผู้ใช้นำทางไปยังหน้าอื่น Bean จะออกจากขอบเขต

เลือกขอบเขตที่คุณต้องการ

ที่มา: Core Java Server Faces รุ่นที่ 3โดย David Geary & Cay Horstmann [หมายเลขหน้า] 51 - 54] ป้อนคำอธิบายรูปภาพที่นี่


คุณช่วยอธิบายได้อย่างชัดเจนคุณหมายถึง "วิธีการที่ไม่ถูกต้องในวัตถุ HttpSession": invalidate()วิธีการหรือวิธีที่ไม่ถูกต้องหรือไม่
Alexander Pozdneev

1
ค่อนข้างเก่าและอาจจะช้าไปหน่อย แต่เพื่อชี้แจงให้ชัดเจน: FacesContext.getCurrentInstance().getExternalContext().invalidateSession();การถูกเรียกใช้ใน "logout bean" ของคุณคือสิ่งที่เขาหมายถึง
Roland

1
มันกลายเป็นคำตอบเดิมในขณะนี้มี 8 ขอบเขต
Ewoks

@KishorPrakash: ได้สักพักแล้ว 6 เดือนที่ผ่านมา ;-)
Kukeltje

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