Java EE 6 @ javax.annotation.ManagedBean so với @ javax.inject.Named so với @ javax.faces.ManagedBean


107

Tôi cảm thấy có một chút lộn xộn trong thông số kỹ thuật Java EE 6. Có một số tập hợp các chú thích.

Chúng tôi có javax.ejbcác chú thích như @Stateful@Statelessđể tạo EJB.

Ngoài ra còn có một @javax.annotation.ManagedBeanđể tạo một bean được quản lý.

Có chú thích trong javax.enterprise.contextlike @SessionScoped@RequestScoped.

Hơn nữa còn có @ManagedBean@SessionScoped/ @RequestScopedchú thích trong javax.faces.beangói.

Và để làm cho mọi thứ trở nên phức tạp hơn, có một gói javax.inject@Namedchú thích.

Ai đó có thể vui lòng mô tả cách chúng có liên quan với nhau không?

Tôi có thể sử dụng ở đâu @EJB, @Injecthoặc @ManagedProperyđể tiêm các loại đậu khác?


Câu trả lời:


194

Trước hết, hãy để tôi làm rõ một số điều:

Định nghĩa bean được quản lý : nói chung bean được quản lý là một đối tượng mà vòng đời của nó (xây dựng, phá hủy, v.v.) được quản lý bởi một vùng chứa.

Trong Java ee, chúng ta có nhiều vùng chứa quản lý vòng đời của các đối tượng của chúng, như vùng chứa JSF, vùng chứa EJB, vùng chứa CDI, vùng chứa Servlet, v.v.

Tất cả các vùng chứa này hoạt động độc lập, chúng khởi động trong quá trình khởi tạo máy chủ ứng dụng và quét các lớp của tất cả các hiện vật bao gồm tệp jar, ejb-jar, war và ear trong thời gian triển khai, đồng thời thu thập và lưu trữ một số siêu dữ liệu về chúng, sau đó khi bạn cần một đối tượng của một lớp trong thời gian chạy, họ sẽ cung cấp cho bạn các cá thể của các lớp đó và sau khi hoàn thành công việc, họ sẽ hủy chúng.

Vì vậy, chúng ta có thể nói rằng chúng ta có:

  • Đậu được quản lý JSF
  • CDI quản lý đậu
  • EJB quản lý đậu
  • Và ngay cả Servlet cũng được quản lý bean vì chúng được khởi tạo và phá hủy bởi một container, đó là một thùng chứa servlet.

Vì vậy, khi bạn nhìn thấy từ Managed Bean, bạn nên hỏi về ngữ cảnh hoặc loại của nó. (JSF, CDI, EJB, v.v.)

Sau đó, bạn có thể hỏi tại sao chúng tôi có nhiều vùng chứa này: AFAIK, Java EE guys muốn có một khung phụ thuộc chèn ép, nhưng họ không thể tập hợp tất cả các yêu cầu trong một đặc điểm kỹ thuật vì họ không thể dự đoán các yêu cầu trong tương lai và họ đã tạo ra EJB 1.0 và sau đó 2.0, sau đó là 3.0 và bây giờ là 3.1 nhưng mục tiêu của EJB chỉ dành cho một số yêu cầu (giao dịch, mô hình thành phần phân tán, v.v.).

Đồng thời (song song) họ nhận ra rằng họ cũng cần hỗ trợ JSF, sau đó họ tạo các bean được quản lý JSF và một vùng chứa khác cho các hạt JSF và họ coi đó là một vùng chứa DI trưởng thành, nhưng nó vẫn chưa phải là vùng chứa hoàn chỉnh và trưởng thành.

Sau đó Gavin King và một số anh chàng tốt bụng khác;) đã tạo ra CDI, đây là bộ chứa DI trưởng thành nhất mà tôi từng thấy. CDI (lấy cảm hứng từ Seam2, Guice và Spring) được tạo ra để lấp đầy khoảng cách giữa JSF và EJB và rất nhiều thứ hữu ích khác như pojo injection, producer method, interceptors, decorator, tích hợp SPI, rất linh hoạt, v.v. và nó thậm chí có thể làm được những gì các bean được quản lý bởi EJB và JSF đang làm thì chúng ta có thể chỉ có một vùng chứa DI trưởng thành và mạnh mẽ. Nhưng vì một số lý do tương thích ngược và lý do chính trị nên các chàng trai Java EE muốn giữ chúng !!!

Tại đây, bạn có thể tìm thấy sự khác biệt và các trường hợp sử dụng cho từng loại này:

Đậu được quản lý JSF, Đậu CDI và EJB

