Làm thế nào để chọn đúng phạm vi đậu?


381

Tôi nhận thấy rằng có các phạm vi đậu khác nhau như:

@RequestScoped
@ViewScoped
@FlowScoped
@SessionScoped
@ApplicationScoped

Mục đích của mỗi là gì? Làm thế nào để tôi chọn một phạm vi thích hợp cho đậu của tôi?


Câu trả lời:


485

Giới thiệu

Nó đại diện cho phạm vi (trọn đời) của hạt đậu. Điều này dễ hiểu hơn nếu bạn quen thuộc với hoạt động "dưới vỏ bọc" của một ứng dụng web servlet cơ bản: Làm thế nào để các servlet hoạt động? Khởi tạo, phiên, biến chia sẻ và đa luồng .


@Request/View/Flow/Session/ApplicationScoped

Một @RequestScopedbean tồn tại miễn là một chu kỳ phản hồi yêu cầu HTTP đơn (lưu ý rằng một yêu cầu Ajax cũng được tính là một yêu cầu HTTP đơn). Một @ViewScopedbean tồn tại miễn là bạn tương tác với cùng một chế độ xem JSF bằng các postback mà gọi các phương thức hành động trở lại null/ voidkhông có bất kỳ điều hướng / chuyển hướng nào. Một @FlowScopedbean tồn tại miễn là bạn điều hướng qua bộ sưu tập các khung nhìn được chỉ định đã đăng ký trong tệp cấu hình luồng. Một @SessionScopedbean sống miễn là phiên HTTP được thiết lập. Một @ApplicationScopedbean sống miễn là ứng dụng web chạy. Lưu ý rằng CDI @Modelvề cơ bản là một khuôn mẫu cho @Named @RequestScoped, vì vậy các quy tắc tương tự được áp dụng.

Việc chọn phạm vi nào chỉ phụ thuộc vào dữ liệu (trạng thái) mà bean giữ và đại diện. Sử dụng @RequestScopedcho các hình thức / bài thuyết trình đơn giản và không ajax. Sử dụng @ViewScopedcho các chế độ xem động hỗ trợ ajax phong phú (xác thực ajaxbided, kết xuất, hộp thoại, v.v.). Sử dụng @FlowScopedcho mẫu "trình hướng dẫn" ("bảng câu hỏi") để thu thập dữ liệu đầu vào trải rộng trên nhiều trang. Sử dụng @SessionScopedcho dữ liệu cụ thể của khách hàng, chẳng hạn như tùy chọn người dùng và người dùng đã đăng nhập (ngôn ngữ, v.v.). Sử dụng @ApplicationScopedcho các dữ liệu / hằng số ứng dụng rộng, chẳng hạn như danh sách thả xuống giống nhau cho tất cả mọi người hoặc các bean được quản lý mà không có bất kỳ biến đối tượng nào và chỉ có các phương thức.

Việc lạm dụng một @ApplicationScopedbean cho dữ liệu phạm vi phiên / lượt xem / yêu cầu sẽ khiến nó được chia sẻ giữa tất cả người dùng, vì vậy bất kỳ ai khác cũng có thể thấy dữ liệu của nhau, điều này hoàn toàn sai. Việc lạm dụng @SessionScopedbean để xem / yêu cầu dữ liệu trong phạm vi sẽ khiến nó được chia sẻ giữa tất cả các tab / cửa sổ trong một phiên trình duyệt, do đó, enduser có thể gặp phải sự bất tiện khi tương tác với mọi chế độ xem sau khi chuyển đổi giữa các tab không tốt cho trải nghiệm người dùng. Việc lạm dụng một @RequestScopedbean để xem dữ liệu trong phạm vi xem sẽ khiến dữ liệu trong phạm vi xem được sắp xếp lại thành mặc định trên mỗi postback (ajax), gây ra các dạng không hoạt động ( xem thêm điểm 4 và 5 tại đây ). Lạm dụng một @ViewScopedbean cho yêu cầu, phiên hoặc dữ liệu phạm vi ứng dụng và lạm dụng một@SessionScoped bean cho dữ liệu trong phạm vi ứng dụng không ảnh hưởng đến máy khách, nhưng nó không cần thiết chiếm bộ nhớ máy chủ và không hiệu quả.

Lưu ý rằng không nên chọn phạm vi dựa trên ý nghĩa hiệu suất, trừ khi bạn thực sự có dung lượng bộ nhớ thấp và muốn hoàn toàn không trạng thái; bạn cần sử dụng các @RequestScopedloại đậu và fiddle độc quyền với các tham số yêu cầu để duy trì trạng thái của máy khách. Cũng lưu ý rằng khi bạn có một trang JSF với dữ liệu có phạm vi khác nhau, thì việc đặt chúng vào các hạt dự phòng riêng biệt trong một phạm vi khớp với phạm vi của dữ liệu là hoàn toàn hợp lệ. Các hạt có thể truy cập lẫn nhau thông qua các @ManagedPropertytrường hợp đậu được quản lý JSF hoặc @Injecttrong trường hợp các hạt được quản lý CDI.

