Đậu hậu (@ManagedBean) hay Đậu CDI (@Named)?


109

Tôi vừa mới bắt đầu đọc qua Core JavaServer Faces, Phiên bản thứ 3. và họ nói điều này (nhấn mạnh của tôi):

Đó là một sự cố lịch sử mà có hai cơ chế riêng biệt, các bean CDI và các bean được quản lý JSF, cho các bean có thể được sử dụng trong các trang JSF. Chúng tôi khuyên bạn nên sử dụng các hạt CDI trừ khi ứng dụng của bạn phải hoạt động trên một trình chạy servlet đơn giản như Tomcat.

Tại sao? Họ không đưa ra bất kỳ lời biện minh nào. Tôi đã sử dụng @ManagedBeancho tất cả các bean trong một ứng dụng nguyên mẫu chạy trên GlassFish 3 và tôi thực sự không nhận thấy bất kỳ vấn đề nào với điều này. Tôi đặc biệt không bận tâm khi chuyển từ @ManagedBeansang @Named, nhưng tôi muốn biết tại sao tôi phải bận tâm .



4
@Bozho: câu hỏi đó khá giống, nhưng sau khi đọc lại câu trả lời của Pascal vài lần, tôi vẫn không hiểu tại sao CDI lại vượt trội hơn nhiều. Tôi không biết CDI và tôi rất vui khi học nó vì nó "tốt hơn". Tại sao nó tốt hơn?
Matt Ball

"trừ khi ứng dụng của bạn phải hoạt động trên một trình chạy servlet đơn giản như Tomcat" Tôi chỉ sử dụng tomcat và tôi thực sự khuyên bạn nên dùng CDI. Tomcat có thể hỗ trợ nó chỉ tốt
Karl Kildén

1
@ KarlKildén "người chạy servlet đơn giản" đề cập đến một vùng chứa servlet không có CDI. Vào thời điểm viết bài, Tomcat không hỗ trợ CDI ngoại trừ một chút ma thuật.
Thorbjørn Ravn Andersen

Câu trả lời:


64

CDI được ưu tiên hơn JSF đơn giản vì CDI cho phép đưa vào JavaEE trên toàn bộ phụ thuộc. Bạn cũng có thể tiêm POJO và để chúng được quản lý. Với JSF, bạn chỉ có thể đưa vào một tập hợp con những gì bạn có thể với CDI.


Vì vậy, về cơ bản, tôi có thể chèn một phiên bản của hầu hết mọi lớp (miễn là nó có "đúng thứ" - nó là gì, chỉ là một hàm tạo không đối số? ) Với CDI, trong khi tôi phải sử dụng @ManagedBeannếu tôi muốn đưa nó vào JSF?
Matt Ball

3
@MattBall Matt sau bạn nhiều năm, bạn có thể nhận xét về sự di chuyển này?
Koray Tugay

5
@KorayTugay Tôi chưa chạm vào mã này kể từ tháng 6 năm 2011 nhưng tôi đã chuyển sang CDI và mọi thứ hoạt động tốt. Tôi sẵn lòng trả lời bất kỳ câu hỏi cụ thể nào theo trí nhớ tốt nhất của mình nếu bạn có chúng.
Matt Ball

170

Sử dụng CDI.

Theo JSF 2.3, @ManagedBeanđược tán thành . Xem thêm thông số kỹ thuật số 1417 . Điều này có nghĩa rằng có không nữa một lý do để lựa chọn @ManagedBeanhơn @Named. Điều này lần đầu tiên được triển khai trong phiên bản beta Mojarra 2.3.0 m06.

nhập mô tả hình ảnh ở đây


Lịch sử

Sự khác biệt cốt lõi là, @ManagedBeanđược quản lý bởi khuôn khổ JSF và chỉ @ManagedPropertycó sẵn cho các bean được quản lý JSF khác. @Namedđược quản lý bởi máy chủ ứng dụng (container) qua khuôn khổ CDI và là thông qua @Injectcung cấp cho bất kỳ loại một tạo tác quản lý container như @WebListener, @WebFilter, @WebServlet, @Path, @Stateless, vv và thậm chí là một JSF @ManagedBean. Từ phía bên kia về, @ManagedPropertykhông không làm việc bên trong một @Namedhoặc bất kỳ container quản lý vật khác. Nó chỉ hoạt động bên trong @ManagedBean.

