Chào bạn,
Trong bài học trước, chúng ta đã được giới thiệu về Service Task và các loại thực thi (implementation type) khác nhau của nó. Bạn đã biết sự khác biệt giữa mẫu kiến trúc "push" (engine chủ động gọi code) và "pull" (worker chủ động lấy việc), và đã thực hành cấu hình một Service Task với loại External (mẫu "pull").
Hôm nay, chúng ta sẽ đào sâu vào các loại thực thi theo mẫu "push". Đây là những kỹ thuật cốt lõi khi bạn muốn tích hợp logic nghiệp vụ viết bằng Java chạy ngay bên trong Camunda engine, một kịch bản rất phổ biến trong các ứng dụng Spring Boot.
Mục tiêu của bài học này là giúp bạn sử dụng thành thạo tab 'Properties Panel' để liên kết mô hình BPMN với mã thực thi Java. Cụ thể, chúng ta sẽ khám phá ba cách chính: Java Class, Delegate Expression, và Expression. Nắm vững kỹ năng này là nền tảng để biến những sơ đồ quy trình của bạn từ hình vẽ tĩnh thành các ứng dụng tự động hóa thực sự.
1. Properties Panel: Cầu nối giữa Sơ đồ và Mã nguồn
Hãy bắt đầu bằng cách xác lập lại vai trò của Properties Panel. Với kinh nghiệm là một developer, bạn có thể coi đây là "bảng điều khiển API" cho mỗi phần tử trên sơ đồ BPMN. Nó không chỉ dùng để đặt tên hay viết mô tả. Đây là nơi bạn định nghĩa hành vi thực thi (execution behavior) của quy trình.
Mỗi thuộc tính bạn cấu hình trong panel này—từ Implementation của một Service Task đến Condition của một luồng đi—chính là chỉ thị để Camunda Process Engine biết phải làm gì, gọi đoạn mã nào, hay đưa ra quyết định ra sao tại mỗi bước.
2. Cách 1: Kết nối trực tiếp với Java Class
Đây là phương pháp cơ bản nhất để thực thi mã Java. Bạn sẽ tạo một lớp Java implement interface org.camunda.bpm.engine.delegate.JavaDelegate và sau đó chỉ định tên đầy đủ (fully qualified name) của lớp này trong Properties Panel.
Hãy xem một video hướng dẫn chi tiết từ Camunda để hình dung rõ hơn.
Tutorial: Camunda Enterprise Edition for Java Developers (Video 2)
Video này sẽ chỉ cho bạn toàn bộ quy trình: từ việc viết một lớp Java Delegate đơn giản đến việc kết nối nó với một Service Task trong Camunda Modeler.
Hãy xem các phần sau: Tạo lớp Java Delegate (07:39 - 10:11): Chú ý cách lớp này implement JavaDelegate và ghi đè phương thức execute. Bên trong phương thức này, mã nguồn sử dụng đối tượng DelegateExecution để thiết lập một biến quy trình (process variable) tên là weather với giá trị boolean ngẫu nhiên. Kết nối lớp Java với Service Task (10:11 - 11:04): Đây là bước cốt lõi. Hãy quan sát kỹ cách người hướng dẫn chọn Service Task, mở Properties Panel, chọn 'Java class' làm loại Implementation và dán 'qualified name' (ví dụ: com.camunda.demo.simple_demo.CheckWeather) vào trường tương ứng.
Tóm tắt các bước:
- Viết một lớp Java implement
JavaDelegate. Phương thứcexecute(DelegateExecution execution)là nơi bạn đặt logic nghiệp vụ của mình. - Trong Camunda Modeler, chọn Service Task.
- Trong Properties Panel, tab
General, mụcImplementation, chọnJava Class. - Dán tên đầy đủ của lớp Java (bao gồm cả package) vào trường
Java Class.
- Ưu điểm: Đơn giản, dễ hiểu.
- Nhược điểm: Rất "giòn" (brittle). Nếu bạn tái cấu trúc (refactor) code và di chuyển lớp Java đó sang một package khác, liên kết này sẽ bị hỏng và quy trình của bạn sẽ không chạy được. Điều này dẫn chúng ta đến một phương pháp tốt hơn.
3. Cách 2 (Khuyên dùng): Delegate Expression với Spring
Trong một ứng dụng Spring Boot hiện đại, bạn không quản lý các đối tượng một cách thủ công. Thay vào đó, bạn để Spring container quản lý chúng dưới dạng các beans. Delegate Expression là cách để Camunda tận dụng cơ chế này.
Thay vì chỉ định một đường dẫn lớp cứng, bạn chỉ cần cung cấp một biểu thức trỏ đến một Spring Bean.
Spring Boot + Camunda Service Task Delegate Expression Example
Bài viết này giải thích rất rõ lợi ích của Delegate Expression so với Java Class, đặc biệt trong bối cảnh một dự án Spring Boot.
Hãy đọc kỹ phần 'Implementation'. Chú ý đến hai điểm khác biệt quan trọng: Lớp Java ConfirmationEmailExpressionDelegate được chú thích bằng @Component. Điều này nói cho Spring biết hãy tạo và quản lý một bean từ lớp này. Trong Camunda Modeler, Implementation được đặt là Delegate expression và giá trị là ${confirmationEmailExpressionDelegate}. Cú pháp ${...} và tên bean (thường là tên lớp viết theo kiểu camelCase) là chỉ thị để Camunda yêu cầu Spring cung cấp bean tương ứng khi cần thực thi.
Tại sao đây là cách tốt hơn?
- Tính linh hoạt: Bạn có thể đổi tên package của lớp delegate thoải mái, miễn là tên bean không đổi, quy trình vẫn hoạt động bình thường.
- Tận dụng sức mạnh của Spring: Lớp delegate của bạn giờ là một Spring Bean, nghĩa là bạn có thể tiêm (inject) các bean khác (như services, repositories) vào nó bằng
@Autowired. Điều này làm cho việc tích hợp logic nghiệp vụ trở nên cực kỳ mạnh mẽ và sạch sẽ.