Xem thêm:


@CustomScoped/NoneScoped/Dependent

Nó không được đề cập trong câu hỏi của bạn, nhưng (di sản) JSF cũng hỗ trợ @CustomScoped@NoneScoped, hiếm khi được sử dụng trong thế giới thực. Các @CustomScopedphải giới thiệu một tùy chỉnh Map<K, Bean>thực hiện trong một số phạm vi rộng hơn trong đó có ghi đè Map#put()và / hoặc Map#get()trật tự trong để có thêm quyền kiểm soát tốt hơn hạt đậu tạo và / hoặc tiêu diệt.

Về cơ bản, JSF @NoneScopedvà CDI @Dependenttồn tại miễn là một đánh giá EL đơn lẻ trên hạt đậu. Hãy tưởng tượng một biểu mẫu đăng nhập với hai trường đầu vào tham chiếu thuộc tính bean và nút lệnh tham chiếu hành động bean, do đó, trong tổng số ba biểu thức EL, sau đó sẽ tạo ra ba trường hợp. Một với tên người dùng được đặt, một với mật khẩu được đặt và một với hành động được gọi. Bạn thường chỉ muốn sử dụng phạm vi này trên các hạt đậu sống lâu như hạt đậu được tiêm. Vì vậy, nếu a @NoneScopedhoặc @Dependentđược tiêm vào a @SessionScoped, thì nó sẽ sống lâu như @SessionScopedhạt đậu.

Xem thêm:


Phạm vi flash

Cuối cùng, JSF cũng hỗ trợ phạm vi flash. Nó được hỗ trợ bởi một cookie sống ngắn được liên kết với một mục nhập dữ liệu trong phạm vi phiên. Trước khi chuyển hướng, cookie sẽ được đặt trên phản hồi HTTP với giá trị được liên kết duy nhất với mục nhập dữ liệu trong phạm vi phiên. Sau khi chuyển hướng, sự hiện diện của cookie phạm vi flash sẽ được kiểm tra và mục nhập dữ liệu được liên kết với cookie sẽ bị xóa khỏi phạm vi phiên và được đưa vào phạm vi yêu cầu của yêu cầu được chuyển hướng. Cuối cùng, cookie sẽ bị xóa khỏi phản hồi HTTP. Bằng cách này, yêu cầu được chuyển hướng có quyền truy cập để yêu cầu dữ liệu trong phạm vi đã được chuẩn bị trong yêu cầu ban đầu.

Điều này thực sự không có sẵn như là một phạm vi bean được quản lý, tức là không có thứ gì như @FlashScoped. Phạm vi flash chỉ có sẵn dưới dạng bản đồ thông qua các ExternalContext#getFlash()hạt được quản lý và #{flash}trong EL.

Xem thêm:


4
Tôi nghĩ rằng một tài liệu tham khảo cho câu trả lời của bạn cho câu hỏi " Làm thế nào và khi nào thì một phạm vi khung nhìn được phá hủy trong JSF? " Có liên quan ở đây.
Lii

3
@Cold: đó là một phạm vi CDI cũ và trong JSF 2.2 được thay thế bằng @FlowScoped(không cần phải tự khởi động / dừng nó).
BalusC

1
Và DeltaSpike cũng có ViewAccesscopedWindowScoped
Kukeltje

@BalusC, tôi nghĩ có một vấn đề, với ViewScopedbean trong MyFaces 2.2. Tôi hiện đang đối mặt với một vấn đề với ViewScopedbean và Ajax, mà tôi đã đăng ở đây . Trong MyFaces JIRA, cũng có một cuộc thảo luận về chủ đề này.
Tapas Bose

CDI định nghĩa bốn phạm vi tích hợp: @RequestScoped @SessionScoped @ApplicationScoped @ConversationScoped tại sao phạm vi bạn mô tả lại khác nhau?
Hosein Aqajani

122

Vì JSF 2.3, tất cả các phạm vi đậu được xác định trong gói javax.faces.beangói đã không được dùng để căn chỉnh phạm vi với CDI. Hơn nữa, chúng chỉ được áp dụng nếu bean của bạn đang sử dụng @ManagedBeanchú thích. Nếu bạn đang sử dụng các phiên bản JSF dưới 2.3, hãy tham khảo câu trả lời kế thừa ở cuối.


Từ JSF 2.3, đây là các phạm vi có thể được sử dụng trên Đậu Backing của JSF:

1 .@javax.enterprise.context.ApplicationScoped : Phạm vi ứng dụng vẫn tồn tại trong toàn bộ thời gian của ứng dụng web. Phạm vi đó được chia sẻ giữa tất cả các yêu cầu và tất cả các phiên. Điều này rất hữu ích khi bạn có dữ liệu cho toàn bộ ứng dụng.