JSF ban đầu được phát triển với cơ chế tiêm phụ thuộc và bean được quản lý của riêng nó, cơ chế này đã được cải tiến cho JSF 2.0 để bao gồm các bean dựa trên chú thích. Khi CDI được phát hành cùng với Java EE 6, nó được coi là khung bean được quản lý cho nền tảng đó và tất nhiên, các EJB đã lỗi thời tất cả chúng đã tồn tại hơn một thập kỷ.

Tất nhiên, vấn đề là biết sử dụng cái nào và khi nào thì sử dụng chúng.

Hãy bắt đầu với các bean được quản lý JSF đơn giản nhất.

Đậu được quản lý JSF

Tóm lại, không sử dụng chúng nếu bạn đang phát triển cho Java EE 6 và sử dụng CDI. Chúng cung cấp một cơ chế đơn giản để tiêm phụ thuộc và xác định các hạt hỗ trợ cho các trang web, nhưng chúng kém mạnh hơn nhiều so với các hạt CDI.

Chúng có thể được xác định bằng cách sử dụng @javax.faces.bean.ManagedBeanchú thích có tham số tên tùy chọn. Tên này có thể được sử dụng để tham chiếu bean từ các trang JSF.

Phạm vi có thể được áp dụng cho bean bằng cách sử dụng một trong các phạm vi khác nhau được xác định trong javax.faces.beangói bao gồm phạm vi yêu cầu, phiên, ứng dụng, chế độ xem và tùy chỉnh.

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

Không thể trộn đậu JSF với các loại đậu khác nếu không có một số loại mã hóa thủ công.

CDI đậu

CDI là framework quản lý bean và phụ thuộc được phát hành như một phần của Java EE 6 và nó bao gồm một cơ sở bean được quản lý toàn diện, hoàn chỉnh. Các hạt CDI tiên tiến và linh hoạt hơn nhiều so với các hạt được quản lý JSF đơn giản. Họ có thể sử dụng các thiết bị đánh chặn, phạm vi hội thoại, Sự kiện, kiểu tiêm an toàn, người trang trí, khuôn mẫu và phương pháp của nhà sản xuất.

Để triển khai các bean CDI, bạn phải đặt một tệp có tên là bean.xml trong thư mục META-INF trên classpath. Khi bạn làm điều này, thì mỗi hạt đậu trong gói sẽ trở thành hạt đậu CDI. Có rất nhiều tính năng trong CDI, quá nhiều tính năng cần trình bày ở đây, nhưng để tham khảo nhanh các tính năng giống JSF, bạn có thể xác định phạm vi của bean CDI bằng cách sử dụng một trong các phạm vi được xác định trong javax.enterprise.contextgói (cụ thể là yêu cầu, hội thoại , phạm vi phiên và ứng dụng). Nếu bạn muốn sử dụng bean CDI từ trang JSF, bạn có thể đặt tên cho nó bằng cách sử dụng javax.inject.Namedchú thích. Để chèn một hạt đậu vào một hạt đậu khác, bạn chú thích trường bằng javax.inject.Injectchú thích.

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

    @Inject
    private SomeService someService;
}

Việc tiêm tự động như được định nghĩa ở trên có thể được kiểm soát thông qua việc sử dụng Bộ định lượng có thể giúp khớp với lớp cụ thể mà bạn muốn tiêm. Nếu bạn có nhiều hình thức thanh toán, bạn có thể thêm bộ định lượng để xem nó có phải là không đồng bộ hay không. Mặc dù bạn có thể sử dụng @Namedchú thích như một định nghĩa, nhưng bạn không nên sử dụng chú thích vì nó được cung cấp để hiển thị các hạt đậu trong EL.

CDI xử lý việc tiêm hạt đậu với phạm vi không khớp thông qua việc sử dụng proxy. Do đó, bạn có thể đưa một bean phạm vi yêu cầu vào một bean phạm vi phiên và tham chiếu sẽ vẫn hợp lệ trên mỗi yêu cầu vì đối với mỗi yêu cầu, proxy lại kết nối với một phiên bản trực tiếp của bean phạm vi yêu cầu.

CDI cũng có hỗ trợ cho các trình đánh chặn, sự kiện, phạm vi hội thoại mới và nhiều tính năng khác khiến nó trở thành một lựa chọn tốt hơn nhiều so với các hạt được quản lý JSF.

EJB