4. Cách 3: Sử dụng Expression cho Logic Đơn giản và Điều kiện
Biểu thức (Expression) là một công cụ cực kỳ linh hoạt, không chỉ dùng cho Service Task. Chúng sử dụng Ngôn ngữ Biểu thức Hợp nhất (JUEL - Java Unified Expression Language).
a) Điều khiển luồng đi với Gateway
Một trong những ứng dụng phổ biến nhất của Expression là để định nghĩa các điều kiện rẽ nhánh sau một Gateway (ví dụ: Exclusive Gateway).
Tutorial: Camunda Enterprise Edition for Java Developers (Video 2)
Bây giờ, hãy quay lại video hướng dẫn trước đó để xem cách Expression được sử dụng để kiểm soát luồng quy trình.
Hãy xem lại đoạn từ 11:04 đến 12:42. Quan sát cách người hướng dẫn cấu hình hai Sequence Flow (đường mũi tên) đi ra từ một Exclusive Gateway: Họ chọn một Sequence Flow. Trong Properties Panel, tab General, họ đặt Condition Type là Expression. Họ viết một biểu thức JUEL đơn giản, ví dụ ${weatherOkay} (kiểm tra biến weatherOkay có giá trị true) hoặc ${!weatherOkay} (kiểm tra biến có giá trị false), để quyết định luồng đi.
Khi quy trình đến Gateway, Camunda engine sẽ duyệt qua từng biểu thức trên các luồng đi ra. Luồng đầu tiên có biểu thức trả về true sẽ được chọn để đi tiếp.
b) Gọi phương thức trực tiếp trong Service Task
Nếu logic nghiệp vụ của bạn chỉ đơn giản là một lời gọi phương thức, bạn có thể dùng Expression ngay trong Service Task thay vì phải tạo một lớp JavaDelegate riêng.
- Cấu hình:
- Chọn
ImplementationlàExpression. - Viết biểu thức gọi đến phương thức của một Spring Bean, ví dụ:
${paymentService.chargeCard(orderId)}.
- Chọn
Trong đó, paymentService là tên của Spring Bean và chargeCard là phương thức bạn muốn gọi. Bạn thậm chí có thể truyền các biến quy trình (orderId) làm tham số.
5. Mở rộng: Liên kết Model với việc Xử lý Lỗi
Để thấy rõ hơn sức mạnh của Properties Panel, hãy xem một ví dụ nâng cao: liên kết một sự kiện trên sơ đồ với việc xử lý lỗi trong mã Java.
Giả sử trong JavaDelegate của bạn, có một trường hợp lỗi nghiệp vụ xảy ra (ví dụ: "khách hàng không đủ tiền"). Bạn có thể ném ra một BPMNError đặc biệt từ code Java:
// Bên trong phương thức execute() của một Java Delegate
if (customer.getBalance() < amount) {
throw new org.camunda.bpm.engine.delegate.BpmNError("INSUFFICIENT_FUNDS");
}
Bây giờ, làm thế nào để sơ đồ BPMN của bạn "bắt" được lỗi này và chuyển hướng quy trình sang một nhánh xử lý khác (ví dụ: gửi email thông báo cho khách hàng)? Câu trả lời lại nằm trong Properties Panel.
Bạn có thể gắn một Error Boundary Event vào Service Task. Sau đó, trong Properties Panel của sự kiện này, bạn cấu hình:
- Error Code:
INSUFFICIENT_FUNDS - Error Message Variable:
errorMessage(tên một biến để lưu thông điệp lỗi)
Camunda Platform 7 Tutorial: Running Timer Events, Catching BPMN Error Events in Spring Boot Project
Chuỗi INSUFFICIENT_FUNDS chính là "sợi dây" liên kết. Khi mã Java ném ra lỗi có mã này, Camunda engine sẽ tìm kiếm trên sơ đồ xem có sự kiện nào đang "lắng nghe" mã lỗi đó không và sẽ kích hoạt nó.
Tổng kết bài học
Hôm nay, bạn đã học được cách sử dụng Properties Panel như một chuyên gia để tạo ra mối liên kết chặt chẽ giữa mô hình BPMN và mã nguồn thực thi. Hãy cùng điểm lại những ý chính:
- Properties Panel là trung tâm chỉ huy để định nghĩa hành vi thực thi của quy trình.
Java Class: Cách liên kết trực tiếp nhưng kém linh hoạt. Chỉ nên dùng trong các trường hợp đơn giản nhất.Delegate Expression: Cách liên kết linh hoạt và mạnh mẽ, tận dụng hệ sinh thái Spring. Đây là phương pháp được khuyến khích cho các dự án Camunda + Spring Boot.Expression: Công cụ đa năng để định nghĩa các điều kiện rẽ nhánh trên Sequence Flow và thực thi các logic đơn giản trong Service Task.- Việc liên kết này không chỉ giới hạn ở Service Task mà còn áp dụng cho Events, Gateways và nhiều thành phần khác để tạo ra các quy trình tự động hóa phức tạp và đáng tin cậy.
Xem trước bài học tiếp theo
Chúng ta đã thiết kế quy trình, thêm các tác vụ, và học cách liên kết chúng với logic nghiệp vụ. Bước tiếp theo một cách tự nhiên là gì? Đó chính là triển khai (deploy) mô hình này lên Camunda engine để nó thực sự "sống".
Trong bài học cuối cùng của module này, bạn sẽ học cách "Deploy một quy trình lên Camunda engine trực tiếp từ Camunda Modeler". Đây là một tính năng tiện lợi giúp bạn nhanh chóng kiểm thử những thay đổi trên mô hình của mình mà không cần phải đóng gói và triển khai lại toàn bộ ứng dụng.