2 .@javax.enterprise.context.SessionScoped : Phạm vi phiên vẫn tồn tại từ khi phiên được thiết lập cho đến khi kết thúc phiên. Bối cảnh phiên được chia sẻ giữa tất cả các yêu cầu xảy ra trong cùng một phiên HTTP. Điều này hữu ích khi bạn không lưu dữ liệu cho một khách hàng cụ thể cho một phiên cụ thể.

3 .@javax.enterprise.context.ConversationScoped : Phạm vi hội thoại vẫn tồn tại dưới dạng log như bean sống. Phạm vi cung cấp 2 phương thức: Conversation.begin()Conversation.end(). Các phương thức này nên được gọi một cách rõ ràng, để bắt đầu hoặc kết thúc vòng đời của một hạt.

4 .@javax.enterprise.context.RequestScoped : Phạm vi yêu cầu là ngắn hạn. Nó bắt đầu khi một yêu cầu HTTP được gửi và kết thúc sau khi phản hồi được gửi lại cho khách hàng. Nếu bạn đặt một bean được quản lý vào phạm vi yêu cầu, một thể hiện mới sẽ được tạo với mỗi yêu cầu. Rất đáng để xem xét phạm vi yêu cầu nếu bạn lo ngại về chi phí lưu trữ phạm vi phiên.

5 .@javax.faces.flow.FlowScoped : Phạm vi Flow vẫn tồn tại chừng nào Flow còn sống. Một luồng có thể được định nghĩa là một tập hợp các trang (hoặc dạng xem) xác định một đơn vị công việc. Flow phạm vi được hoạt động miễn là người dùng điều hướng trong Flow.

6 .@javax.faces.view.ViewScoped : Một bean trong phạm vi khung nhìn vẫn tồn tại trong khi cùng một trang JSF được hiển thị lại. Ngay khi người dùng điều hướng đến một trang khác, bean sẽ vượt ra ngoài phạm vi.


Câu trả lời kế thừa sau đây áp dụng phiên bản JSF trước 2.3

Kể từ JSF 2.x, có 4 Phạm vi Bean:

  • @SessionScoped
  • @RequestScoped
  • @ Ứng dụngScoped
  • @ViewScoped

Phạm vi phiên: Phạm vi phiên vẫn tồn tại từ khi phiên được thiết lập cho đến khi kết thúc phiên. Một phiên kết thúc nếu ứng dụng web gọi phương thức không hợp lệ trên đối tượng HttpSession hoặc nếu nó hết thời gian.

RequestScope: Phạm vi yêu cầu là ngắn hạn. Nó bắt đầu khi một yêu cầu HTTP được gửi và kết thúc sau khi phản hồi được gửi lại cho khách hàng. Nếu bạn đặt một bean được quản lý vào phạm vi yêu cầu, một thể hiện mới sẽ được tạo với mỗi yêu cầu. Rất đáng để xem xét phạm vi yêu cầu nếu bạn lo ngại về chi phí lưu trữ phạm vi phiên.

ApplicationScope: Phạm vi ứng dụng vẫn tồn tại trong toàn bộ thời gian của ứng dụng web. Phạm vi đó được chia sẻ giữa tất cả các yêu cầu và tất cả các phiên. Bạn đặt các hạt được quản lý vào phạm vi ứng dụng nếu một hạt đậu phải được chia sẻ giữa tất cả các phiên bản của ứng dụng web. Bean được xây dựng khi nó được yêu cầu lần đầu bởi bất kỳ người dùng ứng dụng nào và nó vẫn tồn tại cho đến khi ứng dụng web bị xóa khỏi máy chủ ứng dụng.

ViewScope: Phạm vi xem đã được thêm vào trong JSF 2.0. Một bean trong phạm vi khung nhìn vẫn tồn tại trong khi cùng một trang JSF được hiển thị lại. (Đặc tả JSF sử dụng chế độ xem thuật ngữ cho trang JSF.) Ngay sau khi người dùng điều hướng đến một trang khác, bean sẽ vượt ra khỏi phạm vi.

Chọn phạm vi bạn dựa trên yêu cầu của bạn.

Nguồn: Máy chủ Java lõi phải đối mặt với phiên bản thứ 3 của David Geary & Cay Horstmann [Trang số. 51 - 54] nhập mô tả hình ảnh ở đây


Bạn có thể vui lòng làm rõ, ý của bạn là " invalidate()phương thức không hợp lệ trên đối tượng HttpSession": phương thức hoặc phương thức không hợp lệ?
Alexander Pozdneev 29/07/2015

1
Một chút cũ và có thể trễ để trả lời, nhưng để làm rõ nó: FacesContext.getCurrentInstance().getExternalContext().invalidateSession();được gọi trong "logout bean" của bạn là những gì anh ấy có nghĩa.
Roland

1
nó đã trở thành câu trả lời kế thừa, tại thời điểm này có 8 phạm vi
Ewoks

@KishorPrakash: một thời gian bây giờ là 6 tháng trước. ;-)
Kukeltje

@Kukeltje: Xin lỗi, tôi đang ở trên đó.
Kishor Prakash
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.