EJB có trước đậu CDI và về mặt nào đó tương tự như đậu CDI và theo những cách khác thì rất khác. Về cơ bản, sự khác biệt giữa các hạt CDI và EJB là các EJB là:

  • Giao dịch
  • Từ xa hoặc cục bộ
  • Có thể thụ động đậu trạng thái giải phóng tài nguyên
  • Có thể sử dụng bộ hẹn giờ
  • Có thể không đồng bộ

Hai loại EJB được gọi là không trạng thái và trạng thái. Các EJB không trạng thái có thể được coi là các hạt đậu sử dụng một lần an toàn cho luồng không duy trì bất kỳ trạng thái nào giữa hai yêu cầu web. Các EJB trạng thái có trạng thái lưu giữ và có thể được tạo và ngồi xung quanh miễn là chúng cần thiết cho đến khi chúng được xử lý.

Định nghĩa một EJB rất đơn giản, bạn chỉ cần thêm một javax.ejb.Statelesshoặc javax.ejb.Statefulchú thích vào lớp.

@Stateless
public class BookingService {

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

Đậu không trạng thái phải có phạm vi phụ thuộc trong khi đậu phiên trạng thái có thể có bất kỳ phạm vi nào. Theo mặc định, chúng là giao dịch, nhưng bạn có thể sử dụng chú thích thuộc tính giao dịch.

Trong khi các EJB và CDI đậu rất khác nhau về các tính năng, việc viết mã để tích hợp chúng rất giống nhau vì các hạt CDI có thể được tiêm vào EJB và các EJB có thể được tiêm vào các hạt CDI. Không cần phân biệt khi tiêm cái này vào cái kia. Một lần nữa, các phạm vi khác nhau được CDI xử lý thông qua việc sử dụng proxy. Một ngoại lệ cho điều này là CDI không hỗ trợ việc đưa vào các EJB từ xa nhưng điều đó có thể được thực hiện bằng cách viết một phương thức nhà sản xuất đơn giản cho nó.

Các javax.inject.Namedchú thích cũng như bất kỳ Qualifiers có thể được sử dụng trên một EJB để phù hợp với nó vào một điểm tiêm.

Khi nào dùng đậu nào

Làm thế nào để bạn biết khi sử dụng đậu? Đơn giản.

Không bao giờ sử dụng các bean được quản lý JSF trừ khi bạn đang làm việc trong một thùng chứa servlet và không muốn thử và bắt CDI hoạt động trong Tomcat (mặc dù có một số nguyên mẫu của Maven cho điều đó nên không có lý do gì).

Nói chung, bạn nên sử dụng các hạt CDI trừ khi bạn cần chức năng nâng cao có sẵn trong EJB, chẳng hạn như các chức năng giao dịch. Bạn có thể viết bộ đánh chặn của riêng mình để thực hiện giao dịch các hạt CDI, nhưng hiện tại, việc sử dụng EJB đơn giản hơn cho đến khi CDI nhận được các hạt CDI giao dịch đang ở gần. Nếu bạn bị mắc kẹt trong vùng chứa servlet và đang sử dụng CDI, thì giao dịch viết tay hoặc công cụ chặn giao dịch của riêng bạn là lựa chọn duy nhất không có EJB.

Nếu bạn cần sử dụng @ViewScopedtrong CDI, bạn nên

