Giới thiệu về Context Dependency Injection trong Jakarta EE

Nếu các bạn đã làm việc với Spring framework thì ắt hẳn nhiều bạn sẽ biết về khái niệm Dependency Injection và cách mà Spring sử dụng khái niệm này để hiện thực framework của mình như thế nào. Jakarta EE cũng định nghĩa một specification tương tự gọi là Context Dependency Injection (CDI) để hiện thực khái niệm Dependency Injection này. Chi tiết về specification này các bạn có thể xem mới nhất ở đây https://jakarta.ee/specifications/cdi/. Jakarta EE CDI cũng định nghĩa một container để chứa các đối tượng phụ thuộc, khi các đối tượng bị phụ thuộc cần sử dụng các đối tượng phụ thuộc này, chúng chỉ cần gọi từ CDI container mà thôi. Trong bài viết này, mình sẽ giới thiệu với các bạn về Context Dependency Injection trong Jakarta EE với một official implementation của nó là thư viện Weld các bạn nhé!

Đầu tiên, mình sẽ tạo mới một Maven project để làm ví dụ:

Thư viện Weld mặc dù implementation cho Jakarta EE CDI nhưng nó cũng có version hỗ trợ cho Java SE. Để đơn giản, mình sẽ sử dụng phiên bản hỗ trợ cho Java SE này. Mình sẽ khai báo Weld dependency cho Java SE như sau:

Mình sẽ tạo mới một class, chỉ đơn giản là in dòng chữ “Hello World”, để có thể tạo mới đối tượng của class này trong CDI container. Nội dung của class này đơn giản như sau:

Các đối tượng được tạo trong Jakarta EE CDI container cũng được gọi là các bean và trong Jakarta EE CDI, mặc định, chúng ta sẽ sử dụng một tập tin tên là beans.xml nằm trong thư mục src/main/resource/META-INF để định nghĩa cơ chế mà Jakarta EE CDI sẽ định nghĩa các bean từ các class là như thế nào. Nội dung của tập tin beans.xml cơ bản như sau:

Thuộc tính quan trọng nhất là bean-discovery-mode định nghĩa cách mà Jakarta EE CDI sẽ tạo bean từ các Java class là như thế nào đó các bạn. Có 3 giá trị cho thuộc tính bean-discovery-mode này là:

  • annotated: chỉ khởi tạo các Java class được annotate với các annotation của Jakarta EE CDI.
  • all: khởi tạo tất cả các Java class trong CDI container.
  • none: không làm gì cả.

Mặc định nếu chúng ta không khai báo thuộc tính bean-discovery-mode thì giá trị của bean-discovery-mode là “annotated” từ phiên bản CDI 4.0 các bạn nhé!

Các annotations được định nghĩa của Jakarta EE CDI bao gồm:

  • Annotation @ApplicationScoped
  • Annotation @RequestScoped
  • Annotation @Interceptor
  • Tất cả các annotations được annotate với annotation @Stereotype
  • Annotation @Dependent

Để đơn giản, mình sẽ chỉ đề cập và sử dụng annotation @ApplicationScoped để làm ví dụ cho bài viết này.

Nói nôm na thì annotation @ApplicationScoped sẽ chỉ định bean được tạo bởi class được annotate với annotation này sẽ chỉ được khởi tạo một lần duy nhất trong ứng dụng. Giống như class hiện thực Singleton design pattern vậy các bạn!

Mình sẽ annotate class SayHello với annotation @ApplicationScoped như sau:

Bây giờ, chúng ta sẽ sử dụng class Main với main() method, định nghĩa CDI container class để lấy bean của class SayHello ra xem sao các bạn nhé!

Jakarta EE CDI định nghĩa interface SeContainer đóng vai trò là một CDI container và chúng ta sử dụng class SeContainerInitializer để khởi tạo CDI container này như sau:

Implementation của thư viện Weld cho class SeContainer là class WeldContainer và class SeContainerInitializer là class Weld các bạn nhé! Class Weld sẽ đọc nội dung của tập tin beans.xml trong thư mục src/main/resources/META-INF để cấu hình cho CDI container.

Chúng ta sẽ sử dụng phương thức select() của class SeContainer để lấy bean của class SayHello trong CDI container và gọi phương thức say() của class SayHello này như sau:

Kết quả:

Add Comment