Một sự khác biệt khác là CDI thực sự đưa các proxy ủy quyền cho phiên bản hiện tại trong phạm vi đích trên cơ sở mỗi yêu cầu / luồng (giống như cách EJB được đưa vào). Cơ chế này cho phép đưa một bean có phạm vi hẹp hơn vào bean có phạm vi rộng hơn, điều này không thể thực hiện được với JSF @ManagedProperty. JSF "đưa" vào đây trực tiếp cá thể vật lý bằng cách gọi một setter (đó cũng chính xác là lý do tại sao cần phải có setter, trong khi điều đó không bắt buộc với @Inject).

Mặc dù không trực tiếp là một bất lợi - có những cách khác - phạm vi của @ManagedBeannó chỉ đơn giản là hạn chế. Ở góc độ khác, nếu bạn không muốn phơi bày "quá nhiều" @Inject, bạn cũng có thể giữ lại những hạt đậu đã quản lý của mình @ManagedBean. Nó giống như protectedso với public. Nhưng điều đó không thực sự được tính.

Ít nhất, trong JSF 2.0 / 2.1, nhược điểm lớn của việc quản lý các hạt sao lưu JSF bằng CDI là không có CDI tương đương @ViewScoped. Quá trình @ConversationScopednày đến gần, nhưng vẫn yêu cầu bắt đầu và dừng theo cách thủ công và nó thêm một cidtham số yêu cầu xấu vào các URL kết quả. MyFaces CODI giúp việc này trở nên dễ dàng hơn bằng cách kết nối hoàn toàn minh bạch giữa JSF javax.faces.bean.ViewScopedvới CDI để bạn có thể thực hiện @Named @ViewScoped, tuy nhiên, điều đó sẽ thêm một windowIdtham số yêu cầu xấu vào các URL kết quả, cũng trên điều hướng từ trang đến trang đơn giản. OmniFaces giải quyết tất cả điều này bằng một CDI @ViewScopedthực sự liên kết phạm vi của bean với trạng thái xem JSF thay vì với một tham số yêu cầu tùy ý.

JSF 2.2 (được phát hành 3 năm sau câu hỏi / câu trả lời này) cung cấp một @ViewScopedchú thích hoàn toàn mới tương thích với CDI javax.faces.view.ViewScoped. JSF 2.2 thậm chí còn đi kèm với chỉ CDI @FlowScopedmà không có @ManagedBeantương đương, do đó thúc đẩy người dùng JSF hướng tới CDI. Kỳ vọng là như vậy @ManagedBeanvà bạn bè sẽ không được chấp nhận theo Java EE 8. Nếu bạn hiện vẫn đang sử dụng @ManagedBean, do đó, bạn nên chuyển sang CDI để chuẩn bị cho các lộ trình nâng cấp trong tương lai. CDI có sẵn trong các vùng chứa tương thích với Hồ sơ Web Java EE, chẳng hạn như WildFly, TomEE và GlassFish. Đối với Tomcat, bạn phải cài đặt nó một cách riêng biệt, chính xác như bạn đã làm cho JSF. Xem thêm Cách cài đặt CDI trong Tomcat?


4
Tôi đã tạo beans.xml, chuyển đổi các @ManagedBeanhạt sao lưu thành @Namedvà chuyển đổi @ManagedPropertythành @Inject. Tất cả là tốt với thế giới. Tuy nhiên, nếu tôi thay đổi @EJBchú thích của mình thành @Inject, triển khai không thành công ( org.jboss.weld.exceptions.DeploymentException) với thông báo WELD-001408 Injection point has unsatisfied dependencies. Tôi thực sự nên sử dụng @Injectđể đưa các EJB không có giao diện vào một @Namedbean hay tôi nên gắn bó với nó @EJB? Các EJB được đóng gói trong một EJB JAR, trong cùng một EAR với WAR chứa các hạt CDI của tôi.
Matt Ball

Nó sẽ chỉ hoạt động. Bạn vẫn phải đối mặt với vấn đề này với phiên bản Weld hiện tại?
BalusC

Than ôi, tôi không thể nói. Câu hỏi này là của 2 nhà tuyển dụng và> 2 năm trước. Dựa trên nhận xét cũ của tôi về câu trả lời của Bozho, tôi hẳn đã chuyển sang CDI / @Named.
Matt Ball