  • sử dụng mặt đường may hoặc mô-đun MyFaces CODI . chỉ cần thêm một trong số chúng vào classpath của bạn và @ViewScopedsẽ hoạt động trong CDI. MyFaces CODI có sự hỗ trợ vững chắc hơn của @ViewScoped
  • sử dụng MyFaces CODI's @ViewAccessScoped, nó là một phần mở rộng được Apache viết trên CDI, chỉ cần tải xuống và sử dụng @ViewAccessScopedchú thích thay vì @ViewScoped.
  • Sử dụng CDI @ConversationScopedvà làm cho nó hoạt động lâu dài. Xem ở đây để biết thêm thông tin .
  • Sử dụng Omnifaces @ViewScoped chú thích

Một số phần bị ăn cắp từ đây .


3
Điều đó thật tuyệt! Cảm ơn! Để hoàn tất, chỉ cần cho biết cách đưa CDI hoặc EJB bean vào JSF bean. Là @ManagedProperty("#{someBean})"cách thích hợp?
Piotr Gwiazda

2
Không! nó sẽ không hoạt động. chỉ cần bật JSF bean được quản lý của bạn để CDI quản lý đậu bằng cách chú thích nó sử dụng @Named@javax.enterprise.context.RequestScopedvà tiêm sử dụng CDI sử dụng chú thích @Inject. không sử dụng đậu được quản lý jsf nếu bạn không cần phải làm thế;).
Mehdi

3
> Các chàng trai của JEE muốn giữ chúng lại !!! - Nó tinh tế hơn thế một chút. CDI đã hoàn thành khá muộn trong chu kỳ Java EE 6 và cả JSF 2 & JAX-RS đều đã được thực hiện. Họ đã nâng cao phản ứng. đã giới thiệu cơ sở đậu do chính họ quản lý. Nếu CDI có sẵn sớm hơn một chút, mọi thứ có thể đã khác. Trong Java EE 7, JSF sẽ áp dụng CDI và javax.faces.bean cuối cùng sẽ không được dùng nữa (tuy nhiên, việc ngừng sử dụng là một quá trình chậm trong Java EE, điều này vừa tốt vừa xấu).
Arjan Tijms

3
Khi bạn nói: Để triển khai các bean CDI, bạn phải đặt một tệp có tên là bean.xml trong thư mục META-INF trên classpath. Khi bạn làm điều này, thì mỗi hạt đậu trong gói sẽ trở thành hạt đậu CDI. Bạn có nghĩa là mỗi hạt đậu cũng trở thành một hạt CDI ngoài những gì nó đã được? Điều gì sẽ xảy ra nếu tôi có JSF ManagedBeans với ManagedBean và ViewScoped. Họ vẫn là Đậu được quản lý JSF phải không?
Koray Tugay

3
Ai đó có thể cập nhật cho Java EE 7 trên bài viết tuyệt vời này?
Martijn Burger

7

Đúng, điều này có thể gây nhầm lẫn.

Đối với một số ehm lý do lịch sử JSF và CDI đang sử dụng cùng các chú thích cho phạm vi, nhưng từ các gói khác nhau.

Như bạn có thể đoán những từ đó javax.faces.beanlà từ thông số JSF và không liên quan đến CDI. Không sử dụng chúng trừ khi bạn có lý do chính đáng để làm như vậy. Và đừng bao giờ trộn chúng với các chú thích từ CDI javax.ejb. Điều này sẽ tạo ra một danh sách vô tận về các lỗi và các điểm bất thường nhỏ.

Nói chung, tôi khuyên bạn nên đọc lướt một vài (hoặc thậm chí nhiều hơn) trang đầu tiên của tài liệu Weld xuất sắc . Điều này sẽ đưa bạn đi đúng hướng cho Java EE 6.

Và vui lòng đăng thêm câu hỏi ở đây.


Thực ra tôi có hai câu hỏi: 1. Tôi thường thấy tầm nhìn rất hữu ích. Tôi cần sử dụng chú thích JSF sau đó? 2. Điều đó có nghĩa @javax.annotation.ManagedBeanlà vô ích vì CDI coi tất cả các lớp như những hạt đậu được quản lý, đúng không?
Piotr Gwiazda

Không hẳn. Bạn sẽ cần kết nối phạm vi JSF với CDI với ví dụ như Seam Faces. Và có, @ManagedBeans không cần thiết nếu bạn có bean.xml trong tệp jar liên quan. Ồ, và nếu bạn có thêm câu hỏi, tốt hơn nên bắt đầu một chủ đề mới trước khi chúng tôi tự giải quyết trong phần bình luận.
jan groth

3

Vì không có câu trả lời cụ thể nào @javax.annotation.ManagedBean, đây là liên kết đến câu trả lời của một câu hỏi tương tự: Đậu hậu (@ManagedBean) hay Đậu CDI (@Named)? . Thông số kỹ thuật có thể được tìm thấy tại http://download.oracle.com/otndocs/jcp/managed_beans-1.0-fr-eval-oth-JSpec/ . Vì vậy, đối với tôi, nó @javax.annotation.ManagedBeancó nghĩa là một sự tổng quát hóa @javax.faces.bean.ManagedBean.

Từ những gì tôi thu thập được, JSF Managed Beans đang bị loại bỏ dần dần để thay thế cho CDI Beans (có thể không còn được chấp nhận từ JSF 2.3?), Vì vậy tôi đoán @javax.annotation.ManagedBeanbây giờ tất cả ngày càng trở nên lỗi thời.


@Namedsẽ thay thế @ManagedBeantrong tương lai?
Thufir

1
Tôi đã đọc một số tuyên bố của các chuyên gia Java EE khác nhau, những người dự đoán rằng các @Namedhạt CDI sẽ thay thế JSF @ManagedBeans, ví dụ: trong stackoverflow.com/questions/4347374/… , BalusC nói "Kỳ vọng là @ManagedBean và bạn bè sẽ không được chấp nhận theo Java EE 8. ”.
Hein Blöd
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.