"MyFaces CODI làm cho việc này trở nên dễ dàng hơn bằng cách bắc cầu hoàn toàn minh bạch javax.faces.bean.ViewScoped của JSF với CDI để bạn có thể thực hiện @Named @ViewScoped, tuy nhiên, điều đó sẽ thêm một tham số yêu cầu windowId xấu xí vào các URL kết quả, cũng trên điều hướng từng trang đơn giản." Lưu ý rằng với DeltaSpike, điều này không còn đúng nữa. Bạn có thể tắt cả tham số URL dsId và windowId, nếu bạn không cần Phạm vi cửa sổ.
JanM

1
@Jan: Và trong khi đó, OmniFaces cũng có một JSF 2.2-like @ViewScopedcho JSF 2.0 / 2.1: showcase.omnifaces.org/cdi/ViewScoped
BalusC

16

Với Java EE 6 và CDI, bạn có tùy chọn khác cho Managed Beans

  • @javax.faces.bean.ManagedBeanlà tham chiếu đến JSR 314 và được giới thiệu với JSF 2.0. Mục tiêu chính là tránh cấu hình trong tệp face-config.xml để sử dụng bean bên trong Trang JSF.
  • @javax.annotation.ManagedBean(“myBean”) được định nghĩa bởi JSR 316. Nó tổng quát các bean được quản lý JSF để sử dụng ở những nơi khác trong Java EE
  • @javax.inject.Named(“myBean”) gần giống như tệp ở trên, ngoại trừ bạn cần tệp bean.xml trong Thư mục web / WEB-INF để kích hoạt CDI.

1
Sự khác biệt giữa hai đầu tiên là gì?
Matt Ball

Mục tiêu của chú thích đầu tiên là / là để thay thế cấu hình bean trong face-config.xml để sử dụng trong JSF. Cái thứ hai sao chép khái niệm vào "java ee 6 container". Nó có nhiều chức năng hơn (như chú thích @PostConstruct và @PreDestroy), nhưng cũng có thể truy cập được bằng Trang JSF (với Ngôn ngữ biểu hiện).
h2mch

1
tại sao bạn cần một beans.xmltập tin? Ngày nay điều này có còn đúng không?
Thufir

2
Không, với JavaEE7, bạn không cần tới bean.xml nữa. xem docs.oracle.com/javaee/7/tutorial/doc/cdi-adv001.htm
h2mch

1
Với JavaEE7 bạn không cần beans.xml: docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm (đúng link) blogs.oracle.com/theaquarium/entry/... (Mặc định CDI Enablement trong Java EE 7)
M. Atif Riaz

2

Tôi đang sử dụng CDI trong GlassFish 3.0.1, nhưng để nó hoạt động, tôi phải nhập khuôn khổ Seam 3 (Weld). Điều đó hoạt động khá tốt.

Trong GlassFish 3.1 CDI ngừng hoạt động và Seam Weld ngừng hoạt động với nó. Tôi đã mở một lỗi về điều này nhưng vẫn chưa thấy nó được sửa. Tôi đã phải chuyển đổi tất cả mã của mình sang sử dụng các chú thích javax.faces. * Nhưng tôi dự định quay lại CDI khi chúng hoạt động.

Tôi đồng ý rằng bạn nên sử dụng CDI, nhưng một vấn đề mà tôi chưa thấy giải quyết là phải làm gì với chú thích @ViewScoped. Tôi có rất nhiều mã phụ thuộc vào nó. Không rõ liệu @ViewScoped có hoạt động hay không nếu bạn không sử dụng @ManagedBean với nó. Nếu bất cứ ai có thể làm rõ điều này, tôi sẽ đánh giá cao nó.


-1

Một lý do chính đáng để chuyển sang CDI: bạn có thể có một tài nguyên có phạm vi phiên chung (ví dụ: hồ sơ người dùng) @Inject đưa vào cả các dịch vụ được quản lý JSF và các dịch vụ REST (tức là Jersey / JAX-RS).

Mặt khác, @ViewScopedlà một lý do thuyết phục để gắn bó với JSF @ManagedBean- đặc biệt là đối với bất kỳ thứ gì có AJAX quan trọng. Không có tiêu chuẩn thay thế cho điều này trong CDI.

Có vẻ như nó có thể có một số hỗ trợ cho @ViewScopedchú thích giống như đậu CDI, nhưng cá nhân tôi chưa chơi với nó.

http://seamframework.org/Seam3/FacesModule

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.