![]() | |
| • | Table of Contents |
| Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions | ||
| By Gregor Hohpe, Bobby Woolf | ||
![]() | ||
| Publisher | : Addison Wesley | |
| Pub Date | : October 10, 2003 | |
| ISBN | : 0-321-20068-3 | |
| Pages | : 736 | |
Bạn có muốn sử dụng một ký hiệu trực quan nhất quán để vẽ các giải pháp tích hợp không? Hãy xem bên trong bìa trước.
Bạn có muốn khai thác sức mạnh của các hệ thống bất đồng bộ mà không bị sa vào các cạm bẫy không? Hãy xem "Suy nghĩ Bất đồng bộ" trong phần Giới thiệu.
Bạn có muốn biết kiểu tích hợp ứng dụng nào là tốt nhất cho mục đích của bạn không? Hãy xem Chương 2, Các phong cách tích hợp.
Bạn có muốn học các kỹ thuật để xử lý tin nhắn đồng thời không? Xem Chương 10, Người tiêu dùng cạnh tranh và Bộ điều phối tin nhắn.
Bạn có muốn biết cách theo dõi các tin nhắn bất đồng bộ khi chúng di chuyển qua các hệ thống phân tán không? Hãy xem Chương 11, Lịch sử Tin nhắn và Kho Tin nhắn.
Bạn có muốn hiểu cách một hệ thống được thiết kế bằng các mẫu tích hợp có thể được triển khai bằng dịch vụ web Java, hệ thống hàng đợi tin nhắn .NET và kiến trúc công bố-đăng ký dựa trên TIBCO không? Xem Chương 9, Giữa chương: Nhắn tin hợp thành.
Sử dụng nhiều năm kinh nghiệm thực tiễn, các chuyên gia giàu kinh nghiệm Gregor Hohpe và Bobby Woolf chỉ ra rằng việc sử dụng nhắn tin bất đồng bộ đã chứng tỏ là chiến lược tốt nhất cho sự thành công trong tích hợp doanh nghiệp. Tuy nhiên, việc xây dựng và triển khai các giải pháp nhắn tin gặp phải một số vấn đề cho các nhà phát triển. Các Mẫu Tích Hợp Doanh Nghiệp cung cấp một danh mục quý giá gồm sáu mươi lăm mẫu, với các giải pháp thực tế minh họa cho sức mạnh của nhắn tin và giúp bạn thiết kế các giải pháp nhắn tin hiệu quả cho doanh nghiệp của mình.
Các tác giả cũng bao gồm các ví dụ về nhiều công nghệ tích hợp khác nhau, chẳng hạn như JMS, MSMQ, TIBCO ActiveEnterprise, Microsoft BizTalk, SOAP và XSL. Một nghiên cứu trường hợp mô tả một hệ thống giao dịch trái phiếu minh họa các mẫu trong thực tế, và cuốn sách cung cấp cái nhìn về các tiêu chuẩn đang nổi lên, cũng như những hiểu biết về tương lai của tích hợp doanh nghiệp có thể như thế nào.
Cuốn sách này cung cấp một từ vựng và khung ghi chú trực quan nhất quán để mô tả các giải pháp tích hợp quy mô lớn trên nhiều công nghệ khác nhau. Nó cũng khám phá chi tiết những lợi ích và hạn chế của kiến trúc nhắn tin không đồng bộ. Các tác giả đưa ra lời khuyên thực tiễn về thiết kế mã kết nối một ứng dụng với hệ thống nhắn tin, và cung cấp thông tin phong phú để giúp bạn xác định khi nào nên gửi tin nhắn, cách định tuyến nó đến đích đúng và cách theo dõi tình trạng của hệ thống nhắn tin. Nếu bạn muốn biết cách quản lý, giám sát và duy trì một hệ thống nhắn tin khi nó đã được sử dụng, hãy sở hữu cuốn sách này.
![]() | |
| • | Table of Contents |
| Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions | ||
| By Gregor Hohpe, Bobby Woolf | ||
![]() | ||
| Publisher | : Addison Wesley | |
| Pub Date | : October 10, 2003 | |
| ISBN | : 0-321-20068-3 | |
| Pages | : 736 | |
Nhiều trong số các tên gọi được sử dụng bởi các nhà sản xuất và người bán để phân biệt sản phẩm của họ được xem là nhãn hiệu. Khi các tên gọi đó xuất hiện trong cuốn sách này, và Addison-Wesley biết về việc có yêu cầu nhãn hiệu, các tên gọi đã được in bằng chữ cái đầu tên viết hoa hoặc in tất cả chữ hoa.
Các tác giả và nhà xuất bản đã cẩn thận trong việc chuẩn bị cuốn sách này, nhưng không đưa ra bất kỳ bảo đảm nào, rõ ràng hay ngụ ý, và không chịu trách nhiệm về các lỗi hoặc thiếu sót. Không có trách nhiệm nào được nhận cho các thiệt hại phát sinh ngẫu nhiên hoặc hậu quả liên quan đến hoặc phát sinh từ việc sử dụng thông tin hoặc chương trình có trong cuốn sách này.
Nhà xuất bản cung cấp giảm giá cho cuốn sách này khi đặt hàng với số lượng lớn và trong các đợt bán hàng đặc biệt. Để biết thêm thông tin, vui lòng liên hệ:
Bán hàng cho Doanh nghiệp và Chính phủ Hoa Kỳ (800) 382-3419 corpsales@pearsontechgroup.com
Để bán hàng ngoài Hoa Kỳ, vui lòng liên hệ:
Bán hàng quốc tế (317) 581-3793 international@pearsontechgroup.com
Truy cập Addison-Wesley trên web: www.awprofessional.com
Dữ liệu phân loại xuất bản của Thư viện Quốc hội
Hohpe, Gregor. Mô hình tích hợp doanh nghiệp: thiết kế, xây dựng và triển khai giải pháp nhắn tin / Gregor Hohpe, Bobby Woolf. p. cm. Bao gồm tài liệu tham khảo và chỉ mục. ISBN 0-321-20068-3 1. Xử lý thông điệp viễn thông. 2. Hệ thống thông tin quản lý. I. Woolf, Bobby. II. Tiêu đề. TK5102.5.H5882 2003 005.7'136 dc22 2003017989
Bản quyền © 2004 bởi Pearson Education, Inc.
Tất cả các quyền được bảo lưu. Không phần nào của ấn phẩm này được phép sao chép, lưu trữ trong hệ thống truy xuất, hoặc truyền tải, dưới bất kỳ hình thức nào, hoặc bằng bất kỳ phương tiện nào, điện tử, cơ khí, sao chép, ghi âm, hoặc bằng cách khác, mà không có sự đồng ý trước của nhà xuất bản. In tại Hoa Kỳ. Xuất bản đồng thời tại Canada.
Để biết thông tin về việc xin phép sử dụng tài liệu từ công trình này, xin vui lòng gửi yêu cầu bằng văn bản đến:
Công ty Giáo dục Pearson, Bộ phận Quyền lợi và Hợp đồng, 75 Phố Arlington, Suite 300, Boston, MA 02116, Fax: (617) 848-7047
Văn bản in trên giấy tái chế
Một hai ba bốn năm sáu bảy tám chín mười CRS0706050403
Lần in đầu tiên, tháng 10 năm 2003
Đến gia đình tôi và tất cả bạn bè vẫn nhớ đến tôi sau khi tôi thoát ra từ "chế độ nghiền sách".
Gregor
Gửi Sharon, vợ mới của tôi
Bobby
Chuỗi sách Addison-Wesley Signature cung cấp cho người đọc thông tin thực tiễn và uy tín về các xu hướng mới nhất trong công nghệ hiện đại cho các chuyên gia máy tính. Chuỗi sách dựa trên một giả định đơn giản: những cuốn sách tuyệt vời đến từ những tác giả vĩ đại. Các cuốn sách trong chuỗi được lựa chọn cá nhân bởi các cố vấn chuyên gia, những tác giả hàng đầu thế giới trong lĩnh vực của họ. Những chuyên gia này tự hào đặt chữ ký của họ trên các bìa sách, và chữ ký của họ đảm bảo rằng những người dẫn dắt tư tưởng này đã làm việc chặt chẽ với các tác giả để xác định phạm vi chủ đề, nội dung quan trọng và sự độc đáo tổng thể. Chữ ký của các chuyên gia cũng tượng trưng cho một lời hứa đối với độc giả của chúng tôi: bạn đang đọc một tác phẩm kinh điển trong tương lai.
Chuỗi Chữ ký Addison-Wesley
"Người ký: KENT BECK VÀ MARTIN FOWLER"
Kent Beck đã tiên phong trong việc phát triển các công nghệ hướng tới con người như JUnit, Lập trình cực đoan và các mẫu cho phát triển phần mềm. Kent quan tâm đến việc giúp các nhóm hoạt động tốt bằng cách làm điều tốt, tìm kiếm một phong cách phát triển phần mềm mà simultanously đáp ứng các ràng buộc kinh tế, thẩm mỹ, cảm xúc và thực tiễn. Các cuốn sách của ông tập trung vào việc chạm đến cuộc sống của những người sáng tạo và người sử dụng phần mềm.
Martin Fowler là một nhà tiên phong trong công nghệ đối tượng trong các ứng dụng doanh nghiệp. Mối quan tâm chính của ông là cách thiết kế phần mềm một cách tốt nhất. Ông tập trung vào việc đi sâu vào cốt lõi của cách xây dựng phần mềm doanh nghiệp có thể tồn tại lâu dài trong tương lai. Ông quan tâm đến việc nhìn ra phía sau các công nghệ cụ thể để tìm hiểu các mô hình, thực tiễn và nguyên tắc tồn tại trong nhiều năm; những cuốn sách này nên có thể sử dụng được trong một thập kỷ nữa. Tiêu chí của Martin là những cuốn sách này là những gì ông ước có thể viết.
Tiêu đề trong loạt sách

Phát Triển Theo Hướng Kiểm Tra: Thông Qua Ví Dụ Kent Beck, ISBN: 0321146530

Mô hình kiến trúc ứng dụng doanh nghiệp Martin Fowler, ISBN: 0321127420
Ngoài Kiến Trúc Phần Mềm: Tạo Ra và Duy Trì Giải Pháp Thành Công Luke Hohmann, ISBN: 0201775948
Mô hình Tích hợp Doanh nghiệp: Thiết kế, Xây dựng và Triển khai Giải pháp Nhắn tin Gregor Hohpe và Bobby Woolf, ISBN: 0321200683
Để biết thêm thông tin, hãy truy cập trang web của loạt bài tại www.awprofessional.com.
bởi John Crupi
Bạn sẽ làm gì khi một công nghệ mới xuất hiện? Bạn học công nghệ đó. Đây chính xác là những gì tôi đã làm. Tôi đã nghiên cứu J2EE (vì nó từ Sun Microsystems, nên đó có vẻ là lựa chọn hợp lý). Cụ thể, tôi đã tập trung vào công nghệ EJB bằng cách đọc các tài liệu kỹ thuật (vì chưa có sách nào cả). Tuy nhiên, việc học công nghệ chỉ là bước đầu tiên - mục tiêu thực sự là học cách áp dụng công nghệ một cách hiệu quả. Điều tuyệt vời về các công nghệ nền tảng là chúng khiến bạn phải thực hiện những nhiệm vụ nhất định. Nhưng, về phần công nghệ, bạn có thể làm bất cứ điều gì bạn muốn và thường thì bạn sẽ gặp rắc rối nếu không làm mọi thứ một cách thích hợp.
Một điều tôi đã thấy trong 15 năm qua là có vẻ như có hai lĩnh vực mà các nhà phát triển phần mềm rất đam mê: lập trình và thiết kế, hoặc chính xác hơn là lập trình và thiết kế hiệu quả. Có nhiều cuốn sách tuyệt vời nói về cách lập trình hiệu quả cho một số thứ nhất định trong Java và C#, nhưng ít cuốn sách nói về cách thiết kế hiệu quả. Đó là lý do cuốn sách này ra đời. Khi Deepak Alur, Dan Malks và tôi viết cuốn Core J2EE Patterns, chúng tôi muốn giúp các nhà phát triển J2EE "thiết kế" mã tốt hơn. Quyết định tốt nhất mà chúng tôi đã đưa ra là sử dụng mẫu thiết kế làm hiện vật lựa chọn. Như James Baty, một Kỹ sư Danh dự của Sun, đã nói, "Các mẫu thiết kế dường như là điểm ngọt trong thiết kế." Tôi hoàn toàn đồng ý, và may mắn cho chúng tôi, Gregor và Bobby cũng cảm thấy như vậy.
Cuốn sách này tập trung vào một chủ đề nóng và đang phát triển: tích hợp thông qua giao tiếp. Không chỉ giao tiếp là yếu tố then chốt cho việc tích hợp, mà nó cũng sẽ trở thành trọng tâm chính trong dịch vụ Web trong nhiều năm tới. Hiện nay có rất nhiều thông tin hỗn loạn trong thế giới dịch vụ Web, thật khó khăn và phức tạp chỉ để xác định các thông số kỹ thuật và công nghệ cần tập trung vào. Tuy nhiên, mục tiêu vẫn không thay đổi, đó là phần mềm giúp bạn giải quyết một vấn đề. Cũng giống như trong những ngày đầu của J2EE và .NET, vẫn chưa có nhiều hỗ trợ thiết kế cho dịch vụ Web. Nhiều người nói rằng dịch vụ Web chỉ là một cách mới và mở để giải quyết các vấn đề tích hợp hiện có của chúng ta và tôi đồng ý. Nhưng điều đó không có nghĩa là chúng ta biết cách thiết kế dịch vụ Web. Và điều đó đưa chúng ta đến điểm quan trọng của cuốn sách này. Tôi tin rằng cuốn sách này có nhiều mẫu mà chúng ta cần để thiết kế dịch vụ Web và các hệ thống tích hợp khác. Bởi vì các thông số kỹ thuật dịch vụ Web vẫn đang trong quá trình cạnh tranh, nên sẽ không hợp lý nếu Bobby và Gregor cung cấp ví dụ về nhiều thông số kỹ thuật dịch vụ Web. Nhưng, điều đó không sao cả. Phần thưởng thực sự sẽ đến khi các thông số kỹ thuật trở thành tiêu chuẩn và chúng ta sử dụng các mẫu trong cuốn sách này để thiết kế cho các giải pháp được hiện thực hóa bởi những tiêu chuẩn đó. Sau đó, có thể chúng ta có thể đạt được mục tiêu tích hợp tiếp theo của mình là thiết kế cho kiến trúc hướng dịch vụ.
Đọc cuốn sách này và giữ nó bên cạnh bạn. Nó sẽ nâng cao sự nghiệp phần mềm của bạn một cách không giới hạn.
John Crupi Bethesda, MD Tháng 8 năm 2003
bởi Martin Fowler
Trong khi tôi đang làm việc trên cuốn sách "Patterns of Enterprise Application Architecture", tôi đã may mắn nhận được một số đánh giá sâu sắc từ Kyle Brown và Rachel Reinitz ở một số buổi hội thảo không chính thức tại văn phòng của Kyle ở Raleigh-Durham. Trong các phiên họp này, chúng tôi nhận ra rằng một khoảng trống lớn trong công việc của tôi là hệ thống nhắn tin bất đồng bộ.
Trong cuốn sách của tôi có nhiều khoảng trống, và tôi chưa từng có ý định biến nó thành một bộ sưu tập hoàn chỉnh các mẫu cho phát triển doanh nghiệp. Nhưng khoảng trống về nhắn tin bất đồng bộ đặc biệt quan trọng vì chúng tôi tin rằng nhắn tin bất đồng bộ sẽ đóng vai trò ngày càng quan trọng trong phát triển phần mềm doanh nghiệp, đặc biệt là trong tích hợp. Tích hợp quan trọng vì các ứng dụng không thể sống tách biệt với nhau. Chúng ta cần các kỹ thuật cho phép chúng ta kết hợp các ứng dụng chưa bao giờ được thiết kế để tương tác và phá vỡ các rào cản để chúng ta có thể thu được lợi ích lớn hơn so với những gì mà các ứng dụng riêng lẻ có thể cung cấp.
Nhiều công nghệ đã xuất hiện hứa hẹn giải quyết bài toán tích hợp. Tất cả chúng tôi đã kết luận rằng nhắn tin là công nghệ mang lại nhiều triển vọng nhất. Thách thức mà chúng tôi gặp phải là truyền đạt cách làm nhắn tin một cách hiệu quả. Thách thức lớn nhất trong việc này là nhắn tin về bản chất là bất đồng bộ, và có những khác biệt đáng kể trong các phương pháp thiết kế mà bạn sử dụng trong một thế giới bất đồng bộ.
Tôi không có đủ không gian, năng lượng, hoặc frankly là kiến thức để đề cập đúng cách về chủ đề này trong Patterns of Enterprise Application Architecture. Nhưng chúng tôi đã tìm ra một giải pháp tốt hơn để lấp đầy khoảng trống này: tìm một người khác có thể. Chúng tôi đã tìm tới Gregor và Bobby, và họ đã nhận lời thách thức. Kết quả là cuốn sách mà bạn sắp đọc.
Tôi rất hài lòng với công việc mà họ đã thực hiện. Nếu bạn đã từng làm việc với các hệ thống nhắn tin, cuốn sách này sẽ hệ thống hóa nhiều kiến thức mà bạn và những người khác đã học được một cách khó khăn. Nếu bạn sắp làm việc với các hệ thống nhắn tin, cuốn sách này sẽ cung cấp một nền tảng vô giá bất kể bạn phải làm việc với công nghệ nhắn tin nào.
Martin Fowler Melrose, MA Tháng 8 năm 2003
Đây là một cuốn sách về tích hợp doanh nghiệp sử dụng tin nhắn. Nó không tài liệu hóa bất kỳ công nghệ hoặc sản phẩm cụ thể nào. Thay vào đó, nó được thiết kế cho các nhà phát triển và nhà tích hợp sử dụng nhiều sản phẩm và công nghệ tin nhắn khác nhau, chẳng hạn như.
Phần mềm trung gian dựa trên tin nhắn (MOM) và các bộ giải pháp EAI được cung cấp bởi các nhà cung cấp như IBM (WebSphere MQ Family), Microsoft (BizTalk), TIBCO, WebMethods, SeeBeyond, Vitria và những công ty khác.
Java Message Service (JMS) được tích hợp vào các máy chủ ứng dụng J2EE thương mại và mã nguồn mở cũng như các sản phẩm độc lập.
Hàng đợi tin nhắn của Microsoft (MSMQ), có thể truy cập thông qua một số API, bao gồm các thư viện System.Messaging trong Microsoft .NET.
Các tiêu chuẩn dịch vụ web mới nổi hỗ trợ dịch vụ web bất đồng bộ (chẳng hạn như WS-ReliableMessaging) và các API liên quan như API Java cho Tin nhắn XML (JAXM) của Sun Microsystems hoặc Các Mở rộng Dịch vụ Web (WSE) của Microsoft.
Hội nhập doanh nghiệp vượt ra ngoài việc tạo ra một ứng dụng đơn lẻ với kiến trúc n-tier phân tán, cho phép một ứng dụng duy nhất được phân phối trên nhiều máy tính. Trong khi một tầng trong một ứng dụng phân tán không thể chạy độc lập, các ứng dụng đã được tích hợp là những chương trình độc lập có thể chạy riêng lẻ, nhưng hoạt động bằng cách phối hợp với nhau theo cách lỏng lẻo. Messaging cho phép nhiều ứng dụng trao đổi dữ liệu hoặc lệnh qua mạng bằng cách sử dụng phương pháp "gửi và quên". Điều này cho phép người gọi gửi thông tin và ngay lập tức chuyển sang công việc khác trong khi thông tin được truyền đi bởi hệ thống nhắn tin. Tùy chọn, người gọi có thể sau đó được thông báo về kết quả qua một cuộc gọi lại. Các cuộc gọi không đồng bộ và cuộc gọi lại có thể làm cho thiết kế phức tạp hơn so với phương pháp đồng bộ, nhưng một cuộc gọi không đồng bộ có thể được thử lại cho đến khi thành công, điều này làm cho việc giao tiếp đáng tin cậy hơn nhiều. Nhắn tin không đồng bộ cũng cho phép một số lợi ích khác, chẳng hạn như kiểm soát lưu lượng yêu cầu và cân bằng tải.
Cuốn sách này được thiết kế để giúp các nhà phát triển ứng dụng và các nhà tích hợp hệ thống kết nối các ứng dụng bằng cách sử dụng các công cụ tích hợp dựa trên tin nhắn.
Các kiến trúc sư ứng dụng và nhà phát triển thiết kế và xây dựng các ứng dụng doanh nghiệp phức tạp cần tích hợp với các ứng dụng khác. Chúng tôi giả định rằng bạn đang phát triển ứng dụng của mình bằng một nền tảng ứng dụng doanh nghiệp hiện đại như Java 2 Platform, Enterprise Edition (J2EE) hoặc Microsoft .NET Framework. Cuốn sách này sẽ giúp bạn kết nối ứng dụng với một lớp nhắn tin và trao đổi thông tin với các ứng dụng khác. Cuốn sách này tập trung vào việc tích hợp các ứng dụng, không phải là xây dựng ứng dụng; vì điều đó, chúng tôi giới thiệu cho bạn cuốn Patterns of Enterprise Application Architecture của Martin Fowler.
Các kiến trúc sư và nhà phát triển tích hợp thiết kế và xây dựng các giải pháp tích hợp kết nối các ứng dụng đóng gói hoặc tùy chỉnh. Hầu hết độc giả trong nhóm này sẽ có kinh nghiệm với một trong nhiều công cụ tích hợp thương mại như IBM WebSphere MQ, TIBCO, WebMethods, SeeBeyond hoặc Vitria, cái mà bao gồm nhiều mẫu được trình bày trong cuốn sách này. Cuốn sách này giúp bạn hiểu các khái niệm cơ bản và đưa ra các quyết định thiết kế tự tin bằng cách sử dụng từ vựng độc lập với nhà cung cấp.
Các kiến trúc sư doanh nghiệp phải duy trì cái nhìn "tổng thể" về các tài sản phần mềm và phần cứng trong một doanh nghiệp. Cuốn sách này trình bày một từ vựng nhất quán và ký hiệu đồ họa để mô tả các giải pháp tích hợp quy mô lớn có thể trải rộng trên nhiều công nghệ hoặc giải pháp điểm. Ngôn ngữ này cũng là một yếu tố then chốt để tạo điều kiện cho việc giao tiếp hiệu quả giữa kiến trúc sư doanh nghiệp và các kiến trúc sư, nhà phát triển tích hợp và ứng dụng.
Cuốn sách này không cố gắng đưa ra lý do kinh doanh cho việc tích hợp ứng dụng doanh nghiệp; trọng tâm là làm thế nào để thực hiện nó. Bạn sẽ học cách tích hợp các ứng dụng doanh nghiệp bằng cách hiểu những điều sau đây:
Lợi ích và hạn chế của việc nhắn tin không đồng bộ so với các kỹ thuật tích hợp khác.
Làm thế nào để xác định các kênh tin nhắn mà ứng dụng của bạn cần, cách kiểm soát xem có thể có nhiều người tiêu dùng nhận cùng một tin nhắn hay không, và cách xử lý các tin nhắn không hợp lệ.
Khi nào gửi một tin nhắn, nó nên chứa đựng những gì, và cách sử dụng các thuộc tính tin nhắn đặc biệt.
"Cách để chuyển một tin nhắn đến điểm đến cuối cùng ngay cả khi người gửi không biết đó là đâu."
Cách chuyển đổi thông điệp khi người gửi và người nhận không đồng ý về một định dạng chung.
Cách thiết kế mã kết nối một ứng dụng với hệ thống nhắn tin.
Cách quản lý và theo dõi một hệ thống nhắn tin khi nó đã được sử dụng trong doanh nghiệp.
Chúng tôi tin rằng bất kỳ cuốn sách nào có từ "doanh nghiệp" trong tiêu đề đều có khả năng rơi vào một trong ba loại. Đầu tiên, cuốn sách có thể cố gắng đề cập toàn bộ chiều rộng của lĩnh vực nhưng buộc phải dừng lại trước những hướng dẫn chi tiết về cách thực hiện các giải pháp thực tế. Thứ hai, cuốn sách có thể cung cấp hướng dẫn cụ thể về việc phát triển các giải pháp thực tế nhưng buộc phải hạn chế phạm vi của lĩnh vực mà nó đề cập. Thứ ba, cuốn sách có thể cố gắng làm cả hai điều nhưng có khả năng sẽ không bao giờ hoàn thành hoặc được phát hành quá muộn đến mức trở nên không còn liên quan. Chúng tôi đã chọn lựa chọn thứ hai và hy vọng tạo ra một cuốn sách giúp mọi người tạo ra các giải pháp tích hợp tốt hơn mặc dù chúng tôi đã phải hạn chế phạm vi của cuốn sách. Các chủ đề mà chúng tôi rất muốn thảo luận nhưng đã phải loại trừ để không rơi vào cái bẫy loại ba bao gồm bảo mật, lập bản đồ dữ liệu phức tạp, quy trình làm việc, động cơ quy tắc, khả năng mở rộng và độ bền cũng như xử lý giao dịch phân tán (XA, Tuxedo, và tương tự). Chúng tôi đã chọn nhắn tin bất đồng bộ làm trọng tâm của cuốn sách này vì nó đầy những vấn đề thiết kế thú vị và các cân nhắc, đồng thời cung cấp một sự trừu tượng rõ ràng từ nhiều sự triển khai được cung cấp bởi các nhà cung cấp tích hợp khác nhau.
Cuốn sách này cũng không phải là một hướng dẫn về một công nghệ nhắn tin hoặc phần mềm trung gian cụ thể. Để nhấn mạnh tính ứng dụng rộng rãi của các khái niệm được trình bày trong cuốn sách này, chúng tôi đã bao gồm các ví dụ dựa trên một số công nghệ khác nhau, chẳng hạn như JMS, MSMQ, TIBCO, BizTalk và XSL. Tuy nhiên, chúng tôi tập trung vào các quyết định thiết kế và sự đánh đổi, thay vì các chi tiết cụ thể của công cụ. Nếu bạn quan tâm đến việc tìm hiểu thêm về bất kỳ công nghệ cụ thể nào trong số này, xin vui lòng tham khảo một trong những cuốn sách được đề cập trong tài liệu tham khảo hoặc một trong nhiều tài nguyên trực tuyến.
Như tiêu đề đã gợi ý, phần lớn cuốn sách này gồm một bộ sưu tập các mẫu. Các mẫu là một cách đã được chứng minh để ghi lại kiến thức của các chuyên gia trong các lĩnh vực mà không có câu trả lời đơn giản "một kích cỡ phù hợp với tất cả", chẳng hạn như kiến trúc ứng dụng, thiết kế hướng đối tượng, hoặc các giải pháp tích hợp dựa trên kiến trúc nhắn tin không đồng bộ.
Mỗi mẫu thiết kế đặt ra một vấn đề thiết kế cụ thể, thảo luận về các yếu tố liên quan đến vấn đề đó, và trình bày một giải pháp thanh lịch cân bằng các lực lượng hoặc động lực khác nhau. Trong hầu hết các trường hợp, giải pháp không phải là cách tiếp cận đầu tiên nảy ra trong đầu, mà là một giải pháp đã phát triển thông qua việc sử dụng thực tế theo thời gian. Kết quả là, mỗi mẫu trong số này kết hợp kinh nghiệm mà các nhà phát triển tích hợp và kiến trúc sư cấp cao đã thu được từ việc xây dựng giải pháp lặp đi lặp lại và học từ những sai lầm của họ. Điều này ngụ ý rằng chúng tôi không "phát minh" ra các mẫu trong cuốn sách này; các mẫu không được phát minh, mà được phát hiện và quan sát từ thực tiễn thực tế trong lĩnh vực.
Bởi vì các mẫu được thu thập từ việc sử dụng thực tế của những người thực hành, có khả năng rằng nếu bạn đã làm việc với các công cụ tích hợp doanh nghiệp và kiến trúc nhắn tin bất đồng bộ một thời gian, nhiều mẫu trong cuốn sách này sẽ có vẻ quen thuộc với bạn. Tuy nhiên, ngay cả khi bạn đã nhận ra hầu hết các mẫu này, vẫn có giá trị trong việc xem xét lại cuốn sách này. Cuốn sách này nên xác thực sự hiểu biết đáng giá mà bạn đã tích lũy được về cách sử dụng nhắn tin trong khi ghi lại chi tiết của các giải pháp và mối quan hệ giữa chúng mà bạn có thể chưa nhận thức được. Nó cũng cung cấp cho bạn một tài liệu tham khảo tập hợp để giúp bạn truyền đạt kiến thức của mình một cách hiệu quả cho những đồng nghiệp ít kinh nghiệm hơn. Cuối cùng, các tên mẫu cung cấp cho bạn một từ vựng chung để thảo luận hiệu quả về các lựa chọn thiết kế tích hợp với đồng nghiệp của bạn.
Các mẫu trong cuốn sách này áp dụng cho nhiều ngôn ngữ lập trình và nền tảng khác nhau. Điều này có nghĩa là một mẫu không phải là một đoạn mã cắt và dán sẵn, mà bạn cần phải điều chỉnh một mẫu cho môi trường cụ thể của bạn. Để việc chuyển dịch này trở nên dễ dàng hơn, chúng tôi đã thêm nhiều ví dụ khác nhau cho thấy các cách thực hiện mẫu bằng cách sử dụng các công nghệ phổ biến như JMS, MSMQ, TIBCO, BizTalk, XSL và những công nghệ khác. Chúng tôi cũng đã bao gồm một vài ví dụ lớn hơn để chứng minh cách mà nhiều mẫu cùng phối hợp với nhau để tạo thành một giải pháp nhất quán.
Việc tích hợp nhiều ứng dụng bằng cách sử dụng kiến trúc nhắn tin không đồng bộ là một lĩnh vực đầy thách thức và thú vị. Chúng tôi hy vọng bạn sẽ thích đọc cuốn sách này như chúng tôi đã thích viết nó.
Chủ đề chung cho các cuốn sách trong Dòng Chữ Ký Martin Fowler là hình ảnh một cây cầu. Theo một cách nào đó, chúng tôi đã gặp may, vì chủ đề nào phù hợp hơn cho một cuốn sách về tích hợp? Hàng ngàn năm qua, những cây cầu đã giúp kết nối mọi người từ những bờ biển khác nhau, núi non, và hai bên đường.
Chúng tôi đã chọn một bức tranh của cầu Taiko-bashi tại đền Sumiyoshi-taisha ở Osaka, Nhật Bản, vì sự thanh lịch và vẻ đẹp đơn giản của nó. Là một đền thờ Thần Đạo dành cho vị thần bảo vệ cho những người đi biển, nó ban đầu được xây dựng bên cạnh mặt nước. Thú vị là, việc bồi đắp đất đã đẩy mặt nước xa ra, khiến cho đền ngày nay đứng cách xa gần ba dặm trong nội địa. Khoảng ba triệu người ghé thăm đền này vào đầu năm mới.
Gregor Hohpe San Francisco, California Bobby Woolf Raleigh, North Carolina Tháng Chín 2003 www.doanhnghiepchihuong.com
Bảng Tiên Phong của Tiến sĩ Carl Sagan
Thông điệp gửi đến các hình thức sự sống ngoài trái đất.

Giống như hầu hết các cuốn sách khác, "Mô Hình Tích Hợp Doanh Nghiệp" đã mất nhiều thời gian để hình thành. Ý tưởng viết về các mô hình tích hợp dựa trên tin nhắn bắt đầu từ mùa hè năm 2001 khi Martin Fowler đang làm việc với "Mô Hình Kiến Trúc Ứng Dụng Doanh Nghiệp" (P of EAA). Vào thời điểm đó, Kyle Brown nhận thấy rằng, mặc dù P of EAA đã đề cập nhiều về cách tạo ra ứng dụng, nhưng chỉ đề cập một cách ngắn gọn về cách tích hợp chúng. Ý tưởng này là điểm khởi đầu cho một loạt các cuộc họp giữa Martin và Kyle, trong đó cũng có sự tham gia của Rachel Reinitz, John Crupi và Mark Weitzel. Bobby tham gia vào những cuộc thảo luận này vào mùa thu năm 2001, tiếp theo là Gregor vào đầu năm 2002. Vào mùa hè tiếp theo, nhóm đã gửi hai bài báo để xem xét tại hội nghị "Ngôn Ngữ Mô Hình của Các Chương Trình" (PLoP), một bài do Bobby và Kyle đồng tác giả và bài còn lại do Gregor viết. Sau hội nghị, Kyle và Martin đã tập trung lại vào các dự án sách của riêng họ trong khi Gregor và Bobby đã hợp nhất các bài báo của họ để hình thành cơ sở cho cuốn sách. Cùng thời điểm đó, trang web www.enterpriseintegrationpatterns.com chính thức hoạt động để cho phép các kiến trúc sư và nhà phát triển tích hợp trên toàn thế giới tham gia vào sự tiến hóa nhanh chóng của nội dung. Khi họ làm việc trên cuốn sách, Gregor và Bobby đã mời các cách đóng góp tham gia vào việc tạo ra cuốn sách. Khoảng hai năm sau ý tưởng ban đầu của Kyle, bản thảo cuối cùng đã đến tay nhà xuất bản.
Cuốn sách này là kết quả của một nỗ lực cộng đồng với sự tham gia của rất nhiều người. Nhiều đồng nghiệp và bạn bè (nhiều người trong số họ mà chúng tôi gặp thông qua nỗ lực viết sách) đã cung cấp ý tưởng cho các ví dụ, đảm bảo độ chính xác của nội dung kỹ thuật, và đã cho chúng tôi những phản hồi và phê bình cần thiết. Sự đóng góp của họ đã ảnh hưởng lớn đến hình thức và nội dung cuối cùng của cuốn sách. Chúng tôi rất vui mừng được công nhận những đóng góp của họ và bày tỏ sự trân trọng đối với nỗ lực của họ.
Kyle Brown và Martin Fowler xứng đáng được nhắc đến đặc biệt vì đã đặt nền tảng cho cuốn sách này. Cuốn sách này có thể đã không bao giờ được viết ra nếu không có việc Martin viết cuốn P of EAA và Kyle thành lập một nhóm để thảo luận về các mẫu giao tiếp nhằm bổ sung cho cuốn sách của Martin.
Chúng tôi đã rất may mắn khi có nhiều tác giả đóng góp những phần quan trọng của cuốn sách: Conrad F. D'Cruz, Sean Neville, Michael J. Rettig và Jonathan Simon. Các chương của họ hoàn thiện cuốn sách với những góc nhìn bổ sung về cách mà các mô hình hoạt động trong thực tế.
Các thành viên tham gia hội thảo viết của chúng tôi tại hội nghị PLoP 2002 là những người đầu tiên cung cấp phản hồi chất lượng về tài liệu, giúp chúng tôi đi đúng hướng: Ali Arsanjani, Kyle Brown, John Crupi, Eric Evans, Martin Fowler, Brian Marick, Toby Sarver, Jonathan Simon, Bill Trudell và Marek Vokac.
Chúng tôi xin cảm ơn đội ngũ reviewer đã dành thời gian để đọc qua tài liệu dự thảo và cung cấp cho chúng tôi những phản hồi và gợi ý vô giá.
Richard Helm
Luke Hohmann
Đragos Manolescu
Đavid Ráiсe
Russ Rufer và Nhóm Mô Hình Silicon Valley
Ma-thi-ô Ngắn
Xin cảm ơn đặc biệt đến Russ vì đã làm việc tại nhóm Silicon Valley Patterns để chỉnh sửa bản thảo cuốn sách. Chúng tôi xin cảm ơn những thành viên sau đây vì những nỗ lực của họ: Robert Benson, Tracy Bialik, Jeffrey Blake, Azad Bolour, John Brewer, Bob Evans, Andy Farlie, Jeff Glaza, Phil Goodwin, Alan Harriman, Ken Hejmanowski, Deborah Kaddah, Rituraj Kirti, Jan Looney, Chris Lopez, Jerry Louis, Tao-hung Ma, Jeff Miller, Stilian Pandev, John Parello, Hema Pillay, Russ Rufer, Rich Smith, Carol Thistlethwaite, Debbie Utley, Walter Vannini, David Vydra và Ted Young.
Danh sách thảo luận qua email công khai của chúng tôi cho phép mọi người đã phát hiện ra tài liệu trên www.enterpriseintegrationpatterns.com tham gia và chia sẻ suy nghĩ cũng như ý tưởng của họ. Những lời vinh danh đặc biệt dành cho Bill Trudell, người có đóng góp tích cực nhất cho danh sách gửi thư. Những người đóng góp tích cực khác bao gồm Venkateshwar Bommineni, Duncan Cragg, John Crupi, Fokko Degenaar, Shailesh Gosavi, Christian Hall, Ralph Johnson, Paul Julius, Orjan Lundberg, Dragos Manolescu, Rob Mee, Srikanth Narasimhan, Sean Neville, Rob Patton, Kirk Pepperdine, Matthew Pryor, Somik Raha, Michael Rettig, Frank Sauer, Jonathan Simon, Federico Spinazzi, Randy Stafford, Marek Vokac, Joe Walnes và Mark Weitzel.
Chúng tôi cảm ơn Martin Fowler vì đã tổ chức cho chúng tôi trong chuỗi sự kiện đặc trưng của ông. Sự khẳng định của Martin đã mang lại cho chúng tôi sự tự tin và năng lượng cần thiết để hoàn thành công việc này.
Chúng tôi cảm ơn John Crupi đã viết lời giới thiệu cho cuốn sách của chúng tôi. Ông đã theo dõi quá trình hình thành cuốn sách từ đầu và luôn là một người hướng dẫn kiên nhẫn mà không bao giờ mất đi khiếu hài hước của mình.
Cuối cùng, chúng tôi nợ một khoản lớn cho đội ngũ biên tập và sản xuất tại Addison-Wesley, do biên tập viên trưởng của chúng tôi, Mike Hendrickson, lãnh đạo, bao gồm điều phối viên sản xuất của chúng tôi, Amy Fleischer; quản lý dự án của chúng tôi, Kim Arney Mulcahy; biên tập viên của chúng tôi, Carol J. Lallier; người đọc bản in của chúng tôi, Rebecca Rider; người lập chỉ mục của chúng tôi, Sharon Hilgenberg; cũng như Jacquelyn Doucette, John Fuller và Bernard Gaffney.
Chúng tôi có thể đã bỏ lỡ một số tên và không dành cho mọi người sự công nhận mà họ xứng đáng có được, và chúng tôi xin lỗi. Nhưng đối với tất cả mọi người được liệt kê và không được liệt kê, những người đã giúp làm cho cuốn sách này tốt hơn, xin cảm ơn vì tất cả sự giúp đỡ của các bạn. Chúng tôi hy vọng các bạn có thể tự hào về cuốn sách này như chúng tôi.
Các ứng dụng thú vị hiếm khi tồn tại trong sự cô lập. Dù ứng dụng bán hàng của bạn phải kết nối với ứng dụng quản lý kho, ứng dụng mua sắm của bạn phải liên kết với một trang đấu giá, hay lịch trên PDA của bạn phải đồng bộ với máy chủ lịch của công ty, có vẻ như bất kỳ ứng dụng nào cũng có thể được cải thiện bằng cách tích hợp nó với các ứng dụng khác.
Tất cả các giải pháp tích hợp đều phải đối mặt với một vài thách thức cơ bản:
Mạng lưới là không đáng tin cậy. Các giải pháp tích hợp phải vận chuyển dữ liệu từ máy tính này sang máy tính khác qua các mạng lưới. So với một quy trình chạy trên một máy tính đơn lẻ, điện toán phân tán phải chuẩn bị để đối phó với một tập hợp các vấn đề có thể lớn hơn nhiều. Thường thì, hai hệ thống cần được tích hợp cách nhau bởi các châu lục, và dữ liệu giữa chúng phải di chuyển qua các đường dây điện thoại, các đoạn LAN, bộ định tuyến, bộ chuyển mạch, mạng công cộng và các liên kết vệ tinh. Mỗi bước có thể gây ra sự chậm trễ hoặc gián đoạn.
Mạng lưới chậm. Gửi dữ liệu qua một mạng lưới chậm hơn nhiều lần so với việc gọi một phương thức cục bộ. Thiết kế một giải pháp phân tán rộng rãi theo cách giống như bạn tiếp cận một ứng dụng đơn lẻ có thể dẫn đến các tác động tiêu cực về hiệu suất.
Bất kỳ hai ứng dụng nào cũng khác nhau. Các giải pháp tích hợp cần truyền tải thông tin giữa các hệ thống sử dụng các ngôn ngữ lập trình, nền tảng hoạt động và định dạng dữ liệu khác nhau. Một giải pháp tích hợp phải có khả năng giao tiếp với tất cả các công nghệ khác nhau này.
Thay đổi là điều không thể tránh khỏi. Ứng dụng thay đổi theo thời gian. Một giải pháp tích hợp phải theo kịp những thay đổi trong các ứng dụng mà nó kết nối. Các giải pháp tích hợp có thể dễ dàng bị cuốn vào hiệu ứng tuyết lở của những thay đổi; nếu một hệ thống thay đổi, tất cả các hệ thống khác có thể bị ảnh hưởng. Một giải pháp tích hợp cần giảm thiểu sự phụ thuộc từ hệ thống này sang hệ thống khác bằng cách sử dụng coupling lỏng lẻo giữa các ứng dụng.
Theo thời gian, các nhà phát triển đã vượt qua những thách thức này bằng bốn phương pháp chính:
Chuyển Giao Tệp Một ứng dụng ghi một tệp mà một ứng dụng khác sẽ đọc sau đó. Các ứng dụng cần thỏa thuận về tên và vị trí tệp, định dạng của tệp, thời gian khi nào tệp sẽ được ghi và đọc, và ai sẽ xóa tệp.
Cơ sở dữ liệu chia sẻ Nhiều ứng dụng chia sẻ cùng một sơ đồ cơ sở dữ liệu, nằm trong một cơ sở dữ liệu vật lý duy nhất. Vì không có lưu trữ dữ liệu trùng lặp, không cần phải chuyển dữ liệu từ ứng dụng này sang ứng dụng khác.
Gọi Thủ tục Từ xa Một ứng dụng cung cấp một số chức năng của nó để có thể được truy cập từ xa bởi các ứng dụng khác dưới dạng một thủ tục từ xa. Sự giao tiếp diễn ra trong thời gian thực và đồng bộ.
Tin nhắn Một ứng dụng phát hành một tin nhắn đến một kênh tin nhắn chung. Các ứng dụng khác có thể đọc tin nhắn từ kênh vào một thời điểm sau đó. Các ứng dụng phải đồng ý về một kênh cũng như về định dạng của tin nhắn. Giao tiếp là không đồng bộ.
Mặc dù cả bốn phương pháp đều giải quyết cơ bản cùng một vấn đề, mỗi phong cách có những lợi thế và bất lợi riêng. Thực tế, các ứng dụng có thể tích hợp bằng cách sử dụng nhiều phong cách sao cho mỗi điểm tích hợp tận dụng phong cách phù hợp nhất với nó.
Cuốn sách này nói về cách sử dụng tin nhắn để tích hợp các ứng dụng. Một cách đơn giản để hiểu tin nhắn hoạt động như thế nào là xem xét hệ thống điện thoại. Một cuộc gọi điện thoại là một hình thức giao tiếp đồng bộ. Tôi chỉ có thể giao tiếp với bên kia nếu bên kia có mặt trong thời điểm tôi thực hiện cuộc gọi. Ngược lại, hộp thư thoại cho phép giao tiếp không đồng bộ. Với hộp thư thoại, khi người nhận không trả lời, người gọi có thể để lại một tin nhắn; sau đó, người nhận (vào thời điểm thuận tiện của mình) có thể lắng nghe các tin nhắn được xếp hàng trong hộp thư của mình. Hộp thư thoại cho phép người gọi để lại một tin nhắn ngay bây giờ để người nhận có thể lắng nghe sau, điều này dễ dàng hơn nhiều so với việc cố gắng khiến người gọi và người nhận cùng điện thoại vào cùng một thời điểm. Hộp thư thoại đóng gói (ít nhất một phần của) một cuộc gọi điện thoại thành một tin nhắn và xếp hàng cho việc tiêu thụ sau; đây chính là cách mà tin nhắn hoạt động.
Nhắn tin là một công nghệ cho phép giao tiếp giữa các chương trình với tốc độ cao, không đồng bộ, và đảm bảo giao hàng đáng tin cậy. Các chương trình giao tiếp bằng cách gửi các gói dữ liệu gọi là tin nhắn cho nhau. Các kênh, còn được gọi là hàng đợi, là những đường dẫn logic kết nối các chương trình và truyền tải tin nhắn. Một kênh hoạt động như một tập hợp hoặc mảng tin nhắn, nhưng có khả năng được chia sẻ một cách kỳ diệu qua nhiều máy tính và có thể được sử dụng đồng thời bởi nhiều ứng dụng. Một người gửi hoặc nhà sản xuất là một chương trình gửi một tin nhắn bằng cách ghi tin nhắn vào một kênh. Một người nhận hoặc nhà tiêu thụ là một chương trình nhận một tin nhắn bằng cách đọc (và xóa) nó từ một kênh.
Thông điệp tự nó chỉ đơn giản là một loại cấu trúc dữ liệu nào đó như chuỗi, mảng byte, bản ghi hoặc đối tượng. Nó có thể được hiểu đơn giản là dữ liệu, là mô tả về một lệnh sẽ được thực thi trên người nhận, hoặc là mô tả về một sự kiện đã xảy ra ở người gửi. Một thông điệp thực sự chứa hai phần, tiêu đề và nội dung. Tiêu đề chứa thông tin siêu về thông điệp - ai đã gửi, nó đang đi đâu, và vân vân; thông tin này được sử dụng bởi hệ thống nhắn tin và thường bị bỏ qua bởi các ứng dụng sử dụng thông điệp. Nội dung chứa dữ liệu ứng dụng đang được truyền và thường bị hệ thống nhắn tin bỏ qua. Trong cuộc trò chuyện, khi một nhà phát triển ứng dụng đang sử dụng nhắn tin nói về một thông điệp, thường thì cô ấy đang đề cập đến dữ liệu trong nội dung của thông điệp.
Kiến trúc nhắn tin không đồng bộ rất mạnh mẽ nhưng yêu cầu chúng ta phải suy nghĩ lại về cách phát triển của mình. So với ba phương pháp tích hợp khác, tương đối ít nhà phát triển đã có kinh nghiệm với nhắn tin và các hệ thống nhắn tin. Kết quả là, các nhà phát triển ứng dụng nói chung không quen thuộc với các thành ngữ và đặc điểm riêng của nền tảng giao tiếp này.
Các khả năng nhắn tin thường được cung cấp bởi một hệ thống phần mềm riêng biệt gọi là hệ thống nhắn tin hoặc phần mềm trung gian theo định hướng tin nhắn (MOM). Một hệ thống nhắn tin quản lý việc nhắn tin giống như một hệ thống cơ sở dữ liệu quản lý việc lưu trữ dữ liệu. Cũng như một quản trị viên phải cung cấp cho cơ sở dữ liệu sơ đồ cho dữ liệu của ứng dụng, một quản trị viên cũng phải cấu hình hệ thống nhắn tin với các kênh xác định các con đường giao tiếp giữa các ứng dụng. Hệ thống nhắn tin sau đó phối hợp và quản lý việc gửi và nhận tin nhắn. Mục đích chính của hệ thống cơ sở dữ liệu là đảm bảo mỗi bản ghi dữ liệu được lưu trữ một cách an toàn, và tương tự, nhiệm vụ chính của hệ thống nhắn tin là di chuyển tin nhắn từ máy tính của người gửi đến máy tính của người nhận một cách đáng tin cậy.
Một hệ thống nhắn tin là cần thiết để chuyển các tin nhắn từ máy tính này sang máy tính khác vì các máy tính và mạng kết nối chúng vốn dĩ không đáng tin cậy. Chỉ vì một ứng dụng sẵn sàng gửi dữ liệu không có nghĩa là ứng dụng kia sẵn sàng nhận dữ liệu. Ngay cả khi cả hai ứng dụng đều sẵn sàng, mạng có thể không hoạt động hoặc có thể thất bại trong việc truyền dữ liệu một cách chính xác. Một hệ thống nhắn tin vượt qua những hạn chế này bằng cách liên tục thử nghiệm việc truyền tin nhắn cho đến khi thành công. Trong điều kiện lý tưởng, tin nhắn được truyền thành công ngay từ lần thử đầu tiên, nhưng thực tế thường không lý tưởng.
Về bản chất, một thông điệp được truyền tải qua năm bước:
Tạo Người gửi tạo tin nhắn và điền thông tin vào đó.
Gửi Người gửi thêm tin nhắn vào một kênh.
Gửi đi Hệ thống nhắn tin chuyển tin nhắn từ máy tính của người gửi đến máy tính của người nhận, làm cho tin nhắn có sẵn cho người nhận.
Nhận Bộ thu nhận đọc tin nhắn từ kênh.
Quy trình Người nhận trích xuất dữ liệu từ tin nhắn.
Hình dưới đây minh họa năm bước truyền dẫn này, máy tính thực hiện từng bước nào và những bước nào liên quan đến hệ thống nhắn tin:
Bước Truyền Tải Tin Nhắn Từng Bước Một

Hình này cũng minh họa hai khái niệm nhắn tin quan trọng:
Gửi và quên Trong bước 2, ứng dụng gửi sẽ gửi tin nhắn đến kênh tin nhắn. Một khi việc gửi hoàn tất, người gửi có thể tiếp tục công việc khác trong khi hệ thống nhắn tin truyền tin nhắn ở chế độ nền. Người gửi có thể yên tâm rằng người nhận cuối cùng sẽ nhận được tin nhắn và không phải chờ cho đến khi điều đó xảy ra.
Lưu và chuyển tiếp Trong bước 2, khi ứng dụng gửi gửi thông điệp đến kênh nhắn, hệ thống nhắn tin lưu trữ thông điệp trên máy tính của người gửi, có thể là trong bộ nhớ hoặc trên đĩa. Ở bước 3, hệ thống nhắn tin chuyển phát thông điệp bằng cách chuyển tiếp nó từ máy tính của người gửi đến máy tính của người nhận, và sau đó lưu trữ thông điệp một lần nữa trên máy tính của người nhận. Quá trình lưu và chuyển tiếp này có thể được lặp lại nhiều lần khi thông điệp được di chuyển từ máy tính này sang máy tính khác cho đến khi nó đến máy tính của người nhận.
Các bước tạo, gửi, nhận và xử lý có thể trông như là những rào cản không cần thiết. Tại sao không đơn giản chỉ cần chuyển giao dữ liệu đến người nhận? Bằng cách bao bọc dữ liệu dưới dạng một thông điệp và lưu trữ nó trong hệ thống nhắn tin, các ứng dụng ủy quyền cho hệ thống nhắn tin chịu trách nhiệm chuyển giao dữ liệu. Vì dữ liệu được bao bọc dưới dạng một thông điệp nguyên tử, việc giao hàng có thể được thử lại cho đến khi thành công, và người nhận có thể yên tâm rằng sẽ nhận được chính xác một bản sao của dữ liệu.
Bây giờ chúng ta đã biết thông điệp là gì, chúng ta nên hỏi, Tại sao lại sử dụng thông điệp? Giống như bất kỳ giải pháp tinh vi nào, không có một câu trả lời đơn giản nào. Câu trả lời nhanh chóng là thông điệp ngay lập tức hơn so với Chuyển File, bao quát tốt hơn so với Cơ sở Dữ liệu Chia sẻ, và đáng tin cậy hơn so với Gọi Thủ tục Từ xa. Tuy nhiên, đó chỉ là khởi đầu của những lợi thế mà việc sử dụng thông điệp có thể mang lại.
Lợi ích cụ thể của việc nhắn tin bao gồm:
Giao tiếp từ xa. Nhắn tin cho phép các ứng dụng riêng lẻ giao tiếp và chuyển dữ liệu. Hai đối tượng nằm trong cùng một tiến trình có thể đơn giản chia sẻ cùng một dữ liệu trong bộ nhớ. Việc gửi dữ liệu đến một máy tính khác phức tạp hơn nhiều và yêu cầu dữ liệu phải được sao chép từ máy tính này sang máy tính khác. Điều này có nghĩa là các đối tượng phải "có thể tuần tự hóa", tức là chúng có thể được chuyển đổi thành một dòng byte đơn giản có thể được gửi qua mạng. Nhắn tin đảm nhận việc này để các ứng dụng không phải lo lắng về nó.
Tích hợp Nền tảng/Ngôn ngữ. Khi kết nối nhiều hệ thống máy tính thông qua giao tiếp từ xa, những hệ thống này có thể sử dụng các ngôn ngữ, công nghệ và nền tảng khác nhau, có thể là vì chúng được phát triển theo thời gian bởi các nhóm độc lập. Việc tích hợp các ứng dụng khác biệt như vậy có thể yêu cầu một vùng trung lập của phần mềm trung gian để thương lượng giữa các ứng dụng, thường sử dụng những điểm chung thấp nhất, chẳng hạn như các tệp dữ liệu đơn giản với định dạng không rõ ràng. Trong những trường hợp này, một hệ thống nhắn tin có thể là một trình dịch chung giữa các ứng dụng, làm việc với ngôn ngữ và nền tảng của từng ứng dụng theo cách riêng của nó nhưng vẫn cho phép tất cả giao tiếp thông qua một mô hình nhắn tin chung. Sự kết nối phổ quát này là trái tim của mẫu Message Bus.
Giao tiếp không đồng bộ. Nhắn tin cho phép một cách tiếp cận gửi và quên trong giao tiếp. Người gửi không cần phải chờ đợi người nhận nhận và xử lý tin nhắn; thậm chí họ không cần phải chờ đợi hệ thống nhắn tin giao tin nhắn. Người gửi chỉ cần chờ đợi tin nhắn được gửi đi, tức là tin nhắn được lưu trữ thành công trong kênh bởi hệ thống nhắn tin. Khi tin nhắn đã được lưu trữ, người gửi có thể tự do thực hiện công việc khác trong khi tin nhắn được truyền tải trong nền.
Thời gian biến đổi. Với giao tiếp đồng bộ, người gọi phải chờ người nhận hoàn tất việc xử lý cuộc gọi trước khi có thể nhận kết quả và tiếp tục. Theo cách này, người gọi chỉ có thể thực hiện cuộc gọi nhanh nhất là tốc độ mà người nhận có thể xử lý. Giao tiếp không đồng bộ cho phép người gửi gửi yêu cầu đến người nhận theo nhịp độ riêng của mình và người nhận tiêu thụ các yêu cầu theo nhịp độ khác của chính họ. Điều này cho phép cả hai ứng dụng hoạt động với công suất tối đa và không lãng phí thời gian chờ đợi lẫn nhau (ít nhất là cho đến khi người nhận hết thông điệp để xử lý).
Throttling. Một vấn đề với các cuộc gọi thủ tục từ xa (RPC) là quá nhiều cuộc gọi đến một bộ nhận duy nhất cùng một lúc có thể làm quá tải bộ nhận đó. Điều này có thể gây ra sự suy giảm hiệu suất và thậm chí làm cho bộ nhận bị treo. Bởi vì hệ thống nhắn tin xếp hàng các yêu cầu cho đến khi bộ nhận sẵn sàng để xử lý chúng, bộ nhận có thể kiểm soát tỷ lệ mà nó tiêu thụ các yêu cầu để không bị quá tải bởi quá nhiều yêu cầu đồng thời. Các bên gọi không bị ảnh hưởng bởi việc giảm tốc này vì giao tiếp là bất đồng bộ, vì vậy các bên gọi không bị chặn khi chờ đợi bộ nhận.
Giao tiếp đáng tin cậy. Nhắn tin cung cấp sự giao hàng đáng tin cậy mà RPC không thể làm được. Lý do nhắn tin đáng tin cậy hơn RPC là vì nhắn tin sử dụng phương pháp lưu và chuyển tiếp để truyền tải tin nhắn. Dữ liệu được đóng gói thành các tin nhắn, là các đơn vị độc lập, nguyên tử. Khi người gửi gửi một tin nhắn, hệ thống nhắn tin sẽ lưu trữ tin nhắn đó. Sau đó, nó chuyển tiếp tin nhắn đến máy tính của người nhận, nơi nó lại được lưu trữ lần nữa. Việc lưu trữ tin nhắn trên máy tính của người gửi và máy tính của người nhận được giả định là đáng tin cậy. (Để làm cho nó thậm chí còn đáng tin cậy hơn, các tin nhắn có thể được lưu trữ vào đĩa thay vì bộ nhớ; xem Giao hàng đảm bảo.) Điều không đáng tin cậy là việc chuyển tiếp (di chuyển) tin nhắn từ máy tính của người gửi tới máy tính của người nhận, vì người nhận hoặc mạng có thể không hoạt động đúng cách. Hệ thống nhắn tin vượt qua điều này bằng cách gửi lại tin nhắn cho đến khi thành công. Quy trình thử lại tự động này cho phép hệ thống nhắn tin vượt qua các vấn đề với mạng để người gửi và người nhận không phải lo lắng về những chi tiết này.
Hoạt động không kết nối. Một số ứng dụng được thiết kế đặc biệt để chạy mà không cần kết nối mạng, nhưng vẫn đồng bộ với máy chủ khi có kết nối mạng. Các ứng dụng như vậy thường được triển khai trên các nền tảng như máy tính xách tay và PDA. Việc nhắn tin rất lý tưởng để cho phép các ứng dụng này đồng bộ hóa dữ liệu, các dữ liệu cần được đồng bộ có thể được xếp hàng khi được tạo ra, chờ đến khi ứng dụng kết nối lại với mạng.
Trung gian. Hệ thống nhắn tin hoạt động như một trung gian trong mẫu Trung gian [GoF] giữa tất cả các chương trình có thể gửi và nhận tin nhắn. Một ứng dụng có thể sử dụng nó như một thư mục các ứng dụng hoặc dịch vụ khác có sẵn để tích hợp. Nếu một ứng dụng bị mất kết nối với các ứng dụng khác, nó chỉ cần kết nối lại với hệ thống nhắn tin, không cần kết nối lại với tất cả các ứng dụng nhắn tin khác. Hệ thống nhắn tin có thể sử dụng tài nguyên dư thừa để cung cấp tính khả dụng cao, cân bằng tải, chuyển hướng xung quanh các kết nối mạng thất bại và điều chỉnh hiệu suất cũng như chất lượng dịch vụ.
Quản lý luồng. Giao tiếp bất đồng bộ có nghĩa là một ứng dụng không cần phải chặn trong khi chờ đợi ứng dụng khác thực hiện một nhiệm vụ, trừ khi nó muốn. Thay vì chặn để chờ phản hồi, người gọi có thể sử dụng một hàm gọi lại (callback) để thông báo cho người gọi khi phản hồi đến. (Xem mẫu Request-Reply.) Một số lượng lớn các luồng bị chặn hoặc các luồng bị chặn trong thời gian dài có thể khiến ứng dụng không còn đủ các luồng có sẵn để thực hiện công việc thực sự. Ngoài ra, nếu một ứng dụng có số lượng luồng bị chặn động gặp sự cố, việc khôi phục các luồng đó sẽ rất khó khăn khi ứng dụng khởi động lại và phục hồi trạng thái trước đó. Với các hàm gọi lại, chỉ có một số ít luồng biết trước bị chặn là những người lắng nghe chờ phản hồi. Điều này để lại hầu hết các luồng có sẵn cho các công việc khác và xác định một số lượng luồng lắng nghe nhất định có thể dễ dàng được khôi phục sau khi gặp sự cố.
Có nhiều lý do khác nhau mà một ứng dụng hoặc doanh nghiệp có thể hưởng lợi từ việc sử dụng hệ thống nhắn tin. Một số lý do này là những chi tiết kỹ thuật mà các nhà phát triển ứng dụng dễ dàng liên hệ, trong khi những lý do khác là những quyết định chiến lược mà các kiến trúc sư doanh nghiệp dễ dàng đồng cảm. Lý do nào trong số này quan trọng nhất phụ thuộc vào yêu cầu hiện tại của các ứng dụng cụ thể của bạn. Tất cả đều là những lý do hợp lý để sử dụng hệ thống nhắn tin, vì vậy hãy tận dụng những lý do nào mang lại lợi ích nhiều nhất cho bạn.
Messaging không đồng bộ không phải là giải pháp hoàn hảo cho việc tích hợp. Nó giải quyết nhiều thách thức trong việc tích hợp các hệ thống khác nhau một cách tinh tế, nhưng cũng mang đến những thách thức mới. Một số thách thức này là do bản chất của mô hình không đồng bộ, trong khi những thách thức khác thay đổi theo cách cụ thể mà hệ thống nhắn tin được triển khai.
Mô hình lập trình phức tạp. Giao tiếp bất đồng bộ yêu cầu các nhà phát triển làm việc với mô hình lập trình dựa trên sự kiện. Logic ứng dụng không có thể được mã hóa trong một phương thức duy nhất gọi các phương thức khác, mà thay vào đó, logic giờ đây được chia thành một số trình xử lý sự kiện phản hồi lại các tin nhắn đến. Một hệ thống như vậy thì phức tạp hơn và khó phát triển cũng như gỡ lỗi hơn. Ví dụ, tương đương với một lời gọi phương thức đơn giản có thể yêu cầu một tin nhắn yêu cầu và một kênh yêu cầu, một tin nhắn phản hồi và một kênh phản hồi, một định danh tương quan và một hàng đợi tin nhắn không hợp lệ (như được mô tả trong Yêu cầu-Phản hồi).
Vấn đề về thứ tự. Các kênh tin nhắn đảm bảo việc giao nhận tin nhắn, nhưng không đảm bảo thời điểm tin nhắn sẽ được giao. Điều này có thể khiến các tin nhắn được gửi theo thứ tự bị lệch thứ tự. Trong các tình huống mà các tin nhắn phụ thuộc vào nhau, cần phải hết sức cẩn thận để khôi phục lại thứ tự tin nhắn (xem Resequencer).
Kịch bản đồng bộ. Không phải tất cả các ứng dụng đều có thể hoạt động theo chế độ gửi và quên. Nếu một người dùng đang tìm vé máy bay, họ sẽ muốn xem ngay giá vé, chứ không phải sau một khoảng thời gian không xác định. Do đó, nhiều hệ thống nhắn tin cần phải cầu nối khoảng cách giữa các giải pháp đồng bộ và không đồng bộ.
Hiệu suất. Hệ thống nhắn tin thực sự tạo thêm một số chi phí cho việc giao tiếp. Việc đóng gói dữ liệu ứng dụng thành một thông điệp và gửi đi, cũng như nhận thông điệp và xử lý nó là cần thiết. Nếu bạn phải vận chuyển một khối lượng dữ liệu lớn, việc chia nhỏ nó thành hàng triệu mảnh có thể không phải là ý tưởng tốt. Chẳng hạn, nếu một giải pháp tích hợp cần đồng bộ hóa thông tin giữa hai hệ thống hiện có, bước đầu tiên thường là sao chép tất cả thông tin liên quan từ một hệ thống sang hệ thống kia. Đối với bước sao chép dữ liệu hàng loạt như vậy, các công cụ ETL (trích xuất, chuyển đổi và tải) thường hiệu quả hơn so với nhắn tin. Nhắn tin phù hợp nhất để giữ cho các hệ thống đồng bộ sau khi bước sao chép dữ liệu ban đầu.
Hỗ trợ nền tảng hạn chế. Nhiều hệ thống nhắn tin độc quyền không có sẵn trên tất cả các nền tảng. Thông thường, việc chuyển tệp qua FTP là tùy chọn tích hợp duy nhất vì nền tảng mục tiêu có thể không hỗ trợ hệ thống nhắn tin.
Khóa nhà cung cấp. Nhiều triển khai hệ thống nhắn tin dựa vào các giao thức độc quyền. Ngay cả các đặc tả nhắn tin phổ biến như JMS cũng không kiểm soát việc triển khai vật lý của giải pháp. Kết quả là, các hệ thống nhắn tin khác nhau thường không kết nối với nhau. Điều này có thể để lại cho bạn một thách thức tích hợp hoàn toàn mới: tích hợp nhiều giải pháp tích hợp! (Xem mẫu Cầu Nhắn Tin.)
Tóm lại, nhắn tin không đồng bộ không giải quyết tất cả các vấn đề, và nó thậm chí có thể tạo ra những vấn đề mới. Hãy nhớ những hậu quả này khi quyết định vấn đề nào cần giải quyết bằng cách sử dụng nhắn tin.
Nhắn tin là một công nghệ bất đồng bộ, cho phép việc gửi tin nhắn được thử lại cho đến khi thành công. Trái ngược với điều này, hầu hết các ứng dụng sử dụng các cuộc gọi hàm đồng bộ, ví dụ, một quy trình gọi một quy trình con, một phương thức gọi một phương thức khác, hoặc một quy trình gọi một quy trình khác từ xa thông qua một RPC (như CORBA và DCOM). Các cuộc gọi đồng bộ ngụ ý rằng quy trình gọi sẽ bị tạm dừng trong khi quy trình con đang thực hiện một hàm. Ngay cả trong một kịch bản RPC, nơi quy trình con được gọi thực thi trong một quy trình khác, người gọi sẽ bị chặn cho đến khi quy trình con hoàn trả quyền kiểm soát (và các kết quả) cho người gọi. Ngược lại, khi sử dụng nhắn tin bất đồng bộ, người gọi sử dụng cách tiếp cận gửi và quên cho phép họ tiếp tục thực hiện sau khi gửi tin nhắn. Do đó, quy trình gọi sẽ tiếp tục hoạt động trong khi quy trình con đang được gọi.
Ngữ nghĩa cuộc gọi đồng bộ và bất đồng bộ

Giao tiếp bất đồng bộ có một số hệ quả. Thứ nhất, chúng ta không còn một luồng thực thi duy nhất. Nhiều luồng cho phép các tiểu quy trình chạy đồng thời, điều này có thể cải thiện đáng kể hiệu suất và giúp đảm bảo rằng một số tiểu quy trình đang tiến triển ngay cả khi những tiểu quy trình khác có thể đang chờ kết quả từ bên ngoài. Tuy nhiên, các luồng đồng thời cũng làm cho việc gỡ lỗi trở nên khó khăn hơn nhiều. Thứ hai, kết quả (nếu có) đến thông qua cơ chế gọi lại. Điều này cho phép người gọi thực hiện các tác vụ khác và được thông báo khi kết quả có sẵn, điều này có thể cải thiện hiệu suất. Tuy nhiên, điều này có nghĩa là người gọi phải có khả năng xử lý kết quả ngay cả khi đang giữa các tác vụ khác, và phải có khả năng nhớ ngữ cảnh mà cuộc gọi được thực hiện. Thứ ba, các tiểu quy trình bất đồng bộ có thể thực hiện theo bất kỳ thứ tự nào. Một lần nữa, điều này cho phép một tiểu quy trình tiến triển ngay cả khi một tiểu quy trình khác không thể. Nhưng điều này cũng có nghĩa là các tiểu quy trình phải có khả năng chạy độc lập theo bất kỳ thứ tự nào, và người gọi phải có khả năng xác định kết quả nào đến từ tiểu quy trình nào và kết hợp các kết quả lại với nhau. Kết quả là, giao tiếp bất đồng bộ có một số lợi thế nhưng yêu cầu phải suy nghĩ lại cách mà một quy trình sử dụng các tiểu quy trình của nó.
Cuốn sách này nói về tích hợp doanh nghiệp - cách tích hợp các ứng dụng độc lập để chúng có thể hoạt động cùng nhau. Một ứng dụng doanh nghiệp thường bao gồm kiến trúc n-tầng (một phiên bản tinh vi hơn của kiến trúc máy khách/máy chủ), cho phép nó được phân phối qua nhiều máy tính khác nhau. Mặc dù điều này dẫn đến việc các quy trình trên các máy khác nhau giao tiếp với nhau, nhưng đó là phân phối ứng dụng, chứ không phải tích hợp ứng dụng.
Tại sao kiến trúc n-tầng được coi là phân tán ứng dụng chứ không phải là tích hợp ứng dụng? Thứ nhất, các phần giao tiếp với nhau được kết nối chặt chẽ - chúng phụ thuộc trực tiếp vào nhau, vì vậy một tầng không thể hoạt động mà không có các tầng khác. Thứ hai, giao tiếp giữa các tầng thường mang tính đồng bộ. Thứ ba, một ứng dụng (n-tầng hoặc nguyên tử) thường có người dùng mà chỉ chấp nhận thời gian phản hồi hệ thống nhanh chóng.
Ngược lại, các ứng dụng tích hợp là những ứng dụng độc lập có thể tự chạy mà không cần phụ thuộc vào nhau, nhưng phối hợp với nhau một cách lỏng lẻo. Điều này cho phép mỗi ứng dụng tập trung vào một tập hợp chức năng toàn diện và ủy quyền cho các ứng dụng khác cho các chức năng liên quan. Các ứng dụng tích hợp giao tiếp bất đồng bộ không cần phải chờ đợi phản hồi; chúng có thể tiếp tục mà không cần phản hồi hoặc thực hiện các nhiệm vụ khác đồng thời cho đến khi phản hồi có sẵn. Các ứng dụng tích hợp thường có giới hạn thời gian rộng, vì vậy chúng có thể làm việc trên các nhiệm vụ khác cho đến khi có kết quả, và do đó, chúng kiên nhẫn hơn so với hầu hết người dùng đang chờ đợi kết quả trong thời gian thực.
Các lợi ích rõ ràng của việc tích hợp hệ thống bằng cách sử dụng giải pháp nhắn tin bất đồng bộ đã mở ra một thị trường quan trọng cho các nhà cung cấp phần mềm tạo ra phần mềm trung gian nhắn tin và các công cụ liên quan. Chúng ta có thể phân nhóm các sản phẩm của các nhà cung cấp nhắn tin thành bốn loại sau:
Hệ điều hành. Tin nhắn đã trở thành một nhu cầu phổ biến đến nỗi các nhà cung cấp đã bắt đầu tích hợp cơ sở hạ tầng phần mềm cần thiết vào hệ điều hành hoặc nền tảng cơ sở dữ liệu. Ví dụ, hệ điều hành Microsoft Windows 2000 và Windows XP bao gồm phần mềm dịch vụ Microsoft Message Queuing (MSMQ). Dịch vụ này có thể được truy cập thông qua một số API, bao gồm các thành phần COM và không gian tên System.Messaging, một phần của nền tảng Microsoft .NET. Tương tự, Oracle cung cấp Oracle AQ như một phần của nền tảng cơ sở dữ liệu của mình.
Máy chủ ứng dụng. Sun Microsystems đã lần đầu tiên tích hợp Dịch vụ Nhắn tin Java (JMS) vào phiên bản 1.2 của đặc tả J2EE. Kể từ đó, hầu như tất cả các máy chủ ứng dụng J2EE (chẳng hạn như IBM WebSphere và BEA WebLogic) đều cung cấp một triển khai cho đặc tả này. Ngoài ra, Sun còn cung cấp một triển khai tham chiếu JMS với JDK J2EE.
Bộ EAI. Các sản phẩm từ những nhà cung cấp này cung cấp các bộ phần mềm độc quyền nhưng phong phú về chức năng, bao gồm nhắn tin, tự động hóa quy trình kinh doanh, quy trình làm việc, cổng thông tin và các chức năng khác. Những người chơi chính trong thị trường này bao gồm IBM WebSphere MQ, Microsoft BizTalk, TIBCO, WebMethods, SeeBeyond, Vitria, CrossWorlds và những cái khác. Nhiều sản phẩm trong số này bao gồm JMS như một trong nhiều API khách hàng mà họ hỗ trợ, trong khi các nhà cung cấp khác như SonicSoftware và Fiorano chủ yếu tập trung vào việc triển khai cơ sở hạ tầng nhắn tin tuân thủ JMS.
Công cụ dịch vụ web. Dịch vụ web đã thu hút được nhiều sự quan tâm trong cộng đồng tích hợp doanh nghiệp. Các cơ quan tiêu chuẩn và liên minh đang tích cực làm việc để tiêu chuẩn hóa việc giao nhận tin nhắn đáng tin cậy qua dịch vụ web (tức là WS-Reliability, WS-ReliableMessaging và ebMS). Số lượng nhà cung cấp ngày càng tăng cung cấp các công cụ thực hiện định tuyến, chuyển đổi và quản lý các giải pháp dựa trên dịch vụ web.
Các mẫu trong cuốn sách này không phụ thuộc vào nhà cung cấp và áp dụng cho hầu hết các giải pháp nhắn tin. Thật không may, mỗi nhà cung cấp thường xác định thuật ngữ riêng của mình khi mô tả các giải pháp nhắn tin. Trong cuốn sách này, chúng tôi đã cố gắng chọn tên mẫu mà không thiên về công nghệ hay sản phẩm song vẫn mô tả và dễ sử dụng trong giao tiếp.
Nhiều nhà cung cấp dịch vụ nhắn tin đã tích hợp một số mẫu của cuốn sách này vào các tính năng của sản phẩm của họ, điều này làm đơn giản hóa việc áp dụng các mẫu và tăng tốc độ phát triển giải pháp. Những độc giả quen thuộc với thuật ngữ của một nhà cung cấp cụ thể sẽ rất có khả năng nhận ra nhiều khái niệm trong cuốn sách này. Để giúp những độc giả này liên kết ngôn ngữ mẫu với thuật ngữ cụ thể của nhà cung cấp, các bảng sau đây ánh xạ những tên mẫu phổ biến nhất với các tên tính năng sản phẩm tương ứng trong một số sản phẩm nhắn tin được sử dụng rộng rãi nhất.
Mẫu tích hợp doanh nghiệp | Dịch vụ tin nhắn Java (JMS) | Microsoft MSMQ in Vietnamese is "Microsoft MSMQ". | WebSphere MQ dịch sang tiếng Việt là `WebSphere MQ`. |
|---|---|---|---|
Kênh Tin Nhắn | Điểm đến | Hàng đợi tin nhắn | Hàng đợi |
Kênh Điểm-Đến-Điểm | Hàng đợi | Hàng đợi tin nhắn | Hàng đợi |
Kênh Phát-Hành Đăng Ký | Chủ đề | ||
Thông điệp | Thông điệp | Tin nhắn | Tin nhắn |
Điểm cuối tin nhắn | Nhà sản xuất tin nhắn, Người tiêu thụ tin nhắn |
Mô hình Tích hợp Doanh nghiệp | TIBCO | Phương pháp web | Xem vượt lên | Vitria in Vietnamese is "Vitria". |
|---|---|---|---|---|
Kênh Tin Nhắn | Chủ đề | Hàng đợi | Hàng đợi thông minh | Kênh |
Kênh điểm-điểm | Hàng đợi phân tán | Hành động giao hàng | Hàng đợi thông minh | Kênh |
Kênh Đăng ký-Nhận thông báo | Chủ đề | Hành động Đăng-Ký và Nhận Thông Tin | Hàng đợi thông minh | Kênh Đăng Chương - Theo Dõi |
Tin nhắn | Tin nhắn | Tài liệu | Sự kiện | Sự kiện |
Điểm cuối thông điệp | Nhà xuất bản, Người đăng ký | Nhà xuất bản, Người đăng ký | Nhà xuất bản, Người đăng ký | Nhà xuất bản, Người đăng ký |
Cuốn sách này chứa một tập hợp các mẫu được tổ chức thành một ngôn ngữ mẫu. Những cuốn sách như Mẫu Thiết Kế, Kiến Trúc Phần Mềm Hướng Mẫu, Mẫu Chính của J2EE, và Mẫu Kiến Trúc Ứng Dụng Doanh Nghiệp đã phổ biến khái niệm sử dụng các mẫu để tài liệu hóa các kỹ thuật lập trình máy tính. Christopher Alexander là người tiên phong trong khái niệm về các mẫu và ngôn ngữ mẫu trong các cuốn sách của ông như A Pattern Language và A Timeless Way of Building. Mỗi mẫu đại diện cho một quyết định cần phải được đưa ra và các cân nhắc liên quan đến quyết định đó. Một ngôn ngữ mẫu là một mạng lưới các mẫu liên quan, trong đó mỗi mẫu dẫn đến những mẫu khác, hướng dẫn bạn qua quá trình ra quyết định. Phương pháp này là một kỹ thuật mạnh mẽ để tài liệu hóa kiến thức của một chuyên gia sao cho có thể dễ dàng được hiểu và áp dụng bởi người khác.
Một ngôn ngữ mẫu giúp bạn cách giải quyết một loạt các vấn đề không giới hạn trong một không gian vấn đề có giới hạn. Bởi vì vấn đề tổng thể đang được giải quyết là khác nhau mỗi lần, con đường qua các mẫu và cách chúng được áp dụng cũng là độc nhất. Cuốn sách này được viết cho bất kỳ ai sử dụng bất kỳ công cụ nhắn tin nào cho bất kỳ ứng dụng nào, và nó có thể được áp dụng cụ thể cho bạn và ứng dụng nhắn tin độc đáo mà bạn phải đối mặt.
Việc sử dụng hình thức mẫu một mình không đảm bảo rằng một cuốn sách chứa đựng một kho tàng tri thức. Chỉ nói đơn giản rằng, "Khi bạn gặp vấn đề này, hãy áp dụng giải pháp này" là không đủ. Để bạn thực sự học được từ một mẫu, mẫu đó phải ghi chép lý do tại sao vấn đề khó giải quyết, xem xét các giải pháp có thể nhưng thực tế không hiệu quả, và giải thích tại sao giải pháp được đưa ra là tốt nhất có thể. Tương tự, các mẫu cần phải kết nối với nhau để dẫn dắt bạn từ vấn đề này sang vấn đề khác. Bằng cách này, hình thức mẫu có thể được sử dụng để dạy không chỉ những giải pháp nào nên áp dụng mà còn cách giải quyết các vấn đề mà các tác giả không thể dự đoán. Đây là những mục tiêu mà chúng tôi cố gắng đạt được trong cuốn sách này.
Các mẫu nên mang tính quy định, có nghĩa là chúng nên hướng dẫn bạn nên làm gì. Chúng không chỉ mô tả một vấn đề và cũng không chỉ mô tả cách giải quyết, mà chúng hướng dẫn bạn cụ thể để giải quyết nó. Mỗi mẫu đại diện cho một quyết định mà bạn phải đưa ra: "Tôi có nên sử dụng Messaging không?" "Liệu một Command Message có giúp tôi ở đây không?" Điểm mấu chốt của các mẫu và ngôn ngữ mẫu là giúp bạn đưa ra những quyết định dẫn đến một giải pháp tốt cho vấn đề cụ thể của bạn, ngay cả khi các tác giả không nghĩ đến vấn đề cụ thể đó và ngay cả khi bạn không có kiến thức và kinh nghiệm để phát triển giải pháp đó một mình.
Không có một mẫu chung nào cho các hình thức; các cuốn sách khác nhau sử dụng những cấu trúc khác nhau. Chúng tôi đã sử dụng một phong cách khá giống với hình thức Alexandrian, lần đầu tiên được phổ biến cho lập trình máy tính trong cuốn "Smalltalk Best Practice Patterns" của Kent Beck. Chúng tôi thích hình thức Alexandrian vì nó dẫn đến các mẫu có vẻ giống như văn xuôi hơn. Do đó, mặc dù mỗi mẫu đi theo một cấu trúc giống hệt nhau, rõ ràng, định dạng này tránh sử dụng tiêu đề cho các tiểu mục riêng lẻ, điều này có thể làm gián đoạn dòng chảy của cuộc thảo luận. Để cải thiện khả năng điều hướng, định dạng sử dụng các yếu tố kiểu dáng như gạch dưới, thụt đầu dòng và hình minh họa để giúp bạn nhận diện thông tin quan trọng một cách nhanh chóng.
Mỗi mẫu theo cấu trúc này:
Tên Đây là một định danh cho mẫu mà chỉ định điều mà mẫu đó làm. Chúng tôi đã chọn những cái tên có thể dễ dàng được sử dụng trong một câu để dễ dàng tham chiếu đến khái niệm của mẫu trong cuộc trò chuyện giữa các nhà thiết kế.
Biểu tượng Hầu hết các mẫu đều liên quan đến một biểu tượng bên cạnh tên mẫu. Bởi vì nhiều kiến trúc sư quen thuộc với việc giao tiếp trực quan qua các sơ đồ, chúng tôi cung cấp một ngôn ngữ hình ảnh bên cạnh ngôn ngữ từ ngữ. Ngôn ngữ hình ảnh này nhấn mạnh khả năng kết hợp của các mẫu, khi nhiều biểu tượng mẫu có thể được kết hợp để mô tả giải pháp cho một mẫu lớn hơn, phức tạp hơn.
Ngữ cảnh Phần này giải thích loại công việc nào có thể khiến bạn gặp phải vấn đề mà mẫu này giải quyết. Ngữ cảnh đặt nền tảng cho vấn đề và thường đề cập đến các mẫu khác mà bạn có thể đã áp dụng.
Vấn đề Điều này giải thích khó khăn mà bạn đang gặp phải, được diễn đạt dưới dạng câu hỏi. Bạn nên có khả năng đọc tuyên bố vấn đề và nhanh chóng xác định xem mẫu này có liên quan đến công việc của bạn hay không. Chúng tôi đã định dạng vấn đề thành một câu được phân cách bằng các đường ngang.
Các lực khám phá các ràng buộc làm cho vấn đề trở nên khó giải quyết. Họ thường xem xét các giải pháp thay thế mà có vẻ đầy hứa hẹn nhưng không thành công, điều này giúp thể hiện giá trị của giải pháp thực sự.
Giải pháp Phần này giải thích những gì bạn nên thực hiện để giải quyết vấn đề. Nó không chỉ giới hạn ở tình huống cụ thể của bạn, mà mô tả những gì cần làm trong nhiều hoàn cảnh khác nhau được đại diện bởi vấn đề. Nếu bạn hiểu được vấn đề và giải pháp của một mẫu hình, bạn đã hiểu được mẫu hình đó. Chúng tôi đã định dạng giải pháp theo cùng phong cách như vấn đề để bạn có thể dễ dàng nhận ra các phát biểu về vấn đề và giải pháp khi xem qua cuốn sách.
Bản phác thảo Một trong những đặc điểm hấp dẫn nhất của hình thức Alexandrian là mỗi mẫu đều chứa một bản phác thảo minh họa cho giải pháp. Trong nhiều trường hợp, chỉ cần nhìn vào tên mẫu và bản phác thảo, bạn có thể hiểu được bản chất của mẫu. Chúng tôi đã cố gắng giữ nguyên phong cách này bằng cách minh họa giải pháp bằng một hình vẽ ngay sau tuyên bố giải pháp của mỗi mẫu.
Kết quả Phần này mở rộng giải pháp để giải thích chi tiết cách áp dụng giải pháp và cách nó giải quyết các lực. Nó cũng đề cập đến những thách thức mới có thể phát sinh do việc áp dụng mô hình này.
Tiếp theo Phần này liệt kê các mẫu khác cần được xem xét sau khi áp dụng mẫu hiện tại. Các mẫu không tồn tại trong sự cô lập; việc áp dụng một mẫu thường dẫn bạn đến những vấn đề mới mà có thể được giải quyết bằng các mẫu khác. Mối quan hệ giữa các mẫu chính là điều tạo nên một ngôn ngữ mẫu thay vì chỉ là một danh mục mẫu.
Các mục bên lề Các phần này thảo luận về các vấn đề kỹ thuật chi tiết hơn hoặc các biến thể của mẫu. Chúng tôi định hình các phần này khác biệt so với phần còn lại của văn bản để bạn có thể dễ dàng bỏ qua nếu chúng không liên quan đến ứng dụng cụ thể của bạn về mẫu.
Các ví dụ Một mẫu thường bao gồm một hoặc nhiều ví dụ về việc mẫu đó được áp dụng hoặc đã được áp dụng. Một ví dụ có thể đơn giản như việc nêu tên một ứng dụng đã biết hoặc chi tiết như một đoạn mã mẫu lớn. Với số lượng lớn các công nghệ nhắn tin có sẵn, chúng tôi không mong bạn phải quen thuộc với từng công nghệ được sử dụng để triển khai một ví dụ. Do đó, chúng tôi đã thiết kế các mẫu sao cho bạn có thể an toàn bỏ qua ví dụ mà không mất bất kỳ nội dung quan trọng nào của mẫu.
Vẻ đẹp trong việc mô tả các giải pháp như những mô hình là nó không chỉ dạy bạn cách giải quyết các vấn đề cụ thể được thảo luận, mà còn cách tạo ra những thiết kế giải quyết những vấn đề mà tác giả thậm chí không nhận thức được. Do đó, những mô hình này cho việc nhắn tin không chỉ mô tả các hệ thống nhắn tin tồn tại hôm nay, mà còn có thể áp dụng cho những hệ thống mới được tạo ra sau khi cuốn sách này được xuất bản.
Giải pháp tích hợp bao gồm nhiều phần khác nhau - ứng dụng, cơ sở dữ liệu, điểm cuối, kênh, tin nhắn, bộ định tuyến, và nhiều thứ khác. Nếu chúng ta muốn mô tả một giải pháp tích hợp, chúng ta cần xác định một ký hiệu có thể bao quát tất cả những thành phần khác nhau này. Theo sự hiểu biết của chúng tôi, không có ký hiệu nào được sử dụng rộng rãi và toàn diện cho việc mô tả tất cả các khía cạnh của một giải pháp tích hợp. Ngôn ngữ Mô hình Hợp nhất (UML) thực hiện rất tốt việc mô tả các hệ thống hướng đối tượng với các sơ đồ lớp và tương tác, nhưng nó không chứa ý nghĩa để mô tả các giải pháp nhắn tin. Hồ sơ UML cho EAI [UMLEAI] làm phong phú ý nghĩa của các sơ đồ hợp tác để mô tả luồng tin nhắn giữa các thành phần. Ký hiệu này rất hữu ích như một thông số hình ảnh chính xác có thể làm cơ sở cho việc tạo mã như một phần của kiến trúc hướng mô hình (MDA). Chúng tôi quyết định không áp dụng ký hiệu này vì hai lý do. Đầu tiên, Hồ sơ UML không nắm bắt được tất cả các mẫu được mô tả trong ngôn ngữ mẫu của chúng tôi. Thứ hai, chúng tôi không muốn tạo ra một thông số hình ảnh chính xác, mà là những hình ảnh có chất lượng "phác thảo" nhất định. Chúng tôi muốn những bức tranh có thể truyền đạt bản chất của một mẫu chỉ trong một cái nhìn nhanh, rất giống với phác thảo của Alexander. Đó là lý do tại sao chúng tôi quyết định tạo ra "ký hiệu" riêng của mình. May mắn thay, khác với ký hiệu chính thức hơn, của chúng tôi không yêu cầu bạn phải đọc một cuốn sổ tay lớn. Một hình ảnh đơn giản sẽ đủ.
Ghi chú hình ảnh cho giải pháp nhắn tin

Bức tranh đơn giản này cho thấy một thông điệp được gửi đến một thành phần qua một kênh. Chúng tôi sử dụng từ "thành phần" một cách rất rộng rãi ở đây - nó có thể chỉ một ứng dụng đang được tích hợp, một trung gian chuyển đổi hoặc định tuyến thông điệp giữa các ứng dụng, hoặc một phần cụ thể của một ứng dụng. Đôi khi, chúng tôi cũng mô tả một kênh dưới dạng một ống ba chiều nếu chúng tôi muốn nhấn mạnh kênh đó. Thường thì, chúng tôi quan tâm hơn đến các thành phần và vẽ các kênh dưới dạng các đường thẳng đơn giản với đầu mũi tên. Hai ký hiệu này là tương đương nhau. Chúng tôi mô tả thông điệp như một cái cây nhỏ với rễ tròn và các phần tử vuông lồng vào nhau vì nhiều hệ thống nhắn tin cho phép thông điệp chứa các cấu trúc dữ liệu giống như cây - ví dụ, tài liệu XML. Các phần tử của cây có thể được tô bóng hoặc tô màu để làm nổi bật việc sử dụng của chúng trong một mẫu cụ thể. Việc mô tả thông điệp theo cách này cho phép chúng tôi cung cấp một mô tả trực quan nhanh chóng về các mẫu chuyển đổi - dễ dàng để chỉ ra một mẫu thêm, sắp xếp lại hoặc loại bỏ các trường từ thông điệp.
Khi chúng ta mô tả thiết kế ứng dụng, chẳng hạn như các điểm cuối nhắn tin hoặc các ví dụ viết bằng C# hoặc Java, chúng ta sử dụng sơ đồ lớp và sơ đồ tuần tự chuẩn UML để minh họa cấu trúc phân cấp lớp và sự tương tác giữa các đối tượng, vì ký hiệu UML được chấp nhận rộng rãi như là cách tiêu chuẩn để mô tả các loại giải pháp này (nếu bạn cần ôn lại về UML, hãy xem [UML]).
Chúng tôi đã cố gắng nhấn mạnh tính khả dụng rộng rãi của các mẫu bằng cách bao gồm các ví dụ triển khai sử dụng nhiều công nghệ tích hợp khác nhau. Nhược điểm tiềm ẩn của cách tiếp cận này là bạn có thể không quen thuộc với từng công nghệ mà được sử dụng trong một ví dụ. Đó là lý do tại sao chúng tôi đã đảm bảo rằng việc đọc các ví dụ là hoàn toàn tùy chọn - tất cả các điểm liên quan đều được thảo luận trong phần mô tả mẫu. Do đó, bạn có thể an tâm bỏ qua các ví dụ mà không lo mất đi các chi tiết quan trọng. Ngoài ra, khi có thể, chúng tôi đã cung cấp hơn một ví dụ triển khai sử dụng các công nghệ khác nhau.
Khi trình bày mã ví dụ, chúng tôi tập trung vào tính dễ đọc hơn là khả năng chạy. Một đoạn mã có thể giúp loại bỏ bất kỳ sự mơ hồ tiềm ẩn nào còn lại từ mô tả giải pháp, và nhiều nhà phát triển ứng dụng cũng như kiến trúc sư thích xem 30 dòng mã hơn là đọc nhiều đoạn văn bản. Để hỗ trợ ý định này, chúng tôi thường chỉ hiển thị các phương thức hoặc lớp quan trọng nhất trong một giải pháp có thể lớn hơn. Chúng tôi cũng bỏ qua hầu hết các hình thức kiểm tra lỗi để làm nổi bật chức năng cốt lõi được thực hiện bởi mã. Hầu hết các đoạn mã không chứa nhận xét trong dòng, vì mã đã được giải thích trong các đoạn trước và sau đoạn mã.
Việc cung cấp một ví dụ có ý nghĩa cho một mẫu tích hợp đơn lẻ là một thách thức. Các giải pháp tích hợp doanh nghiệp thường bao gồm nhiều thành phần heterogenous phân bố trên nhiều hệ thống khác nhau. Tương tự, hầu hết các mẫu tích hợp không hoạt động độc lập mà phụ thuộc vào các mẫu khác để hình thành một giải pháp có ý nghĩa. Để làm nổi bật sự hợp tác giữa nhiều mẫu, chúng tôi đã bao gồm các ví dụ toàn diện hơn như những phần giải lao (xem Chương 6, 9 và 12). Những giải pháp này minh họa nhiều sự đánh đổi liên quan đến việc thiết kế một giải pháp nhắn tin toàn diện hơn.
Tất cả các mẫu mã phải được xem như là công cụ minh họa và không phải là điểm khởi đầu cho việc phát triển một giải pháp tích hợp có chất lượng sản xuất. Ví dụ, gần như tất cả các ví dụ đều thiếu kiểm tra lỗi hoặc không quan tâm đến tính bền vững, an ninh hoặc khả năng mở rộng.
Chúng tôi đã cố gắng hết sức để dựa vào các ví dụ trên các nền tảng phần mềm có sẵn miễn phí hoặc phiên bản dùng thử. Trong một số trường hợp, chúng tôi đã sử dụng các nền tảng thương mại (chẳng hạn như TIBCO ActiveEnterprise và Microsoft BizTalk) để minh họa sự khác biệt giữa việc phát triển một giải pháp từ đầu và việc sử dụng một công cụ thương mại. Chúng tôi đã trình bày các ví dụ đó theo cách mà chúng có tính giáo dục ngay cả khi bạn không có quyền truy cập vào nền tảng runtime yêu cầu. Đối với nhiều ví dụ, chúng tôi sử dụng các khung nhắn tin tương đối đơn giản như JMS hoặc MSMQ. Điều này cho phép chúng tôi trở nên rõ ràng hơn trong ví dụ và tập trung vào vấn đề đang được bàn luận thay vì bị phân tâm bởi tất cả các tính năng mà một bộ công cụ middleware phức tạp hơn có thể cung cấp.
Các ví dụ Java trong cuốn sách này dựa trên đặc tả JMS 1.1, là một phần của đặc tả J2EE 1.4. Khi cuốn sách này được xuất bản, hầu hết các nhà cung cấp dịch vụ nhắn tin và máy chủ ứng dụng sẽ hỗ trợ JMS 1.1. Bạn có thể tải xuống phiên bản triển khai tham khảo của đặc tả JMS từ trang web của Sun Microsystems: http://java.sun.com/j2ee.
Các ví dụ về Microsoft .NET dựa trên Phiên bản 1.1 của .NET Framework và được viết bằng C#. Bạn có thể tải về SDK của .NET Framework từ trang web của Microsoft: http://msdn.microsoft.com/net.
Ngôn ngữ mẫu trong cuốn sách này, giống như bất kỳ ngôn ngữ mẫu nào, là một mạng lưới các mẫu tham chiếu lẫn nhau. Đồng thời, một số mẫu là cơ bản hơn những mẫu khác, hình thành nên một hệ thống phân cấp các mẫu khái niệm lớn dẫn đến những mẫu chi tiết hơn. Các mẫu khái niệm lớn là những thành phần chịu tải của ngôn ngữ mẫu. Chúng là những mẫu chính, những mẫu gốc cung cấp nền tảng cho ngôn ngữ và hỗ trợ các mẫu khác.
Cuốn sách này phân loại các mẫu thành các chương theo mức độ trừu tượng và theo lĩnh vực chủ đề. Sơ đồ dưới đây cho thấy các mẫu gốc và mối quan hệ của chúng với các chương trong cuốn sách.
Mối quan hệ giữa các mẫu gốc và các chương

Mẫu hình cơ bản nhất là Nhắn tin; đây là nội dung chính của cuốn sách này. Nó dẫn đến sáu mẫu hình gốc được mô tả trong Chương 3, "Hệ thống Nhắn tin", đó là: Kênh Nhắn tin, Thông điệp, Ống và Bộ lọc, Bộ định tuyến Thông điệp, Bộ dịch Thông điệp và Điểm cuối Thông điệp. Mỗi mẫu hình gốc lại dẫn đến một chương riêng trong cuốn sách (trừ Ống và Bộ lọc, không thuộc về nhắn tin mà là một phong cách kiến trúc được sử dụng rộng rãi và là cơ sở của các mẫu hình định tuyến và biến đổi).
Ngôn ngữ mẫu được chia thành tám chương, theo thứ bậc vừa được mô tả.
Chương 2, "Phong cách tích hợp" Chương này xem xét các phương pháp khác nhau có sẵn để tích hợp các ứng dụng, bao gồm Giao tiếp.
Chương 3, "Hệ thống Nhắn tin" Chương này xem xét sáu mẫu nhắn tin cơ bản, cung cấp cái nhìn tổng quan về toàn bộ ngôn ngữ mẫu.
Chương 4, "Kênh Giao Tiếp" Các ứng dụng giao tiếp thông qua các kênh. Các kênh xác định lộ trình logic mà một tin nhắn có thể đi theo. Chương này sẽ hướng dẫn cách xác định các kênh mà ứng dụng của bạn cần.
Chương 5, "Xây dựng Thông điệp" Khi bạn đã có các kênh thông điệp, bạn cần có những thông điệp để gửi qua chúng. Chương này giải thích các cách khác nhau mà thông điệp có thể được sử dụng và cách tận dụng những đặc điểm đặc biệt của chúng.
Chương 7, "Định tuyến Tin nhắn" Các giải pháp nhắn tin nhằm tách biệt người gửi và người nhận thông tin. Các bộ định tuyến tin nhắn cung cấp khả năng độc lập về vị trí giữa người gửi và người nhận, để người gửi không cần phải biết ai sẽ xử lý tin nhắn của họ. Thay vào đó, họ gửi tin nhắn đến các thành phần định tuyến tin nhắn trung gian, những người sẽ chuyển tiếp tin nhắn đến đích đúng. Chương này trình bày nhiều kỹ thuật định tuyến khác nhau.
Chương 8, "Chuyển Đổi Tin Nhắn" Các ứng dụng phát triển độc lập thường không thống nhất về định dạng của tin nhắn, về hình thức và ý nghĩa của các định danh được cho là độc nhất, hoặc thậm chí về bộ mã ký tự sẽ được sử dụng. Do đó, cần có các thành phần trung gian để chuyển đổi tin nhắn từ định dạng mà một ứng dụng sản xuất sang định dạng của các ứng dụng nhận. Chương này sẽ trình bày cách thiết kế các thành phần chuyển đổi.
Chương 10, "Các Điểm Kết Nối Tin Nhắn" Nhiều ứng dụng không được thiết kế để tham gia vào một giải pháp tin nhắn. Do đó, chúng phải được kết nối rõ ràng với hệ thống nhắn tin. Chương này mô tả một lớp trong ứng dụng có trách nhiệm gửi và nhận các tin nhắn, biến ứng dụng của bạn thành một điểm kết nối cho các tin nhắn.
Chương 11, "Quản lý Hệ thống" Khi một hệ thống nhắn tin đã được thiết lập để tích hợp các ứng dụng, làm thế nào chúng ta có thể đảm bảo rằng nó hoạt động chính xác và thực hiện những gì chúng ta muốn? Chương này khám phá cách kiểm tra và giám sát một hệ thống nhắn tin đang hoạt động.
Tám chương này tổng hợp lại những gì bạn cần biết về việc kết nối các ứng dụng sử dụng messaging.
Với bất kỳ cuốn sách nào có nhiều điều để dạy, thật khó để biết bắt đầu từ đâu, cả cho tác giả và người đọc. Đọc tất cả các trang một cách liên tục đảm bảo bao quát toàn bộ lĩnh vực chủ đề nhưng không phải là cách nhanh nhất để đến với những vấn đề có ích nhất. Bắt đầu với một mẫu nào đó ở giữa ngôn ngữ có thể giống như bắt đầu xem một bộ phim đã chiếu được nửa chừng - bạn thấy điều đang xảy ra nhưng không hiểu ý nghĩa của nó.
May mắn thay, ngôn ngữ mẫu được hình thành xung quanh các mẫu gốc đã được mô tả trước đó. Những mẫu gốc này tập hợp lại cung cấp cái nhìn tổng quan về ngôn ngữ mẫu, và từng cái cung cấp điểm khởi đầu để đào sâu vào chi tiết của thông điệp. Để có cái nhìn tổng quan về ngôn ngữ mà không cần xem xét tất cả các mẫu, hãy bắt đầu bằng cách xem lại các mẫu gốc trong Chương 3.
Chương 2, "Các kiểu tích hợp," cung cấp cái nhìn tổng quan về bốn kỹ thuật tích hợp ứng dụng chính và khẳng định rằng Nhắn tin là phương pháp tốt nhất cho nhiều cơ hội tích hợp. Hãy đọc chương này nếu bạn chưa quen với các vấn đề liên quan đến tích hợp ứng dụng và những ưu nhược điểm của các phương pháp khác nhau có sẵn. Nếu bạn đã hoàn toàn tin tưởng rằng nhắn tin là con đường để đi và muốn bắt đầu với cách sử dụng nhắn tin, bạn có thể bỏ qua chương này hoàn toàn.
Chương 3, "Hệ Thống Nhắn Tin," chứa tất cả các mẫu gốc của ngôn ngữ mẫu này (trừ mẫu Nhắn Tin, nằm ở Chương 2). Để có cái nhìn tổng quan về ngôn ngữ mẫu, hãy đọc (hoặc ít nhất là lướt qua) tất cả các mẫu trong chương này. Để đi sâu vào một chủ đề cụ thể, hãy đọc mẫu gốc của nó, sau đó chuyển đến các mẫu được đề cập ở cuối phần mẫu; những mẫu tiếp theo đó sẽ đều nằm trong một chương có tên theo mẫu gốc.
Sau Chương 2 và 3, các nhà phát triển theo từng loại hình nhắn tin có thể sẽ quan tâm đến các chương khác nhau dựa trên những đặc điểm cụ thể của cách mà mỗi nhóm sử dụng nhắn tin để thực hiện tích hợp.
Các quản trị viên hệ thống có thể quan tâm nhất đến Chương 4, "Kênh Gửi Tin," hướng dẫn về những kênh nào nên tạo ra, và Chương 11, "Quản Lý Hệ Thống," hướng dẫn về cách duy trì một hệ thống gửi tin đang hoạt động.
Các nhà phát triển ứng dụng nên xem Chương 10, "Điểm cuối tin nhắn," để tìm hiểu cách tích hợp ứng dụng với hệ thống nhắn tin và Chương 5, "Xây dựng tin nhắn," để tìm hiểu những tin nhắn nào cần gửi khi nào.
Các nhà tích hợp hệ thống sẽ thu được nhiều lợi ích nhất từ Chương 7, "Định tuyến Tin nhắn" về cách hướng tin nhắn đến người nhận thích hợp và Chương 8, "Chuyển đổi Tin nhắn" về cách chuyển đổi tin nhắn từ định dạng của người gửi sang định dạng của người nhận.
Hãy nhớ rằng khi đọc một mẫu, nếu bạn đang vội, hãy bắt đầu bằng cách chỉ đọc vấn đề và giải pháp. Điều này sẽ cung cấp cho bạn đủ thông tin để xác định xem mẫu đó có thú vị đối với bạn ngay bây giờ và nếu bạn đã biết về mẫu đó. Nếu bạn chưa biết mẫu và nó nghe có vẻ thú vị, hãy tiến hành đọc các phần khác.
Cũng hãy nhớ rằng đây là một ngôn ngữ mẫu, vì vậy các mẫu không nhất thiết phải được đọc theo thứ tự chúng được trình bày trong cuốn sách. Thứ tự của cuốn sách dạy bạn về việc lập trình thông điệp bằng cách xem xét tất cả các chủ đề liên quan theo lượt và thảo luận về các vấn đề liên quan cùng nhau. Để sử dụng các mẫu nhằm giải quyết một vấn đề cụ thể, hãy bắt đầu với một mẫu gốc phù hợp. Bối cảnh của nó giải thích những mẫu nào cần được áp dụng trước mẫu này, ngay cả khi chúng không phải là những mẫu ngay lập tức đứng trước mẫu này trong cuốn sách. Tương tự, phần tiếp theo (đoạn cuối cùng của mẫu) mô tả những mẫu nào nên xem xét áp dụng sau mẫu này, ngay cả khi chúng không phải là những mẫu ngay lập tức theo sau mẫu này trong cuốn sách. Sử dụng mạng lưới các mẫu liên kết, chứ không phải danh sách tuyến tính của các trang sách, để hướng dẫn bạn qua tài liệu.
Vui lòng tìm thông tin đi kèm với cuốn sách này cũng như thông tin liên quan đến tích hợp doanh nghiệp tại trang web của chúng tôi: www.doanhnghiepint.com. Bạn cũng có thể gửi ý kiến, gợi ý và phản hồi của mình đến chúng tôi qua email: authors@doanhnghiepint.com.
Bạn sẽ có một hiểu biết tốt về các khái niệm sau đây, mà là cơ bản cho tài liệu trong cuốn sách này:
Thông điệp là gì.
Hệ thống nhắn tin là gì.
Tại sao nên sử dụng tin nhắn.
Lập trình bất đồng bộ khác với lập trình đồng bộ như thế nào.
Cách tích hợp ứng dụng khác với phân phối ứng dụng như thế nào.
Các loại sản phẩm thương mại nào chứa hệ thống nhắn tin.
Bạn cũng nên có cảm nhận về cách cuốn sách này sẽ dạy bạn sử dụng nhắn tin:
Các mô hình vai trò có vai trò như thế nào trong việc cấu trúc tài liệu.
Ý nghĩa của ký hiệu tùy chỉnh được sử dụng trong các sơ đồ.
Mục đích và phạm vi của các ví dụ.
Sự tổ chức của tài liệu.
Cách bắt đầu học tài liệu.
Bây giờ mà bạn đã hiểu các khái niệm cơ bản và cách mà tài liệu sẽ được trình bày, chúng tôi mời bạn bắt đầu tìm hiểu về tích hợp doanh nghiệp sử dụng tin nhắn.
Chương này minh họa cách mà các mẫu trong cuốn sách này có thể được sử dụng để giải quyết nhiều vấn đề tích hợp khác nhau. Để làm được điều đó, chúng ta sẽ xem xét các kịch bản tích hợp phổ biến và trình bày một ví dụ tích hợp toàn diện. Khi thiết kế giải pháp cho ví dụ này, chúng ta sẽ diễn đạt giải pháp bằng cách sử dụng các mẫu có trong cuốn sách. Ở cuối chương này, bạn sẽ quen thuộc với khoảng hai chục mẫu tích hợp.
Doanh nghiệp thường bao gồm hàng trăm, nếu không muốn nói là hàng ngàn ứng dụng được xây dựng tùy chỉnh, mua từ bên thứ ba, thuộc hệ thống kế thừa, hoặc là một sự kết hợp của các loại đó, vận hành trên nhiều lớp của các nền tảng hệ điều hành khác nhau. Không hiếm khi gặp một doanh nghiệp có 30 trang web khác nhau, ba instance của SAP và vô số giải pháp cho từng phòng ban.
Chúng ta có thể bị cám dỗ để hỏi: Làm thế nào các doanh nghiệp cho phép mình rơi vào một mớ hỗn độn như vậy? Chẳng phải bất kỳ Giám đốc Công nghệ Thông tin (CIO) nào chịu trách nhiệm cho một kiến trúc doanh nghiệp rối rắm như vậy cũng nên bị sa thải sao? Chà, như trong hầu hết các trường hợp, mọi thứ xảy ra đều có lý do của nó.
Trước tiên, việc viết ứng dụng kinh doanh là rất khó. Việc tạo ra một ứng dụng lớn duy nhất để vận hành một doanh nghiệp hoàn chỉnh gần như là điều không thể. Các nhà cung cấp Phần mềm Hoạch định Tài nguyên Doanh nghiệp (ERP) đã đạt được một số thành công trong việc tạo ra các ứng dụng kinh doanh lớn hơn bao giờ hết. Thực tế, tuy nhiên, là ngay cả những "gã khổng lồ" như SAP, Oracle, Peoplesoft và những công ty tương tự chỉ thực hiện một phần nhỏ các chức năng kinh doanh cần thiết trong một doanh nghiệp điển hình. Chúng ta có thể dễ dàng nhận thấy điều này qua thực tế rằng các hệ thống ERP là một trong những điểm tích hợp phổ biến nhất trong các doanh nghiệp hiện nay.
Thứ hai, việc phân tán các chức năng kinh doanh trên nhiều ứng dụng giúp doanh nghiệp có tính linh hoạt trong việc chọn "gói kế toán tốt nhất", phần mềm "quản lý quan hệ khách hàng tốt nhất", cũng như "hệ thống xử lý đơn hàng tốt nhất" cho nhu cầu của mình. Thông thường, các tổ chức CNTT không quan tâm đến một ứng dụng doanh nghiệp đơn lẻ nào có thể làm tất cả, cũng như một ứng dụng như vậy không thể tồn tại do số lượng yêu cầu kinh doanh cá nhân.
Các nhà cung cấp đã học cách phục vụ sở thích này và cung cấp các ứng dụng tập trung xung quanh một chức năng cốt lõi cụ thể. Tuy nhiên, sự thôi thúc không ngừng để thêm chức năng mới vào các gói phần mềm hiện có đã dẫn đến sự tràn chức năng trong các ứng dụng kinh doanh đã đóng gói. Ví dụ, nhiều hệ thống thanh toán đã bắt đầu kết hợp chức năng chăm sóc khách hàng và kế toán. Tương tự, nhà sản xuất phần mềm chăm sóc khách hàng cũng cố gắng triển khai các chức năng thanh toán đơn giản, chẳng hạn như tranh chấp hoặc điều chỉnh. Việc xác định ranh giới chức năng rõ ràng giữa các hệ thống là khó khăn: Một tranh chấp của khách hàng về một hóa đơn có được coi là chức năng chăm sóc khách hàng hay chức năng thanh toán?
Người dùng như khách hàng, đối tác kinh doanh và người sử dụng nội bộ thường không nghĩ về ranh giới hệ thống khi họ tương tác với một doanh nghiệp. Họ thực hiện các chức năng kinh doanh mà không quan tâm đến việc chức năng kinh doanh đó cắt ngang bao nhiêu hệ thống nội bộ. Chẳng hạn, một khách hàng có thể gọi để thay đổi địa chỉ của mình và xem liệu thanh toán cuối cùng đã được nhận hay chưa. Trong nhiều doanh nghiệp, yêu cầu đơn giản này có thể liên quan đến cả hệ thống chăm sóc khách hàng và hệ thống lập hóa đơn. Tương tự, một khách hàng đặt hàng mới có thể yêu cầu sự phối hợp của nhiều hệ thống. Doanh nghiệp cần xác thực ID khách hàng, xác minh tình trạng tốt của khách hàng, kiểm tra hàng tồn kho, thực hiện đơn hàng, nhận báo giá vận chuyển, tính thuế bán hàng, gửi hóa đơn, và nhiều thứ khác. Quy trình này có thể dễ dàng vượt qua năm hoặc sáu hệ thống khác nhau. Từ góc độ của khách hàng, đó là một giao dịch kinh doanh duy nhất.
Để hỗ trợ các quy trình kinh doanh chung và chia sẻ dữ liệu giữa các ứng dụng, các ứng dụng này cần được tích hợp. Tích hợp ứng dụng cần cung cấp việc trao đổi dữ liệu hiệu quả, đáng tin cậy và an toàn giữa nhiều ứng dụng doanh nghiệp.
Thật không may, việc tích hợp doanh nghiệp không phải là một nhiệm vụ dễ dàng. Theo định nghĩa, tích hợp doanh nghiệp phải xử lý nhiều ứng dụng chạy trên nhiều nền tảng ở các vị trí khác nhau, khiến thuật ngữ tích hợp đơn giản gần như trở thành một nghịch lý. Các nhà cung cấp phần mềm cung cấp các bộ giải pháp Tích hợp Ứng dụng Doanh nghiệp (EAI) cung cấp tích hợp đa nền tảng, đa ngôn ngữ cũng như khả năng giao tiếp với nhiều ứng dụng kinh doanh đóng gói phổ biến. Tuy nhiên, hạ tầng kỹ thuật này chỉ giải quyết một phần nhỏ của những phức tạp trong tích hợp. Những thách thức thực sự của việc tích hợp trải rộng xa hơn nhiều trên các vấn đề kinh doanh và kỹ thuật.
Tích hợp doanh nghiệp đòi hỏi một sự thay đổi đáng kể trong chính trị công ty. Các ứng dụng kinh doanh thường tập trung vào một lĩnh vực chức năng cụ thể, chẳng hạn như quản lý quan hệ khách hàng (CRM), lập hóa đơn và tài chính. Điều này dường như là một sự mở rộng của định luật nổi tiếng của Conway: "Các tổ chức thiết kế hệ thống bị ấn định để sản xuất các thiết kế là bản sao của cấu trúc giao tiếp của các tổ chức này." Nhiều nhóm CNTT được tổ chức theo sự phù hợp với các lĩnh vực chức năng này. Sự tích hợp doanh nghiệp thành công cần thiết lập giao tiếp không chỉ giữa nhiều hệ thống máy tính mà còn giữa các đơn vị kinh doanh và các phòng ban CNTT. Trong một ứng dụng doanh nghiệp tích hợp, các nhóm không còn kiểm soát một ứng dụng cụ thể vì mỗi ứng dụng bây giờ là một phần của dòng chảy tổng thể của các ứng dụng và dịch vụ tích hợp.
Do vì phạm vi rộng lớn của chúng, các nỗ lực tích hợp thường có những tác động sâu rộng đến doanh nghiệp. Khi các chức năng chính của doanh nghiệp được tích hợp vào một giải pháp tích hợp, sự hoạt động đúng đắn của giải pháp đó trở nên rất quan trọng đối với doanh nghiệp. Một giải pháp tích hợp gặp sự cố hoặc hoạt động sai lệch có thể khiến doanh nghiệp mất hàng triệu đô la vì những đơn hàng bị mất, các khoản thanh toán bị gửi nhầm và khách hàng không hài lòng.
Một hạn chế quan trọng trong việc phát triển giải pháp tích hợp là lượng kiểm soát hạn chế mà các nhà phát triển tích hợp thường có đối với các ứng dụng tham gia. Trong hầu hết các trường hợp, các ứng dụng là hệ thống kế thừa hoặc các ứng dụng đóng gói mà không thể thay đổi chỉ để kết nối với một giải pháp tích hợp. Điều này thường để lại cho các nhà phát triển tích hợp trong tình huống phải bù đắp cho các khiếm khuyết hoặc những điểm khác biệt bên trong các ứng dụng hoặc sự khác biệt giữa các ứng dụng. Thường thì sẽ dễ dàng hơn để triển khai một phần của giải pháp ngay bên trong các điểm kết nối ứng dụng, nhưng vì lý do chính trị hoặc kỹ thuật, tùy chọn đó có thể không khả dụng.
Mặc dù nhu cầu về giải pháp tích hợp rất rộng rãi, chỉ có vài tiêu chuẩn đã được thiết lập trong lĩnh vực này. Sự xuất hiện của XML, XSL và dịch vụ web chắc chắn đánh dấu bước tiến quan trọng nhất của các tính năng dựa trên tiêu chuẩn trong một giải pháp tích hợp. Tuy nhiên, sự phấn khích xung quanh dịch vụ web cũng đã tạo điều kiện cho sự phân mảnh mới của thị trường, dẫn đến sự xuất hiện ào ạt của các "mở rộng" và "diễn giải" mới về các tiêu chuẩn. Điều này nên nhắc nhở chúng ta rằng sự thiếu khả năng tương tác giữa các sản phẩm "tuân thủ tiêu chuẩn" là một trong những chướng ngại vật chính đối với CORBA, mà đã cung cấp một giải pháp kỹ thuật tinh vi cho việc tích hợp hệ thống.
Các tiêu chuẩn dịch vụ web XML hiện có chỉ giải quyết một phần nhỏ trong những thách thức về tích hợp. Ví dụ, tuyên bố thường gặp rằng XML là ngôn ngữ chung của tích hợp hệ thống có thể gây hiểu lầm. Việc chuẩn hóa tất cả các trao đổi dữ liệu sang XML có thể được so sánh với việc viết tất cả các tài liệu bằng một bảng chữ cái chung, chẳng hạn như bảng chữ cái La Mã. Dù bảng chữ cái là chung, nó vẫn được sử dụng để đại diện cho nhiều ngôn ngữ và phương ngữ khác nhau, mà không phải tất cả người đọc đều có thể hiểu được. Điều tương tự cũng đúng trong tích hợp doanh nghiệp. Sự tồn tại của một cách trình bày chung (ví dụ, XML) không có nghĩa là có ngữ nghĩa chung. Khái niệm "tài khoản" có thể có nhiều ngữ nghĩa, hàm ý, ràng buộc và giả định khác nhau trong từng hệ thống tham gia. Giải quyết sự khác biệt về ngữ nghĩa giữa các hệ thống chứng tỏ là một công việc đặc biệt khó khăn và tốn thời gian vì nó liên quan đến những quyết định quan trọng về kinh doanh và kỹ thuật.
Khi phát triển một giải pháp EAI là một thách thức trong chính nó, việc vận hành và duy trì một giải pháp như vậy có thể còn khó khăn hơn. Sự kết hợp của các công nghệ và tính chất phân tán của các giải pháp EAI làm cho việc triển khai, giám sát và xử lý sự cố trở thành những nhiệm vụ phức tạp đòi hỏi một sự kết hợp các bộ kỹ năng. Trong hầu hết các trường hợp, các bộ kỹ năng này được phân tán qua nhiều cá nhân khác nhau hoặc thậm chí không tồn tại trong các hoạt động CNTT.
Bất kỳ ai đã trải qua một cuộc triển khai EAI đều có thể chứng minh rằng các giải pháp EAI là một thành phần quan trọng trong các chiến lược doanh nghiệp ngày nay - nhưng chúng làm cho cuộc sống của IT trở nên khó khăn hơn, chứ không dễ dàng hơn. Có một khoảng cách lớn giữa tầm nhìn tổng thể về doanh nghiệp tích hợp (được định nghĩa bởi các thuật ngữ như xử lý liên tục, T+1, doanh nghiệp linh hoạt) và việc triển khai cụ thể (Các tham số mà System.Messaging.XmlMessageFormatter đã lấy lại là gì?).
Không có câu trả lời đơn giản cho việc tích hợp doanh nghiệp. Theo ý kiến của chúng tôi, bất kỳ ai tuyên bố rằng việc tích hợp là dễ dàng đều phải cực kỳ thông minh (hoặc ít nhất là thông minh hơn phần còn lại của chúng ta một chút), cực kỳ thiếu hiểu biết (được rồi, hãy nói là lạc quan), hoặc có lợi ích tài chính trong việc khiến bạn tin rằng việc tích hợp là dễ dàng.
Mặc dù tích hợp là một chủ đề rộng và khó khăn, chúng ta luôn có thể quan sát một số người giỏi hơn hẳn những người khác trong vấn đề này. Những người này biết điều gì mà người khác không biết? Vì không có khái niệm nào về "Dạy bản thân tích hợp trong 21 ngày" (cuốn sách này chắc chắn không phải vậy!), nên không có khả năng những người này biết tất cả các câu trả lời cho tích hợp. Tuy nhiên, họ thường đã giải quyết đủ vấn đề tích hợp để có thể so sánh các vấn đề mới với những vấn đề mà họ đã giải quyết trước đó. Họ biết các "mô hình" của các vấn đề và giải pháp liên quan. Họ đã học được những mô hình này theo thời gian thông qua thử nghiệm và sai sót hoặc từ những kiến trúc sư tích hợp có kinh nghiệm khác.
Các mẫu này không phải là các đoạn mã sao chép-dán hoặc các thành phần được đóng gói sẵn, mà là những gợi ý mô tả các giải pháp cho những vấn đề thường xuyên xảy ra. Nếu được sử dụng đúng cách, các mẫu tích hợp có thể giúp lấp đầy khoảng cách rộng giữa tầm nhìn cấp cao về tích hợp và việc triển khai hệ thống thực tế.
Chúng tôi cố tình để định nghĩa về việc tích hợp rất rộng. Đối với chúng tôi, nó có nghĩa là kết nối các hệ thống máy tính, công ty hoặc con người. Trong khi định nghĩa rộng này mang lại cho chúng tôi sự tiện lợi trong việc đưa bất cứ điều gì chúng tôi thấy thú vị vào cuốn sách này, thì cũng có ích khi xem xét kỹ lưỡng một số kịch bản tích hợp phổ biến nhất. Trong suốt nhiều dự án tích hợp, chúng tôi đã nhiều lần gặp phải sáu loại tích hợp sau đây:
Cổng thông tin
Sao chép dữ liệu
Chức năng kinh doanh chia sẻ
Kiến trúc hướng dịch vụ
Quy trình kinh doanh phân tán
Tích hợp doanh nghiệp với doanh nghiệp
Danh sách này chắc chắn không phải là một phân loại hoàn chỉnh về tất cả các vấn đề liên quan đến tích hợp, nhưng nó minh họa cho loại giải pháp mà các kiến trúc sư tích hợp xây dựng. Nhiều dự án tích hợp bao gồm sự kết hợp của nhiều loại hình tích hợp khác nhau. Ví dụ, việc sao chép dữ liệu tham chiếu thường được yêu cầu để kết nối các ứng dụng vào một quy trình kinh doanh phân phối duy nhất.
Cổng Thông Tin

Nhiều người dùng doanh nghiệp phải truy cập nhiều hệ thống khác nhau để trả lời một câu hỏi cụ thể hoặc thực hiện một chức năng kinh doanh duy nhất. Ví dụ, để xác minh trạng thái của một đơn hàng, một đại diện dịch vụ khách hàng có thể phải truy cập vào hệ thống quản lý đơn hàng trên máy chủ chính, cùng với việc đăng nhập vào hệ thống quản lý các đơn hàng được đặt qua Web. Các cổng thông tin tổng hợp thông tin từ nhiều nguồn khác nhau vào một màn hình duy nhất để tránh việc người dùng phải truy cập nhiều hệ thống để lấy thông tin. Các cổng thông tin đơn giản chia màn hình thành nhiều vùng, mỗi vùng hiển thị thông tin từ một hệ thống khác nhau. Các hệ thống tinh vi hơn cung cấp sự tương tác hạn chế giữa các vùng; ví dụ, khi người dùng chọn một mục từ danh sách ở vùng A, vùng B sẽ làm mới với thông tin chi tiết về mục đã chọn. Các cổng khác cung cấp tương tác người dùng tinh vi hơn và làm mờ ranh giới giữa một cổng và một ứng dụng được tích hợp.
Sao chép dữ liệu

Nhiều hệ thống kinh doanh yêu cầu truy cập vào cùng một dữ liệu. Ví dụ, địa chỉ của khách hàng có thể được sử dụng trong hệ thống chăm sóc khách hàng (khi khách hàng gọi để thay đổi), hệ thống kế toán (để tính thuế bán hàng), hệ thống vận chuyển (để gán nhãn cho đơn hàng), và hệ thống thanh toán (để gửi hóa đơn). Nhiều hệ thống này có kho dữ liệu riêng của chúng để lưu trữ thông tin liên quan đến khách hàng. Khi một khách hàng gọi để thay đổi địa chỉ của họ, tất cả các hệ thống này cần thay đổi bản sao địa chỉ của khách hàng. Điều này có thể được thực hiện bằng cách triển khai một chiến lược tích hợp dựa trên việc sao chép dữ liệu.
Có nhiều cách khác nhau để triển khai sao chép dữ liệu. Ví dụ, một số nhà cung cấp cơ sở dữ liệu tích hợp các chức năng sao chép vào cơ sở dữ liệu; thay vào đó, chúng ta có thể xuất dữ liệu ra tệp và nhập lại chúng vào hệ thống khác, hoặc chúng ta có thể sử dụng phần mềm trung gian dựa trên tin nhắn để vận chuyển các bản ghi dữ liệu trong các tin nhắn.
Chức năng kinh doanh chia sẻ

Theo cách mà nhiều ứng dụng doanh nghiệp lưu trữ dữ liệu dư thừa, chúng cũng có xu hướng triển khai chức năng dư thừa. Nhiều hệ thống có thể cần kiểm tra xem số an sinh xã hội có hợp lệ không, địa chỉ có khớp với mã bưu chính đã chỉ định hay không, hoặc một mặt hàng cụ thể có sẵn trong kho hay không. Việc công khai những chức năng này như một chức năng kinh doanh chung được triển khai một lần và có sẵn như một dịch vụ cho các hệ thống khác là hợp lý.
Một chức năng kinh doanh chia sẻ có thể đáp ứng một số nhu cầu giống như sao chép dữ liệu. Ví dụ, chúng ta có thể triển khai một chức năng kinh doanh gọi là Lấy Địa Chỉ Khách Hàng, cho phép các hệ thống khác yêu cầu địa chỉ của khách hàng khi cần thay vì lưu trữ một bản sao dư thừa. Quyết định giữa hai phương pháp này được điều khiển bởi một số tiêu chí, chẳng hạn như mức độ kiểm soát mà chúng ta có đối với các hệ thống (gọi một chức năng chia sẻ thường xâm nhập hơn so với việc tải dữ liệu vào cơ sở dữ liệu) hoặc tần suất thay đổi (một địa chỉ có thể cần thường xuyên nhưng thay đổi rất ít).
Kiến trúc hướng dịch vụ

Chức năng kinh doanh chung thường được gọi là dịch vụ. Một dịch vụ là một chức năng được xác định rõ ràng, có sẵn cho mọi người và phản hồi theo yêu cầu từ "người tiêu dùng dịch vụ". Khi một doanh nghiệp tập hợp một bộ sưu tập các dịch vụ hữu ích, việc quản lý các dịch vụ trở thành một chức năng quan trọng. Đầu tiên, các ứng dụng cần một dạng danh mục dịch vụ, một danh sách tập trung tất cả các dịch vụ có sẵn. Thứ hai, mỗi dịch vụ cần mô tả giao diện của nó sao cho một ứng dụng có thể "thương lượng" một hợp đồng giao tiếp với dịch vụ. Hai chức năng này, phát hiện dịch vụ và thương lượng, là những yếu tố chính cấu thành nên kiến trúc hướng dịch vụ (SOA).
SOA làm nhòa ranh giới giữa ứng dụng tích hợp và ứng dụng phân tán. Một ứng dụng mới có thể được phát triển bằng cách sử dụng các dịch vụ từ xa hiện có có thể được cung cấp bởi các ứng dụng khác. Do đó, việc gọi một dịch vụ có thể được coi là sự tích hợp giữa hai ứng dụng. Tuy nhiên, hầu hết các SOA cung cấp công cụ giúp việc gọi một dịch vụ bên ngoài gần như đơn giản như gọi một phương thức cục bộ (các yếu tố về hiệu suất sang một bên), nên quá trình phát triển một ứng dụng trên nền tảng SOA giống như việc xây dựng một ứng dụng phân tán.
Quy trình kinh doanh phân tán

Một trong những yếu tố chính thúc đẩy sự tích hợp là một giao dịch kinh doanh đơn lẻ thường được phân tán qua nhiều hệ thống khác nhau. Một ví dụ trước đây cho thấy rằng một chức năng kinh doanh đơn giản như đặt hàng có thể dễ dàng liên quan đến nửa tá hệ thống. Trong hầu hết các trường hợp, tất cả các chức năng liên quan đều được tích hợp trong các ứng dụng hiện có. Điều còn thiếu là sự phối hợp giữa những ứng dụng này. Do đó, chúng ta có thể thêm một thành phần quản lý quy trình kinh doanh để quản lý việc thực hiện một chức năng kinh doanh qua nhiều hệ thống hiện có.
Ranh giới giữa kiến trúc dịch vụ (SOA) và một doanh nghiệp phân tán có thể không rõ ràng. Ví dụ, bạn có thể công khai tất cả các chức năng kinh doanh liên quan như các dịch vụ và sau đó mã hóa quy trình kinh doanh bên trong một ứng dụng truy cập tất cả các dịch vụ thông qua SOA.
Tích hợp Doanh Nghiệp với Doanh Nghiệp

Cho đến nay, chúng ta chủ yếu đã xem xét sự tương tác giữa các ứng dụng và các chức năng kinh doanh bên trong một doanh nghiệp duy nhất. Trong nhiều trường hợp, các chức năng kinh doanh có thể được cung cấp từ các nhà cung cấp hoặc đối tác kinh doanh bên ngoài. Ví dụ, công ty vận chuyển có thể cung cấp dịch vụ cho khách hàng để tính toán chi phí vận chuyển hoặc theo dõi các lô hàng. Hoặc một doanh nghiệp có thể sử dụng một nhà cung cấp bên ngoài để tính toán tỷ lệ thuế bán hàng. Tương tự, việc tích hợp thường xảy ra giữa các đối tác kinh doanh. Một khách hàng có thể liên hệ với một nhà bán lẻ để hỏi về giá cả và tình trạng sẵn có của một mặt hàng. Để phản hồi, nhà bán lẻ có thể hỏi nhà cung cấp về tình trạng của một lô hàng dự kiến chứa mặt hàng đang hết hàng.
Nhiều trong số các yếu tố trên cũng áp dụng cho việc tích hợp giữa các doanh nghiệp. Tuy nhiên, việc giao tiếp qua Internet hoặc mạng lưới khác thường đặt ra những vấn đề mới liên quan đến giao thức vận chuyển và bảo mật. Hơn nữa, vì nhiều đối tác kinh doanh có thể hợp tác trong một "cuộc trò chuyện" điện tử, nên các định dạng dữ liệu tiêu chuẩn là vô cùng quan trọng.
Một trong những từ khóa lớn nhất trong kiến trúc doanh nghiệp và tích hợp là tách rời lỏng. Thực tế, đây là một thuật ngữ phổ biến đến mức Doug Kaye đã viết một cuốn sách mang tựa đề theo khái niệm phổ biến này [Kaye]. Lợi ích của tách rời lỏng đã được biết đến từ khá lâu, nhưng gần đây chúng đã trở thành tâm điểm do sự gia tăng phổ biến của kiến trúc dịch vụ Web.
Nguyên tắc cốt lõi của việc kết nối lỏng là giảm bớt những giả định mà hai bên (các thành phần, ứng dụng, dịch vụ, chương trình, người dùng) đặt ra về nhau khi họ trao đổi thông tin. Càng nhiều giả định mà hai bên đặt ra về nhau và giao thức chung, thì giao tiếp có thể hiệu quả hơn, nhưng giải pháp sẽ ít dung thứ hơn đối với sự gián đoạn hoặc thay đổi vì các bên được gắn kết chặt chẽ với nhau.
Một ví dụ tuyệt vời về sự liên kết chặt chẽ là việc gọi phương thức cục bộ. Việc gọi một phương thức cục bộ trong một ứng dụng dựa trên rất nhiều giả định giữa phương thức được gọi và phương thức gọi. Cả hai phương thức phải chạy trong cùng một quy trình (ví dụ: một máy ảo) và được viết bằng cùng một ngôn ngữ (hoặc ít nhất là sử dụng một ngôn ngữ trung gian hoặc mã byte chung). Phương thức gọi phải truyền đúng số lượng tham số mong đợi bằng các kiểu dữ liệu đã thỏa thuận. Cuộc gọi là ngay lập tức; tức là phương thức được gọi bắt đầu xử lý ngay lập tức sau khi phương thức gọi thực hiện cuộc gọi. Trong khi đó, phương thức gọi sẽ tiếp tục xử lý chỉ khi phương thức được gọi hoàn tất (nghĩa là việc gọi là đồng bộ). Xử lý sẽ tự động tiếp tục trong phương thức gọi với câu lệnh ngay sau cuộc gọi phương thức. Sự giao tiếp giữa các phương thức là ngay lập tức và tức thời, vì vậy cả phương thức gọi và phương thức được gọi đều không phải lo lắng về những vi phạm bảo mật dưới hình thức nghe lén từ các bên thứ ba. Tất cả những giả định này làm cho việc viết các ứng dụng có cấu trúc tốt trở nên rất dễ dàng, chia chức năng thành các phương thức cá nhân để được gọi bởi các phương thức khác. Số lượng lớn các phương thức nhỏ như vậy cho phép tính linh hoạt và tái sử dụng.
Nhiều phương pháp tích hợp đã nhằm mục đích đơn giản hóa việc giao tiếp từ xa bằng cách đóng gói một trao đổi dữ liệu từ xa vào cùng một ngữ nghĩa như một lời gọi phương thức cục bộ. Chiến lược này đã dẫn đến khái niệm Gọi Thủ Tục Từ Xa (RPC) hoặc Gọi Phương Thức Từ Xa (RMI), được hỗ trợ bởi nhiều framework và nền tảng phổ biến: CORBA (xem [Zahavi]), Microsoft DCOM, .NET Remoting, Java RMI và gần đây nhất là các dịch vụ web theo phong cách RPC. Lợi ích dự kiến của cách tiếp cận này là hai chiều. Đầu tiên, ngữ nghĩa của lời gọi phương thức đồng bộ rất quen thuộc với các nhà phát triển ứng dụng, vậy tại sao không xây dựng dựa trên những gì chúng ta đã biết? Thứ hai, việc sử dụng cùng một cú pháp và ngữ nghĩa cho cả lời gọi phương thức cục bộ và các lời gọi từ xa sẽ cho phép chúng ta hoãn lại đến thời điểm triển khai quyết định về việc các thành phần nào nên chạy cục bộ và các thành phần nào nên chạy từ xa, giúp nhà phát triển ứng dụng giảm bớt một mối lo.
Thách thức mà tất cả các phương pháp này phải đối mặt nằm ở chỗ giao tiếp từ xa làm vô hiệu hóa nhiều giả định mà một cuộc gọi phương thức cục bộ dựa vào. Do đó, việc trừu tượng hóa giao tiếp từ xa thành ngữ nghĩa đơn giản của một cuộc gọi phương thức có thể gây nhầm lẫn và sai lệch. Waldo và các đồng nghiệp đã nhắc nhở chúng ta từ năm 1994 rằng "các đối tượng diễn ra trong một hệ thống phân tán cần được xử lý bằng các cách thức có bản chất khác biệt so với các đối tượng tương tác trong một không gian địa chỉ duy nhất" [Waldo]. Ví dụ, nếu chúng ta gọi một dịch vụ từ xa để thực hiện một chức năng cho chúng ta, liệu chúng ta có thực sự muốn giới hạn bản thân vào chỉ những dịch vụ được xây dựng bằng cùng một ngôn ngữ lập trình mà chúng ta sử dụng không? Một cuộc gọi qua mạng cũng thường chậm hơn nhiều lần so với một cuộc gọi cục bộ. Liệu phương thức gọi có thực sự nên chờ cho đến khi phương thức được gọi hoàn tất không? Điều gì sẽ xảy ra nếu mạng bị gián đoạn và phương thức được gọi tạm thời không thể truy cập được? Chúng ta nên chờ bao lâu? Làm thế nào để chúng ta có thể đảm bảo rằng chúng ta đang giao tiếp với bên mong muốn và không phải một "kẻ giả mạo" bên thứ ba? Làm thế nào để chúng ta bảo vệ chống lại việc nghe lén? Điều gì sẽ xảy ra nếu chữ ký phương thức (danh sách các tham số mong đợi) của phương thức được gọi thay đổi? Nếu phương thức từ xa được duy trì bởi một bên thứ ba hoặc một đối tác kinh doanh, chúng ta không còn kiểm soát được các thay đổi như vậy. Chúng ta nên để cuộc gọi phương thức của mình thất bại, hay chúng ta nên cố gắng tìm kiếm ánh xạ tốt nhất có thể giữa các tham số và vẫn thực hiện cuộc gọi? Rõ ràng là việc tích hợp từ xa nảy sinh rất nhiều vấn đề mà một cuộc gọi phương thức cục bộ chưa bao giờ phải đối mặt.
Tóm lại, việc cố gắng diễn đạt giao tiếp từ xa như một biến thể của phương pháp gọi cục bộ là điều dễ gây ra rắc rối. Những kiến trúc gắn chặt như vậy thường dẫn đến những giải pháp dễ gãy, khó bảo trì và kém khả năng mở rộng. Nhiều người tiên phong trong dịch vụ Web gần đây đã (tái) phát hiện ra sự thật này theo cách khó khăn.
Để chỉ ra những tác động của các phụ thuộc chặt chẽ và cách giải quyết chúng, hãy xem xét một cách rất đơn giản để kết nối hai hệ thống. Giả sử chúng ta đang xây dựng một hệ thống ngân hàng trực tuyến cho phép khách hàng gửi tiền vào tài khoản của họ từ một ngân hàng khác. Để thực hiện chức năng này, ứng dụng web front-end phải được tích hợp với hệ thống tài chính back-end quản lý việc chuyển tiền.
Cách đơn giản nhất để kết nối hai hệ thống là thông qua giao thức TCP/IP. Mọi hệ điều hành hay thư viện lập trình đáng tự hào nào được tạo ra trong 15 năm qua đều chắc chắn có một ngăn xếp TCP/IP. TCP/IP là giao thức truyền thông phổ biến mà vận chuyển dữ liệu giữa hàng triệu máy tính được kết nối với Internet và các mạng cục bộ. Tại sao không sử dụng giao thức mạng phổ biến nhất để giao tiếp giữa hai ứng dụng?
Để giữ mọi thứ đơn giản, hãy giả sử rằng hàm từ xa để gửi tiền vào tài khoản của một người chỉ nhận tên của người đó và số tiền bằng đô la làm các đối số. Một vài dòng mã sau đây đủ để gọi một hàm như vậy qua TCP/IP (chúng tôi chọn C#, nhưng mã này sẽ trông gần như giống hệt trong C hoặc Java).
String hostName = "finance.bank.com"; int port = 80; IPHostEntry hostInfo = Dns.GetHostByName(hostName); IPAddress address = hostInfo.AddressList[0]; IPEndPoint endpoint = new IPEndPoint(address, port); Socket socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); socket.Connect(endpoint); byte[] amount = BitConverter.GetBytes(1000); byte[] name = Encoding.ASCII.GetBytes("Joe"); int bytesSent = socket.Send(amount); bytesSent += socket.Send(name); socket.Close(); Mã này mở một kết nối socket đến địa chỉ finance.bank.com và gửi hai dữ liệu (số tiền và tên khách hàng) qua mạng. Không cần phần mềm trung gian đắt tiền: không cần công cụ EAI, không cần bộ công cụ RPC - chỉ cần 10 dòng mã. Khi chúng ta chạy mã này, nó thông báo "7 byte đã được gửi." Thật tuyệt! Làm thế nào mà việc tích hợp lại có thể khó khăn?
Có một vài vấn đề lớn với nỗ lực tích hợp này. Một trong những điểm mạnh của giao thức TCP/IP là sự hỗ trợ rộng rãi, cho phép chúng ta kết nối với hầu hết mọi máy tính được kết nối với mạng mà không cần quan tâm đến hệ điều hành hoặc ngôn ngữ lập trình mà nó sử dụng. Tuy nhiên, tính độc lập với nền tảng chỉ hoạt động với các thông điệp rất đơn giản: luồng byte. Để chuyển đổi dữ liệu của chúng tôi thành một luồng byte, chúng tôi đã sử dụng lớp BitConverter. Lớp này chuyển đổi bất kỳ kiểu dữ liệu nào thành một mảng byte, sử dụng cách đại diện bộ nhớ nội bộ của kiểu dữ liệu. Vấn đề là cách đại diện nội bộ của một số nguyên thay đổi tùy theo hệ thống máy tính. Ví dụ, .NET sử dụng số nguyên 32 bit, trong khi các hệ thống khác có thể sử dụng cách đại diện 64 bit. Ví dụ của chúng tôi truyền 4 byte qua mạng để đại diện cho một số nguyên 32 bit. Một hệ thống sử dụng 64 bit sẽ có xu hướng đọc 8 byte từ mạng và sẽ kết thúc với việc diễn giải toàn bộ thông điệp (bao gồm tên khách hàng) như một số duy nhất.
Ngoài ra, một số hệ thống máy tính lưu trữ số của họ theo định dạng big-endian, trong khi những hệ thống khác lưu trữ theo định dạng little-endian. Định dạng big-endian lưu trữ số bắt đầu với byte cao nhất trước, trong khi các hệ thống little-endian lưu trữ byte thấp nhất trước. Máy tính cá nhân hoạt động theo sơ đồ little-endian để mã được truyền qua 4 byte sau qua mạng.
232 3 0 0
`232 + 3 * 2 bằng 1,000. Một hệ thống sử dụng số big-endian sẽ coi thông điệp này có nghĩa là 232 * 2 + 3 * 2 = 3,892,510,720. Joe sẽ trở thành một người rất giàu có! Vì vậy, cách tiếp cận này chỉ hoạt động dưới giả định rằng tất cả các máy tính kết nối đều biểu diễn số theo cùng một định dạng nội bộ.`
Vấn đề thứ hai với cách tiếp cận đơn giản này là chúng ta chỉ định vị trí của máy tính từ xa (trong trường hợp của chúng ta, finance.bank.com). Dịch vụ Đặt tên Động (DNS) cung cấp cho chúng ta một cấp độ gián tiếp giữa tên miền và địa chỉ IP, nhưng nếu chúng ta muốn chuyển chức năng sang một máy tính khác trên một miền khác thì sao? Nếu máy tính gặp sự cố và chúng ta phải thiết lập một máy khác thì sao? Nếu chúng ta muốn gửi thông tin đến nhiều máy tính hơn một thì sao? Cho mỗi kịch bản, chúng ta đều phải thay đổi mã nguồn. Nếu chúng ta sử dụng nhiều hàm từ xa, điều này có thể trở nên rất tẻ nhạt. Do đó, chúng ta nên tìm cách làm cho giao tiếp của mình độc lập với một máy tính cụ thể trên mạng.
Ví dụ TCP/IP đơn giản của chúng tôi cũng thiết lập các phụ thuộc tạm thời giữa hai máy móc. TCP/IP là một giao thức định hướng kết nối. Trước khi bất kỳ dữ liệu nào có thể được chuyển giao, một kết nối phải được thiết lập trước. Việc thiết lập một kết nối TCP liên quan đến việc các gói IP di chuyển qua lại giữa người gửi và người nhận. Điều này yêu cầu cả hai máy và mạng đều phải có sẵn cùng một lúc. Nếu bất kỳ phần nào trong ba phần này bị trục trặc hoặc không có sẵn do tải cao, dữ liệu không thể được gửi.
Cuối cùng, giao tiếp đơn giản cũng dựa vào một định dạng dữ liệu rất nghiêm ngặt. Chúng tôi đang gửi 4 byte dữ liệu số tiền và sau đó là một chuỗi các ký tự định nghĩa tài khoản của khách hàng. Nếu chúng tôi muốn chèn một tham số thứ ba, chẳng hạn như tên của loại tiền tệ, chúng tôi sẽ phải sửa đổi cả bên gửi và bên nhận để sử dụng định dạng dữ liệu mới.
Tương tác kết nối chặt chẽ

Giải pháp tích hợp tối giản của chúng tôi nhanh chóng và rẻ, nhưng dẫn đến một giải pháp rất yếu ớt vì hai bên tham gia có những giả định sau đây về nhau:
Công nghệ nền tảng các đại diện nội bộ của số và đối tượng
Địa điểm địa chỉ máy được mã hóa cứng
Thời gian tất cả các thành phần phải có sẵn cùng một lúc
Định dạng dữ liệu danh sách các tham số và loại của chúng phải khớp.
Như chúng tôi đã đề cập trước đó, coupling là một thước đo cho biết số lượng giả định mà các bên thực hiện về nhau khi họ giao tiếp. Giải pháp đơn giản của chúng tôi yêu cầu các bên phải thực hiện nhiều giả định. Do đó, giải pháp này là liên kết chặt chẽ.
Để làm cho giải pháp trở nên ít liên kết hơn, chúng ta có thể cố gắng loại bỏ các phụ thuộc này từng bước một. Chúng ta nên sử dụng một định dạng dữ liệu chuẩn mà tự mô tả và độc lập với nền tảng, chẳng hạn như XML. Thay vì gửi thông tin trực tiếp đến một máy cụ thể, chúng ta nên gửi nó đến một kênh có thể địa chỉ được. Một kênh là một địa chỉ logic mà cả người gửi và người nhận có thể đồng thuận mà không cần biết danh tính của nhau. Việc sử dụng các kênh giải quyết được phụ thuộc vị trí nhưng vẫn yêu cầu tất cả các thành phần phải có mặt cùng một lúc nếu kênh được triển khai bằng một giao thức định hướng kết nối. Để loại bỏ sự phụ thuộc tạm thời này, chúng ta có thể tăng cường kênh để xếp hàng các yêu cầu gửi cho đến khi mạng và hệ thống nhận sẵn sàng. Người gửi giờ có thể gửi yêu cầu vào kênh và tiếp tục xử lý mà không cần lo lắng về việc giao hàng dữ liệu. Việc xếp hàng yêu cầu bên trong kênh yêu cầu dữ liệu phải được chia thành các thông điệp tự chứa, để kênh biết được lượng dữ liệu cần đệm và giao hàng tại bất kỳ thời điểm nào. Hai hệ thống vẫn phụ thuộc vào một định dạng dữ liệu chung, nhưng chúng ta có thể loại bỏ sự phụ thuộc này bằng cách cho phép các biến đổi định dạng dữ liệu bên trong kênh. Nếu định dạng của một hệ thống thay đổi, chúng ta chỉ cần thay đổi bộ chuyển đổi mà không cần thay đổi các hệ thống tham gia khác. Điều này đặc biệt hữu ích nếu nhiều ứng dụng gửi dữ liệu đến cùng một kênh.
Tương tác lỏng lẻo

Các cơ chế như định dạng dữ liệu chung, giao tiếp bất đồng bộ qua các kênh xếp hàng và bộ chuyển đổi giúp biến một giải pháp liên kết chặt chẽ thành một giải pháp liên kết lỏng lẻo. Người gửi không còn phải phụ thuộc vào định dạng dữ liệu nội bộ của người nhận cũng như vị trí của nó. Họ thậm chí không cần phải chú ý đến việc máy tính khác đã sẵn sàng chấp nhận yêu cầu hay chưa. Việc loại bỏ những phụ thuộc này giữa các hệ thống làm cho giải pháp tổng thể trở nên tolérance hơn với sự thay đổi, lợi ích chính của việc liên kết lỏng lẻo. Nhược điểm chính của cách tiếp cận liên kết lỏng lẻo là sự phức tạp bổ sung. Đây không còn là một giải pháp chỉ với 10 dòng mã nữa! Do đó, chúng tôi sử dụng một hạ tầng phần mềm trung gian định hướng tin nhắn cung cấp những dịch vụ này cho chúng tôi. Hạ tầng này giúp việc trao đổi dữ liệu theo cách liên kết lỏng lẻo trở nên dễ dàng gần như ví dụ mà chúng tôi đã bắt đầu. Phần tiếp theo mô tả các thành phần tạo nên một giải pháp phần mềm trung gian như vậy.
Kết nối lỏng có phải là phương thuốc vạn năng? Giống như mọi thứ khác trong kiến trúc doanh nghiệp, không có câu trả lời tốt nhất duy nhất. Kết nối lỏng mang lại những lợi ích quan trọng như tính linh hoạt và khả năng mở rộng, nhưng nó cũng giới thiệu một mô hình lập trình phức tạp hơn và có thể khiến việc thiết kế, xây dựng và gỡ lỗi các giải pháp trở nên khó khăn hơn.
Để kết nối hai hệ thống qua một giải pháp tích hợp, cần phải giải quyết một số vấn đề. Những chức năng này tạo thành những gì chúng tôi gọi là phần mềm trung gian - chất kết dính nằm giữa các ứng dụng.
Luôn luôn, một số dữ liệu phải được vận chuyển từ ứng dụng này sang ứng dụng khác. Dữ liệu này có thể là một bản ghi địa chỉ cần được nhân bản, một lời gọi đến dịch vụ từ xa, hoặc một đoạn HTML dành cho hiển thị trên cổng thông tin. Bất kể tải trọng như thế nào, mảnh dữ liệu này cần phải được hiểu bởi cả hai bên và cần được vận chuyển qua mạng. Hai yếu tố cung cấp chức năng cơ bản này. Chúng ta cần một kênh truyền thông có thể di chuyển thông tin từ ứng dụng này sang ứng dụng khác. Kênh này có thể bao gồm một loạt các kết nối TCP/IP, một tệp tin chia sẻ, một cơ sở dữ liệu chia sẻ, hoặc một đĩa mềm được mang từ máy tính này sang máy tính khác (được gọi là "sneakernet" nổi tiếng). Bên trong kênh này, chúng ta đặt một thông điệp - một đoạn dữ liệu có ý nghĩa đã được thống nhất giữa cả hai ứng dụng cần được tích hợp. Mảnh dữ liệu này có thể rất nhỏ, như số điện thoại của một khách hàng duy nhất đã thay đổi, hoặc nó có thể rất lớn, như danh sách hoàn chỉnh tất cả khách hàng và địa chỉ liên quan của họ.
Các yếu tố cơ bản của Tích hợp Dựa trên Tin nhắn

Bây giờ chúng ta có thể gửi tin nhắn qua các kênh, chúng ta có thể thiết lập một hình thức tích hợp rất cơ bản. Tuy nhiên, chúng tôi đã hứa rằng tích hợp đơn giản là một nghịch lý, vì vậy hãy xem điều gì đang thiếu. Chúng tôi đã đề cập rằng các giải pháp tích hợp thường có quyền kiểm soát hạn chế đối với các ứng dụng mà họ đang tích hợp, chẳng hạn như các định dạng dữ liệu nội bộ được sử dụng bởi các ứng dụng. Ví dụ, một định dạng dữ liệu có thể lưu trữ tên khách hàng trong hai trường, được gọi là FIRST_NAME và LAST_NAME, trong khi hệ thống khác có thể sử dụng một trường duy nhất gọi là Customer_Name. Tương tự, một hệ thống có thể hỗ trợ nhiều địa chỉ khách hàng, trong khi hệ thống khác chỉ hỗ trợ một địa chỉ duy nhất. Bởi vì định dạng dữ liệu nội bộ của một ứng dụng thường không thể thay đổi, phần mềm trung gian cần cung cấp một cơ chế nào đó để chuyển đổi định dạng dữ liệu của một ứng dụng sang định dạng của ứng dụng khác. Chúng tôi gọi bước này là dịch.
Cho đến nay, chúng ta có thể gửi dữ liệu từ hệ thống này sang hệ thống khác và điều chỉnh sự khác biệt trong định dạng dữ liệu. Điều gì xảy ra nếu chúng ta tích hợp nhiều hơn hai hệ thống? Dữ liệu cần được di chuyển đến đâu? Chúng ta có thể mong đợi mỗi ứng dụng xác định hệ thống mục tiêu cho dữ liệu mà nó đang gửi qua kênh. Ví dụ, nếu địa chỉ khách hàng thay đổi trong hệ thống chăm sóc khách hàng, chúng ta có thể làm cho hệ thống đó chịu trách nhiệm gửi dữ liệu đến tất cả các hệ thống khác lưu trữ bản sao của địa chỉ khách hàng. Khi số lượng hệ thống tăng lên, điều này trở nên rất rườm rà và yêu cầu hệ thống gửi phải có kiến thức về tất cả các hệ thống khác. Mỗi khi một hệ thống mới được thêm vào, hệ thống chăm sóc khách hàng sẽ cần được điều chỉnh cho phù hợp với môi trường mới. Mọi thứ sẽ trở nên dễ dàng hơn rất nhiều nếu phần mềm trung gian có thể lo việc gửi tin nhắn đến các địa điểm chính xác. Đây là vai trò của một thành phần định tuyến, chẳng hạn như một trình môi giới tin nhắn.
Giải pháp tích hợp có thể nhanh chóng trở nên phức tạp vì chúng xử lý nhiều ứng dụng, định dạng dữ liệu, kênh, định tuyến và chuyển đổi. Tất cả các yếu tố này có thể được phân bổ trên nhiều nền tảng vận hành và vị trí địa lý khác nhau. Để có bất kỳ ý tưởng nào về những gì đang diễn ra bên trong hệ thống, chúng ta cần một chức năng quản lý hệ thống. Hệ thống con này giám sát luồng dữ liệu, đảm bảo rằng tất cả các ứng dụng và thành phần đều hoạt động và báo cáo các điều kiện lỗi về một vị trí trung tâm.
Giải pháp tích hợp của chúng tôi hiện đã gần hoàn thiện. Chúng tôi có thể di chuyển dữ liệu từ hệ thống này sang hệ thống khác, điều chỉnh sự khác biệt trong định dạng dữ liệu, chuyển dữ liệu đến các hệ thống cần thiết và theo dõi hiệu suất của giải pháp. Cho đến nay, chúng tôi giả định rằng một ứng dụng gửi dữ liệu dưới dạng tin nhắn đến kênh. Tuy nhiên, hầu hết các ứng dụng gói sẵn và ứng dụng kế thừa cũng như nhiều ứng dụng tùy chỉnh không được chuẩn bị để tham gia vào một giải pháp tích hợp. Chúng tôi cần một điểm cuối tin nhắn để kết nối hệ thống một cách rõ ràng với giải pháp tích hợp. Điểm cuối có thể là một đoạn mã đặc biệt hoặc một Bộ điều hợp Kênh được cung cấp bởi nhà cung cấp phần mềm tích hợp.
Cách tốt nhất để hiểu giải pháp tích hợp dựa trên thông điệp là thông qua một ví dụ cụ thể. Hãy cùng xem xét Widgets & Gadgets 'R Us (WGRUS), một nhà bán lẻ trực tuyến mua các dụng cụ và thiết bị từ các nhà sản xuất và bán lại cho khách hàng.
Hệ sinh thái WGRUS

Trong ví dụ này, chúng tôi giả định rằng giải pháp cần hỗ trợ các yêu cầu sau. Tất nhiên, chúng tôi đã đơn giản hóa một chút các yêu cầu để tiết kiệm thời gian, nhưng những loại yêu cầu như vậy xảy ra thường xuyên trong các doanh nghiệp thực tế.
Nhận Đơn Hàng: Khách hàng có thể đặt hàng qua Web, điện thoại hoặc fax.
Xử lý Đơn hàng: Việc xử lý một đơn hàng bao gồm nhiều bước, bao gồm kiểm tra tồn kho, vận chuyển hàng hóa và lập hóa đơn cho khách hàng.
Kiểm tra trạng thái: Khách hàng có thể kiểm tra trạng thái đơn hàng.
Thay đổi địa chỉ: Khách hàng có thể sử dụng giao diện Web để thay đổi địa chỉ thanh toán và giao hàng.
Danh mục mới: Các nhà cung cấp cập nhật danh mục của họ định kỳ. WGRUS cần cập nhật giá cả và tình trạng sẵn có dựa trên các danh mục mới.
Thông báo: Khách hàng có thể đăng ký nhận các thông báo lựa chọn từ WGRUS.
Kiểm tra và Giám sát: Nhân viên vận hành cần có khả năng giám sát tất cả các thành phần riêng lẻ và luồng tin nhắn giữa chúng.
Chúng tôi sẽ giải quyết từng yêu cầu này một cách riêng biệt và mô tả các lựa chọn giải pháp và các phương án đánh đổi bằng ngôn ngữ mẫu được giới thiệu trong cuốn sách này. Chúng tôi sẽ bắt đầu với một kiến trúc luồng tin nhắn đơn giản và giới thiệu các khái niệm phức tạp hơn, chẳng hạn như Quản lý Quy trình, khi chúng tôi giải quyết những yêu cầu ngày càng phức tạp hơn.
Như trong hầu hết các kịch bản tích hợp, WGRUS không phải là một triển khai "mới hoàn toàn", mà là việc tích hợp một hạ tầng CNTT hiện có gồm nhiều ứng dụng đóng gói và tùy chỉnh khác nhau. Việc phải làm việc với các ứng dụng hiện có thường làm cho công việc tích hợp trở nên khó khăn. Trong ví dụ của chúng tôi, WGRUS vận hành các hệ thống sau (xem hình).
Hạ tầng CNTT WGRUS

WGRUS có bốn kênh khác nhau để tương tác với khách hàng. Khách hàng có thể truy cập trang web của công ty, gọi đến đại diện dịch vụ khách hàng tại trung tâm cuộc gọi, hoặc gửi đơn đặt hàng qua fax. Khách hàng cũng có thể nhận thông báo qua email.
Hệ thống nội bộ của WGRUS bao gồm hệ thống kế toán, trong đó cũng bao gồm các chức năng lập hóa đơn, và hệ thống vận chuyển tính toán các phí vận chuyển và tương tác với các công ty vận chuyển. Vì lý do lịch sử, WGRUS có hai hệ thống hàng tồn kho và danh mục. WGRUS trước đây chỉ bán các sản phẩm widget nhưng đã mua lại một nhà bán lẻ khác chuyên bán các sản phẩm gadget.
Chức năng đầu tiên mà chúng tôi muốn triển khai là nhận đơn hàng. Nhận đơn hàng là một điều tốt vì đơn hàng mang lại doanh thu. Tuy nhiên, việc đặt hàng hiện tại là một quy trình thủ công tẻ nhạt, vì vậy chi phí phát sinh với mỗi đơn hàng là rất cao.
Bước đầu tiên để hợp lý hóa quá trình xử lý đơn hàng là thống nhất việc nhận đơn hàng. Khách hàng có thể đặt hàng qua một trong ba kênh: Trang web, trung tâm cuộc gọi hoặc fax. Thật không may, mỗi hệ thống dựa trên một công nghệ khác nhau và lưu trữ các đơn hàng đến theo định dạng dữ liệu khác nhau. Hệ thống trung tâm cuộc gọi là một ứng dụng đóng gói, trong khi trang web là một ứng dụng J2EE tùy chỉnh. Hệ thống fax đến yêu cầu nhập dữ liệu thủ công vào một ứng dụng Microsoft Access nhỏ. Chúng tôi muốn đối xử với tất cả các đơn hàng như nhau, bất kể nguồn gốc của chúng. Ví dụ, khách hàng nên có khả năng đặt hàng qua trung tâm cuộc gọi và kiểm tra trạng thái đơn hàng trên trang web.
Bởi vì việc đặt hàng là một quá trình bất đồng bộ kết nối nhiều hệ thống, chúng tôi quyết định triển khai một giải pháp phần mềm trung gian dựa trên tin nhắn để tinh giản quy trình nhập hàng. Ứng dụng trung tâm cuộc gọi đã được đóng gói không được phát triển với ý định tích hợp, vì vậy chúng tôi phải kết nối nó với hệ thống nhắn tin bằng cách sử dụng một Bộ chuyển đổi Kênh (Channel Adapter). Một Bộ chuyển đổi Kênh là một thành phần có thể gắn vào một ứng dụng và xuất bản tin nhắn lên một Kênh Tin nhắn bất cứ khi nào có sự kiện xảy ra bên trong ứng dụng. Với một số Bộ chuyển đổi Kênh, ứng dụng thậm chí có thể không nhận thức được sự tồn tại của bộ chuyển đổi. Ví dụ, một bộ chuyển đổi cơ sở dữ liệu có thể thêm các trigger vào các bảng cụ thể để mỗi khi ứng dụng chèn một hàng dữ liệu, một tin nhắn được gửi đến Kênh Tin nhắn. Các Bộ chuyển đổi Kênh cũng có thể hoạt động theo hướng ngược lại, tiêu thụ tin nhắn từ một Kênh Tin nhắn và kích hoạt một hành động bên trong ứng dụng để phản hồi.
Chúng tôi sử dụng cùng một phương pháp cho ứng dụng fax vào, kết nối Bộ điều hợp Kênh với cơ sở dữ liệu ứng dụng. Vì ứng dụng Web được xây dựng tùy chỉnh, chúng tôi triển khai mã Điểm kết thúc Thông điệp bên trong ứng dụng. Chúng tôi sử dụng Cổng thông điệp để cách ly mã ứng dụng khỏi mã cụ thể cho thông điệp.
Nhận đơn hàng từ ba kênh khác nhau

Bởi vì mỗi hệ thống sử dụng một định dạng dữ liệu khác nhau cho các đơn hàng đến, chúng tôi sử dụng ba Bộ Chuyển Đổi Tin Nhắn để chuyển đổi các định dạng dữ liệu khác nhau thành một thông điệp Đơn Mới chung theo Mô Hình Dữ Liệu Chuẩn. Một Mô Hình Dữ Liệu Chuẩn định nghĩa các định dạng tin nhắn độc lập với bất kỳ ứng dụng cụ thể nào để tất cả các ứng dụng có thể giao tiếp với nhau trong định dạng chung này. Nếu định dạng nội bộ của một ứng dụng thay đổi, chỉ cần Bộ Chuyển Đổi Tin Nhắn giữa ứng dụng bị ảnh hưởng và Kênh Tin Nhắn chung cần thay đổi, trong khi tất cả các ứng dụng và Bộ Chuyển Đổi Tin Nhắn khác vẫn không bị ảnh hưởng. Việc sử dụng Mô Hình Dữ Liệu Chuẩn có nghĩa là chúng tôi xử lý hai loại tin nhắn: tin nhắn chuẩn (công khai) và tin nhắn cụ thể cho ứng dụng (riêng tư). Tin nhắn cụ thể cho ứng dụng không nên được tiêu thụ bởi bất kỳ thành phần nào khác ngoài ứng dụng đó và Bộ Chuyển Đổi Tin Nhắn liên quan. Để củng cố chính sách này, chúng tôi đặt tên cho các Kênh Tin Nhắn cụ thể cho ứng dụng bắt đầu bằng tên của ứng dụng: ví dụ, WEB_NEW_ORDER. Ngược lại, các kênh mang tin nhắn chuẩn được đặt tên theo ý định của tin nhắn mà không có bất kỳ tiền tố nào: ví dụ, NEW_ORDER.
Chúng tôi kết nối mỗi Bộ chuyển đổi Kênh với Bộ dịch Tin nhắn qua một Kênh Điểm-đến-Điểm vì chúng tôi muốn đảm bảo rằng mỗi tin nhắn đơn hàng chỉ được tiêu thụ một lần. Chúng tôi có thể không cần sử dụng Bộ dịch Tin nhắn cho giao diện Web nếu chúng tôi lập trình logic biến đổi vào Cổng Thông điệp. Tuy nhiên, việc viết mã thủ công cho các hàm biến đổi có thể tẻ nhạt và dễ gặp lỗi, và chúng tôi thích sử dụng một phương pháp nhất quán. Bộ dịch Tin nhắn bổ sung cũng cho phép chúng tôi bảo vệ quy trình đơn hàng Mới khỏi những thay đổi nhỏ trong định dạng dữ liệu của giao diện Web. Tất cả các Bộ dịch Tin nhắn đều xuất bản tới cùng một Kênh Điểm-đến-Điểm NEW_ORDER để các đơn hàng có thể được xử lý từ kênh này mà không cần quan tâm đến nguồn gốc của đơn hàng.
Kênh Thông điệp NEW_ORDER là một kênh loại Dữ liệu, vì nó chỉ truyền tải thông điệp của một loại duy nhất: đơn hàng mới. Điều này giúp cho những người tiêu thụ thông điệp dễ dàng biết được loại thông điệp nào mà họ có thể mong đợi. Thông điệp Đơn hàng mới được thiết kế dưới dạng Thông điệp Tài liệu. Mục đích của thông điệp không phải là chỉ dẫn người nhận thực hiện một hành động cụ thể, mà là chuyển tài liệu đến bất kỳ người nhận nào quan tâm, người mà có quyền quyết định cách xử lý tài liệu.
Bây giờ khi chúng ta có một thông điệp đơn hàng nhất quán, độc lập với nguồn tin nhắn, chúng ta đã sẵn sàng để xử lý đơn hàng. Để hoàn thành một đơn hàng, chúng ta cần thực hiện các bước sau:
Xác minh tình trạng tín dụng của khách hàng. Nếu khách hàng có hóa đơn chưa thanh toán, chúng tôi muốn từ chối đơn hàng mới.
Xác minh hàng tồn kho. Chúng tôi không thể thực hiện đơn hàng cho các mặt hàng không có sẵn.
Nếu khách hàng đang trong tình trạng tốt và chúng tôi có hàng tồn kho, chúng tôi muốn giao hàng và lập hóa đơn cho khách hàng.
Chúng ta có thể diễn đạt chuỗi sự kiện này bằng một biểu đồ hoạt động (activity diagram) của Ngôn ngữ Mô hình Hợp nhất (UML). Biểu đồ hoạt động có ý nghĩa tương đối đơn giản và là một công cụ tốt để mô tả các quy trình bao gồm các hoạt động song song. Cách chú thích rất đơn giản; các hoạt động tuần tự được kết nối bằng các mũi tên đơn giản. Các hoạt động song song được kết nối bởi một thanh đen dày đại diện cho các hành động phân nhánh và gộp lại. Hành động phân nhánh khiến tất cả các hoạt động kết nối bắt đầu đồng thời, trong khi hành động gộp chỉ tiếp tục sau khi tất cả các hoạt động đầu vào đã hoàn thành.
Biểu đồ hoạt động của chúng tôi (xem hình) được thiết kế để thực hiện nhiệm vụ Kiểm tra Tồn kho và nhiệm vụ Xác thực Tình trạng Khách hàng song song. Thanh kết nối chờ cho đến khi cả hai hoạt động hoàn tất trước khi cho phép hoạt động tiếp theo bắt đầu. Hoạt động tiếp theo xác minh kết quả của cả hai bước: Chúng ta có tồn kho không, và khách hàng có đang trong tình trạng tốt không? Nếu cả hai điều kiện đều được đáp ứng, quy trình sẽ tiếp tục để hoàn thành đơn hàng. Ngược lại, chúng ta sẽ chuyển sang một hoạt động xử lý ngoại lệ. Ví dụ, chúng ta có thể gọi điện nhắc nhở khách hàng thanh toán hóa đơn cuối cùng hoặc gửi một email thông báo cho họ biết rằng đơn hàng sẽ bị trì hoãn. Vì cuốn sách này tập trung vào các khía cạnh thiết kế của tích hợp dựa trên thông điệp hơn là mô hình hóa quy trình làm việc, nên chúng tôi tạm gác lại chi tiết của quy trình xử lý ngoại lệ. Để có những thảo luận rất tốt về kiến trúc quy trình làm việc và mô hình hóa quy trình làm việc, hãy tham khảo [Leyman] và [Sharp].
Sơ đồ Hoạt động cho Quy trình Đặt hàng

Hóa ra các hoạt động trong sơ đồ hoạt động tương ứng khá tốt với các hệ thống trong phòng IT của WGRUS. Hệ thống kế toán xác minh tình trạng tín dụng của khách hàng, các hệ thống quản lý tồn kho kiểm tra hàng tồn kho, và hệ thống vận chuyển khởi động việc vận chuyển hàng hóa thực tế. Hệ thống kế toán cũng đóng vai trò như hệ thống lập hóa đơn và gửi hóa đơn. Chúng ta có thể thấy rằng việc xử lý đơn hàng là một thực hiện điển hình của một quy trình kinh doanh phân tán.
Để chuyển đổi sơ đồ hoạt động logic thành thiết kế tích hợp, chúng ta có thể sử dụng Kênh Xuất Bản-Đăng Ký để thực hiện hành động phân nhánh và một Trình Tập Hợp để thực hiện hành động gộp. Kênh Xuất Bản-Đăng Ký gửi một tin nhắn đến tất cả các người tiêu dùng đang hoạt động; Trình Tập Hợp nhận nhiều tin nhắn đến và kết hợp chúng thành một tin nhắn duy nhất, đi ra (xem hình).
Triển khai xử lý đơn hàng sử dụng nhắn tin bất đồng bộ

Trong ví dụ của chúng ta, Kênh Xuất Bản-Đăng Ký gửi thông điệp Đơn Hàng Mới đến cả hệ thống kế toán và hệ thống tồn kho. Bộ Tập Hợp kết hợp các thông điệp kết quả từ cả hai hệ thống và chuyển thông điệp kết hợp đó đến một Bộ Định Tuyến Dựa Trên Nội Dung. Bộ Định Tuyến Dựa Trên Nội Dung là một thành phần tiêu thụ một thông điệp và xuất bản nó, không thay đổi, đến một số kênh khác dựa trên các quy tắc được mã hóa trong bộ định tuyến. Bộ Định Tuyến Dựa Trên Nội Dung tương đương với nhánh trong sơ đồ hoạt động UML. Trong trường hợp này, nếu cả kiểm tra tồn kho và kiểm tra tín dụng đều xác nhận, Bộ Định Tuyến Dựa Trên Nội Dung sẽ chuyển tiếp thông điệp đến kênh ĐƠN_HÀNG_XÁC_NHẬN. Kênh này là một Kênh Xuất Bản-Đăng Ký, vì vậy đơn hàng đã được xác nhận sẽ đến cả hệ thống vận chuyển và hệ thống thanh toán. Nếu khách hàng không có tình trạng tốt hoặc chúng ta không còn hàng tồn kho, Bộ Định Tuyến Dựa Trên Nội Dung sẽ chuyển tiếp thông điệp đến kênh ĐƠN_HÀNG_KHÔNG_HỢP_LỆ. Một quy trình xử lý ngoại lệ (không được hiển thị trong hình) lắng nghe các thông điệp trên kênh này và thông báo cho khách hàng về đơn hàng bị từ chối.
Bây giờ khi chúng ta đã xác định được luồng thông điệp tổng thể, chúng ta cần xem xét kỹ chức năng tồn kho. Như chúng ta đã học trong phần yêu cầu, WGRUS có hai hệ thống tồn kho: một cho các thiết bị và một cho các món đồ. Do đó, chúng ta phải định tuyến yêu cầu về tồn kho đến hệ thống chính xác. Vì chúng ta muốn ẩn đi những đặc điểm riêng biệt của các hệ thống tồn kho khỏi các hệ thống khác, chúng ta chèn một Bộ định tuyến Dựa trên Nội dung khác để định tuyến thông điệp đến hệ thống tồn kho chính xác dựa trên loại mặt hàng được đặt hàng (xem hình). Ví dụ, tất cả các thông điệp đến với số mặt hàng bắt đầu bằng W sẽ được định tuyến đến hệ thống tồn kho của thiết bị, và tất cả các đơn hàng với số mặt hàng bắt đầu bằng G sẽ được định tuyến đến hệ thống tồn kho của món đồ.
Chuyển tiếp yêu cầu hàng tồn kho

Lưu ý rằng mục đích của các thông điệp trên các Kênh Điểm-Đến-Điểm giữa Bộ Định Tuyến Dựa Trên Nội Dung và các hệ thống tồn kho là khác với kênh trước đó. Các kênh này chứa các Thông Điệp Lệnh, những thông điệp mà chỉ thị cho hệ thống thực hiện lệnh đã được chỉ định, trong trường hợp này là xác minh tồn kho của một mục.
Vì hệ thống quản lý hàng hóa và hệ thống quản lý thiết bị sử dụng các định dạng dữ liệu nội bộ khác nhau, chúng tôi lại chèn các Bộ dịch Tin nhắn để chuyển đổi từ định dạng tin nhắn Đơn hàng Mới chuẩn mực sang định dạng cụ thể của hệ thống.
Điều gì xảy ra nếu mặt hàng trong đơn hàng không bắt đầu bằng W hoặc G? Bộ định tuyến dựa trên nội dung sẽ gửi thông điệp đến kênh ĐƠN_HÀNG_KHÔNG_HỢP_LỆ để đơn hàng không hợp lệ có thể được xử lý theo cách phù hợp, chẳng hạn như thông báo cho khách hàng. Kênh này là một ví dụ điển hình về Kênh Thông Điệp Không Hợp Lệ. Nó làm nổi bật thực tế rằng ý nghĩa của một thông điệp thay đổi tùy thuộc vào kênh mà nó đang ở. Cả kênh ĐƠN_HÀNG_BAR và kênh ĐƠN_HÀNG_KHÔNG_HỢP_LỆ đều vận chuyển cùng một loại thông điệp, nhưng trong một trường hợp, một đơn hàng mới đang được xử lý, trong khi trường hợp kia đơn hàng bị coi là không hợp lệ.
Cho đến nay, chúng tôi đã giả định rằng mỗi đơn hàng chỉ chứa một mặt hàng duy nhất. Điều này sẽ khá bất tiện cho khách hàng của chúng tôi vì họ sẽ phải đặt một đơn hàng mới cho mỗi mặt hàng. Hơn nữa, chúng tôi sẽ kết thúc việc giao nhiều đơn hàng đến cùng một khách hàng và phải chịu chi phí vận chuyển không cần thiết. Tuy nhiên, nếu chúng tôi cho phép nhiều mặt hàng trong một đơn hàng, hệ thống quản lý hàng tồn kho nào sẽ xác minh hàng tồn kho cho đơn hàng này? Chúng tôi có thể sử dụng Kênh Xuất-Biến để gửi đơn hàng đến từng hệ thống quản lý hàng tồn kho để chọn ra những mặt hàng mà nó có thể xử lý. Nhưng sau đó sẽ xảy ra điều gì với những mặt hàng không hợp lệ? Làm thế nào chúng tôi có thể nhận ra rằng không có hệ thống quản lý hàng tồn kho nào xử lý mặt hàng đó? Chúng tôi muốn duy trì quyền kiểm soát trung tâm mà Bộ định tuyến Dựa trên Nội dung đem lại cho chúng tôi, nhưng chúng tôi cần có khả năng định tuyến từng mặt hàng trong đơn hàng một cách riêng biệt.
Do đó, chúng tôi chèn một Splitter, một thành phần phân tách một thông điệp duy nhất thành nhiều thông điệp riêng lẻ. Trong trường hợp của chúng tôi, Splitter phân tách một thông điệp Đơn hàng thành nhiều thông điệp Mục đơn hàng. Mỗi thông điệp Mục đơn hàng sau đó có thể được định tuyến đến hệ thống kho phù hợp bằng cách sử dụng một Bộ định tuyến Dựa trên Nội dung như trước; xem hình dưới đây.
Xử lý các mặt hàng đơn hàng một cách riêng lẻ

Tất nhiên, khi hàng tồn kho cho tất cả các mặt hàng đã được xác minh, chúng ta cần kết hợp lại các thông điệp thành một thông điệp duy nhất. Chúng ta đã học rằng thành phần có thể kết hợp nhiều thông điệp thành một thông điệp là Aggregator. Bằng cách sử dụng cả Splitter và Aggregator, chúng ta có thể tách biệt hợp lý dòng chảy thông điệp cho các mặt hàng đặt hàng riêng lẻ khỏi dòng chảy cho một đơn hàng hoàn chỉnh.
Khi thiết kế một Bộ tổng hợp (Aggregator), chúng ta phải đưa ra ba quyết định quan trọng:
Các thông điệp nào liên quan với nhau (sự tương quan)?
Làm thế nào để chúng ta xác định rằng tất cả các thông điệp đã được nhận (điều kiện hoàn chỉnh)?
Chúng ta kết hợp các thông điệp cá nhân thành một thông điệp kết quả (thuật toán tổng hợp) như thế nào?
Hãy giải quyết những vấn đề này một cách lần lượt. Chúng ta không thể liên kết các mặt hàng trong đơn hàng theo ID khách hàng, vì một khách hàng có thể đặt nhiều đơn hàng trong thời gian ngắn. Do đó, chúng ta cần một ID đơn hàng duy nhất cho mỗi đơn hàng. Chúng ta thực hiện điều này bằng cách chèn một Bộ làm phong phú nội dung vào phần của giải pháp nhận đơn hàng (xem hình). Một Bộ làm phong phú nội dung là một thành phần thêm các mục dữ liệu thiếu vào một thông điệp đến. Trong trường hợp của chúng ta, Bộ làm phong phú nội dung sẽ thêm một ID đơn hàng duy nhất vào thông điệp.
Nhận đơn hàng với Enricher

Bây giờ chúng ta đã có mã đơn hàng để liên kết các tin nhắn Mục Đơn hàng, chúng ta cần xác định điều kiện hoàn chỉnh và thuật toán tổng hợp cho Bộ tổng hợp Mục Đơn hàng. Vì chúng ta định tuyến tất cả các tin nhắn, bao gồm cả các mục không hợp lệ, đến Bộ tổng hợp, Bộ tổng hợp có thể đơn giản sử dụng số lượng mục trong đơn hàng (một trong các trường trong tin nhắn Đơn hàng) để đếm đến khi tất cả các mục đơn hàng đều đến. Thuật toán tổng hợp cũng tương tự đơn giản. Bộ tổng hợp ghép nối tất cả các tin nhắn Mục Đơn hàng lại thành một tin nhắn Đơn hàng duy nhất và công bố nó lên kênh ĐƠN_HÀNG_XÁC_THỰC.
Sự kết hợp của một Bộ chia, một Bộ định tuyến tin nhắn và một Bộ tổng hợp là khá phổ biến. Chúng tôi gọi nó là Bộ xử lý tin nhắn hợp thành. Để đơn giản hóa hình ảnh, chúng tôi chèn ký hiệu cho một Bộ xử lý tin nhắn hợp thành vào sơ đồ luồng tin nhắn gốc.
Triển khai quy trình đặt hàng đã được sửa đổi

Mặc dù đã kết nối các hệ thống qua Kênh Tin nhắn, việc hoàn thành đơn hàng có thể mất một khoảng thời gian. Ví dụ, chúng tôi có thể hết hàng một mặt hàng nhất định và hệ thống quản lý kho có thể đang giữ thông điệp Kiểm tra Kho cho đến khi có hàng mới đến. Đây là một trong những lợi thế của việc nhắn tin không đồng bộ: việc giao tiếp được thiết kế để diễn ra theo nhịp độ của các thành phần. Trong khi hệ thống quản lý kho đang giữ tin nhắn, hệ thống kế toán vẫn có thể xác minh tình trạng tín dụng của khách hàng. Khi cả hai bước hoàn tất, Bộ tổng hợp sẽ công bố thông điệp Đơn hàng Đã xác thực để khởi động việc vận chuyển và lập hóa đơn.
Một quy trình kinh doanh lâu dài cũng có nghĩa là cả khách hàng và nhà quản lý đều có khả năng muốn biết tình trạng của một đơn hàng cụ thể. Ví dụ, nếu một số mặt hàng không có trong kho, khách hàng có thể quyết định chỉ xử lý những mặt hàng có sẵn. Hoặc, nếu khách hàng chưa nhận được hàng, điều hữu ích là chúng ta có thể cho họ biết rằng hàng đang trên đường (bao gồm số theo dõi của công ty vận chuyển) hoặc rằng có sự chậm trễ nội bộ trong kho.
Việc theo dõi trạng thái của một đơn hàng với thiết kế hiện tại không hề dễ dàng. Các thông điệp liên quan chảy qua nhiều hệ thống khác nhau. Để xác định trạng thái của đơn hàng trong chuỗi các bước, chúng ta cần biết thông điệp "cuối cùng" liên quan đến đơn hàng này. Một trong những lợi thế của Kênh Xuất Bản-Đăng Ký là chúng ta có thể thêm nhiều người đăng ký mà không làm gián đoạn luồng thông điệp. Chúng ta có thể sử dụng thuộc tính này để lắng nghe các đơn hàng mới và đã được xác thực và lưu trữ chúng trong một Kho Thông Điệp. Sau đó, chúng ta có thể truy vấn cơ sở dữ liệu Kho Thông Điệp để biết trạng thái của một đơn hàng.
Thêm một Kho Tin Nhắn để Theo Dõi Trạng Thái Đơn Hàng

Trong những tình huống mà chúng ta sử dụng Kênh Điểm-Điểm, chúng ta không thể đơn giản thêm một người đăng ký vào kênh, vì Kênh Điểm-Điểm đảm bảo rằng mỗi tin nhắn chỉ được tiêu thụ bởi một người đăng ký duy nhất. Tuy nhiên, chúng ta có thể chèn một Wire Tap, một thành phần đơn giản tiêu thụ một tin nhắn từ một kênh và xuất bản nó đến hai kênh. Chúng ta có thể sử dụng kênh thứ hai để gửi tin nhắn đến Kho Tin nhắn; xem hình.
Theo dõi tin nhắn bằng cách nghe lén

Việc lưu trữ dữ liệu tin nhắn trong một cơ sở dữ liệu trung tâm có một lợi thế đáng kể khác. Trong thiết kế ban đầu, mỗi tin nhắn đều phải mang theo dữ liệu thặng dư để tiếp tục xử lý tin nhắn theo sau. Ví dụ, tin nhắn Xác thực Tình trạng Khách hàng có thể đã phải vận chuyển đủ loại dữ liệu khách hàng mặc dù chỉ yêu cầu ID khách hàng. Dữ liệu bổ sung này cần thiết để tin nhắn kết quả vẫn chứa tất cả dữ liệu từ tin nhắn đơn hàng ban đầu. Việc lưu trữ tin nhắn Đơn hàng Mới trong một Kho Tin nhắn ở đầu dòng chảy tin nhắn có lợi thế là tất cả các thành phần tiếp theo có thể tham chiếu đến Kho Tin nhắn để lấy dữ liệu tin nhắn quan trọng mà không cần tất cả các bước trung gian phải mang theo dữ liệu. Chúng tôi gọi một chức năng như vậy là tin nhắn Kiểm Tra Thanh toán có thể "kiểm tra" dữ liệu để lấy lại sau. Nhược điểm của cách tiếp cận này là việc truy cập vào một kho dữ liệu trung tâm không đáng tin cậy bằng việc gửi tin nhắn qua các Kênh Tin nhắn không đồng bộ.
Bây giờ, Kho Tin Nhắn chịu trách nhiệm duy trì dữ liệu liên quan đến tin nhắn mới cũng như tiến trình của tin nhắn trong quá trình. Dữ liệu này cung cấp cho chúng ta đủ thông tin để sử dụng Kho Tin Nhắn nhằm xác định các bước tiếp theo cần thiết trong quá trình thay vì kết nối các thành phần với các Kênh Tin Nhắn cố định. Ví dụ, nếu cơ sở dữ liệu chứa các tin nhắn trả lời từ cả hệ thống tồn kho và hệ thống lập hóa đơn, chúng ta có thể kết luận rằng đơn hàng đã được xác nhận và có thể gửi một tin nhắn đến hệ thống vận chuyển và lập hóa đơn. Thay vì đưa ra quyết định này trong một thành phần Tổng Hợp riêng biệt, chúng ta có thể thực hiện điều đó ngay trong Kho Tin Nhắn. Về cơ bản, chúng ta đang biến Kho Tin Nhắn thành một Quản Lý Quy Trình.
Một Quản lý Quy trình là thành phần trung tâm quản lý luồng tin nhắn qua hệ thống. Quản lý Quy trình cung cấp hai chức năng chính:
Lưu trữ dữ liệu giữa các tin nhắn (trong một "phiên xử lý")
Theo dõi tiến trình và xác định bước tiếp theo (bằng cách sử dụng "mẫu quy trình")
Xử lý Đơn hàng với Trình quản lý Quy trình

Kiến trúc này biến các hệ thống riêng lẻ (ví dụ: hệ thống quản lý hàng tồn kho) thành các chức năng kinh doanh chung có thể được truy cập bởi các thành phần khác như các dịch vụ, từ đó tăng cường khả năng tái sử dụng và đơn giản hóa việc bảo trì. Các dịch vụ có thể được kết nối với nhau thông qua luồng tin nhắn (ví dụ: sử dụng Bộ xử lý tin nhắn hợp thành để kiểm tra trạng thái hàng tồn kho cho từng mục đơn hàng) hoặc được điều phối thông qua một Trình quản lý quy trình. Sử dụng Trình quản lý quy trình khiến việc thay đổi luồng tin nhắn dễ dàng hơn rất nhiều so với phương pháp trước đây của chúng tôi.
Kiến trúc mới cho phép tất cả các dịch vụ truy cập vào một bus dịch vụ chung để chúng có thể được gọi từ bất kỳ thành phần nào khác. Chúng ta có thể biến cơ sở hạ tầng CNTT của WGRUS thành một SOA bằng cách thêm các tiện ích để tra cứu ("khám phá") một dịch vụ từ một đăng ký dịch vụ trung tâm. Để tham gia vào SOA này, mỗi dịch vụ sẽ phải cung cấp các chức năng bổ sung. Ví dụ, mỗi dịch vụ sẽ phải công khai một hợp đồng giao diện mô tả các chức năng mà dịch vụ cung cấp. Mỗi dịch vụ trả lời yêu cầu cũng cần hỗ trợ khái niệm Địa chỉ Trả về. Địa chỉ Trả về cho phép người gọi (người tiêu thụ dịch vụ) chỉ định kênh mà dịch vụ nên gửi tin nhắn trả về. Điều này rất quan trọng để cho phép dịch vụ được tái sử dụng trong các bối cảnh khác nhau, mỗi bối cảnh có thể yêu cầu kênh riêng cho các tin nhắn trả về.
Quản lý Quy trình tự nó sử dụng một kho lưu trữ bền vững (thường là tệp hoặc cơ sở dữ liệu quan hệ) để lưu trữ dữ liệu liên quan đến từng phiên quy trình. Để cho phép giao diện Web truy vấn trạng thái của một đơn hàng, chúng tôi có thể gửi một tin nhắn đến Quản lý Quy trình hoặc cơ sở dữ liệu đơn hàng. Tuy nhiên, việc kiểm tra trạng thái là một quá trình đồng bộ - khách hàng mong đợi nhận được phản hồi ngay lập tức. Vì giao diện Web là một ứng dụng tùy chỉnh, chúng tôi quyết định truy cập trực tiếp vào cơ sở dữ liệu đơn hàng để truy vấn trạng thái đơn hàng. Hình thức Cơ sở Dữ liệu Chia sẻ này là phương pháp đơn giản nhất và hiệu quả nhất, và chúng tôi luôn đảm bảo rằng giao diện Web hiển thị trạng thái hiện tại nhất. Nhược điểm tiềm ẩn của phương pháp này là giao diện Web bị ràng buộc chặt chẽ với cơ sở dữ liệu, một sự đánh đổi mà chúng tôi sẵn sàng chấp nhận.
Một khó khăn trong việc khai thác các hệ thống như là dịch vụ xuất phát từ thực tế rằng nhiều hệ thống cũ không được xây dựng với các tính năng như Địa Chỉ Trả về trong tâm trí. Do đó, chúng tôi "gói" quyền truy cập vào hệ thống cũ bằng một Proxy Thông minh. Proxy Thông minh này nâng cao dịch vụ hệ thống cơ bản với khả năng bổ sung để nó có thể tham gia vào một Kiến trúc Hỗ trợ Dịch vụ (SOA). Để làm điều này, Proxy Thông minh chặn cả tin nhắn yêu cầu và phản hồi đến và từ dịch vụ cơ bản (xem hình minh họa).
"Chèn một Smart Proxy để biến hệ thống kế thừa thành dịch vụ chia sẻ"

Proxy thông minh có thể lưu trữ thông tin từ thông điệp yêu cầu (ví dụ: Địa chỉ Trả về do người yêu cầu chỉ định) và sử dụng thông tin này để xử lý thông điệp phản hồi (ví dụ: định tuyến nó đến kênh phản hồi đúng). Proxy thông minh cũng rất hữu ích trong việc theo dõi chất lượng dịch vụ (ví dụ: thời gian phản hồi) của một dịch vụ bên ngoài.
WGRUS cần xử lý một số địa chỉ. Ví dụ, hóa đơn cần được gửi đến địa chỉ thanh toán của khách hàng, trong khi hàng hóa được vận chuyển đến địa chỉ giao hàng. Chúng tôi muốn cho phép khách hàng quản lý tất cả những địa chỉ này qua giao diện Web để loại bỏ các bước thủ công không cần thiết.
Chúng ta có thể chọn giữa hai phương pháp cơ bản để có được địa chỉ thanh toán và giao hàng chính xác cho các hệ thống thanh toán và giao hàng:
Bao gồm dữ liệu địa chỉ với mỗi tin nhắn Đơn hàng Mới.
Lưu trữ dữ liệu địa chỉ trong mỗi hệ thống và sao chép các thay đổi.
Tùy chọn đầu tiên có lợi thế là chúng ta có thể sử dụng một kênh tích hợp sẵn có để vận chuyển thông tin bổ sung. Một nhược điểm tiềm năng là dòng dữ liệu bổ sung chảy qua hạ tầng phần mềm trung gian; chúng ta truyền dữ liệu địa chỉ cùng với mỗi đơn hàng mặc dù địa chỉ có thể thay đổi ít thường xuyên hơn.
Khi thực hiện tùy chọn đầu tiên, chúng ta cần lưu ý rằng hệ thống lập hóa đơn và vận chuyển là các ứng dụng được đóng gói và có thể không được thiết kế với khả năng tích hợp trong tâm trí. Do đó, chúng khó có thể chấp nhận địa chỉ với đơn hàng mới mà thay vào đó sẽ sử dụng địa chỉ được lưu trữ trong cơ sở dữ liệu địa phương của họ. Để cho phép các hệ thống cập nhật địa chỉ với thông điệp Đơn hàng Mới, chúng ta cần thực hiện hai chức năng trong hệ thống lập hóa đơn (và hệ thống vận chuyển): Đầu tiên, chúng ta phải cập nhật địa chỉ, và sau đó chúng ta phải gửi hóa đơn (hoặc giao hàng). Vì thứ tự của hai thông điệp có ý nghĩa quan trọng, chúng ta chèn một thành phần Quản lý Quy trình đơn giản nhận thông điệp Đơn hàng Mới (bao gồm địa chỉ giao hàng và lập hóa đơn hiện tại) và phát hành hai thông điệp riêng biệt đến hệ thống lập hóa đơn (hoặc hệ thống vận chuyển) (xem hình).
Bao gồm dữ liệu địa chỉ trong tin nhắn đơn hàng mới

Chúng ta cần nhớ rằng các Bộ điều hợp Kênh yêu cầu tin nhắn được định dạng theo các định dạng sở hữu được sử dụng bởi các ứng dụng (sử dụng các tin nhắn gọi là tin nhắn riêng tư). Bởi vì tin nhắn Đơn hàng Mới đến theo định dạng tin nhắn chuẩn, chúng ta cần thực hiện một sự chuyển đổi giữa hai định dạng. Chúng ta có thể xây dựng quá trình chuyển đổi vào trong Quản lý Quy trình, nhưng thực tế chúng ta thích sử dụng các Bộ dịch Tin nhắn bên ngoài để logic bên trong Quản lý Quy trình không bị ảnh hưởng bởi định dạng dữ liệu có thể phức tạp mà các ứng dụng yêu cầu.
Lựa chọn thứ hai sử dụng sao chép dữ liệu để truyền bá các thay đổi địa chỉ đến tất cả các hệ thống bị ảnh hưởng một cách độc lập với quy trình Đặt hàng Mới. Mỗi khi thông tin địa chỉ thay đổi trên giao diện web, chúng tôi sẽ truyền bá các thay đổi đến tất cả các hệ thống quan tâm bằng cách sử dụng Kênh Xuất Bản-Đăng Ký. Các hệ thống lưu trữ địa chỉ cập nhật nội bộ và sử dụng nó khi một tin nhắn Đặt hàng đến. Cách tiếp cận này giảm lưu lượng tin nhắn (giả sử khách hàng thay đổi địa chỉ ít thường xuyên hơn họ đặt hàng). Nó cũng có thể giảm sự kết nối giữa các hệ thống. Bất kỳ hệ thống nào sử dụng địa chỉ có thể đăng ký vào kênh THAY ĐỔI ĐỊA CHỈ mà không ảnh hưởng đến bất kỳ hệ thống nào khác.
Bởi vì chúng tôi đang xử lý nhiều loại địa chỉ (địa chỉ giao hàng và địa chỉ thanh toán), chúng tôi cần đảm bảo rằng chỉ loại địa chỉ phù hợp được lưu trữ trong mỗi hệ thống. Chúng tôi cần tránh việc gửi thông điệp thay đổi địa chỉ đến hệ thống giao hàng nếu địa chỉ đó là địa chỉ thanh toán. Chúng tôi thực hiện điều này bằng cách sử dụng Bộ lọc Thông điệp chỉ cho phép các thông điệp phù hợp với các tiêu chí nhất định (xem hình).
Chúng tôi cũng sử dụng Trình dịch Thông điệp để dịch thông điệp Thay đổi Địa chỉ tổng quát thành định dạng thông điệp cụ thể được sử dụng bởi các ứng dụng. Trong trường hợp này, chúng tôi không cần sử dụng Trình dịch Thông điệp cho giao diện Web vì chúng tôi định nghĩa Mô hình Dữ liệu Canonical bằng với định dạng của ứng dụng giao diện Web. Điều này có thể hạn chế tính linh hoạt của chúng tôi nếu chúng tôi muốn giới thiệu những cách khác để thay đổi địa chỉ trong tương lai, nhưng hiện tại thì nó là đủ.
"Phát tán thay đổi địa chỉ thông qua một kênh phát hành-đăng ký tách biệt"

Cả hệ thống vận chuyển và hệ thống thanh toán đều lưu trữ địa chỉ trong cơ sở dữ liệu quan hệ, vì vậy chúng tôi sử dụng một Bộ chuyển đổi cơ sở dữ liệu để cập nhật dữ liệu trong từng hệ thống.
Làm thế nào để chúng ta quyết định giữa hai tùy chọn? Trong tình huống của chúng tôi, lưu lượng tin nhắn không phải là một mối quan tâm lớn vì chúng tôi chỉ xử lý vài trăm đơn hàng mỗi ngày, vì vậy cả hai giải pháp đều khá hiệu quả. Yếu tố quyết định chính sẽ là cấu trúc nội bộ của các ứng dụng. Chúng tôi có thể không thể chèn địa chỉ trực tiếp vào cơ sở dữ liệu, mà thay vào đó thông qua lớp nghiệp vụ của các ứng dụng. Trong trường hợp này, các ứng dụng có thể thực hiện các bước xác thực bổ sung và ghi lại hoạt động thay đổi địa chỉ. Hệ thống thậm chí có thể được lập trình để gửi email xác nhận cho khách hàng mỗi khi địa chỉ thay đổi. Điều này sẽ trở nên rất phiền phức nếu việc cập nhật xảy ra với mỗi đơn hàng. Một điều kiện như vậy sẽ ưu tiên việc phát tán các thay đổi địa chỉ sử dụng những tin nhắn chuyên dụng chỉ được gửi khi khách hàng thực sự thay đổi địa chỉ.
Nói chung, chúng tôi thích những hành động kinh doanh rõ ràng, tự chứa như "Thay đổi địa chỉ" và "Đặt hàng" vì chúng mang lại cho chúng tôi nhiều tính linh hoạt hơn trong việc điều phối các quy trình kinh doanh. Tất cả đều liên quan đến một câu hỏi về mức độ chi tiết và những đánh đổi liên quan. Các giao diện chi tiết quá mức có thể dẫn đến hệ thống chậm chạp do số lượng cuộc gọi từ xa hoặc tin nhắn được gửi quá nhiều. Chẳng hạn, hãy tưởng tượng một giao diện tiết lộ một phương thức riêng biệt để thay đổi từng trường địa chỉ. Cách tiếp cận này sẽ hiệu quả nếu giao tiếp diễn ra bên trong một ứng dụng duy nhất mà bạn chỉ cập nhật những trường đã thay đổi. Trong một kịch bản tích hợp, việc gửi sáu hoặc bảy tin nhắn để cập nhật một địa chỉ sẽ là một gánh nặng đáng kể, hơn nữa chúng tôi sẽ phải đối phó với việc đồng bộ hóa các tin nhắn riêng lẻ. Các giao diện chi tiết quá mức cũng dẫn đến việc kết nối chặt chẽ. Nếu chúng tôi thay đổi định dạng địa chỉ bằng cách thêm một trường mới, chúng tôi sẽ phải định nghĩa các định dạng tin nhắn mới và thay đổi tất cả các ứng dụng khác để gửi một tin nhắn bổ sung.
Giao diện thô giải quyết những vấn đề này, nhưng với một cái giá. Chúng tôi gửi ít thông điệp hơn và do đó hiệu quả hơn và ít bị gắn bó chặt chẽ hơn. Tuy nhiên, các giao diện quá thô có thể hạn chế tính linh hoạt của chúng tôi. Nếu Gửi Hóa Đơn và Thay Đổi Địa Chỉ được kết hợp thành một chức năng bên ngoài, chúng tôi sẽ không bao giờ có thể thay đổi địa chỉ mà không gửi một hóa đơn. Vì vậy, như thường lệ, câu trả lời tốt nhất là một sự trung dung hạnh phúc và phụ thuộc vào các sự đánh đổi cụ thể đang hoạt động trong kịch bản thực tế.
Để đặt hàng, khách hàng cần xem các mặt hàng hiện đang được cung cấp và giá của chúng trực tuyến. Danh mục của WGRUS được điều khiển bởi các sản phẩm từ các nhà cung cấp tương ứng. Tuy nhiên, một trong những dịch vụ mà WGRUS cung cấp cho khách hàng là cho phép họ xem các thiết bị và đồ dùng trên cùng một trang web và đặt hàng cả hai loại mặt hàng trong một đơn hàng duy nhất. Chức năng này là một ví dụ của một kịch bản Cổng Thông Tin, nơi thông tin từ nhiều nguồn được kết hợp vào một cái nhìn duy nhất.
Hóa ra cả hai nhà cung cấp đều cập nhật danh mục sản phẩm của họ mỗi ba tháng một lần. Do đó, việc tạo ra một hạ tầng nhắn tin thời gian thực để truyền đạt các thay đổi trong danh mục từ các nhà cung cấp đến WGRUS thì tương đối không hợp lý. Thay vào đó, chúng tôi sử dụng tích hợp Chuyển File để chuyển dữ liệu danh mục từ các nhà cung cấp đến WGRUS. Một lợi thế khác của việc sử dụng file là chúng dễ dàng và hiệu quả trong việc vận chuyển qua các mạng công cộng sử dụng FTP hoặc các giao thức tương tự. So với đó, hầu hết các hạ tầng nhắn tin bất đồng bộ không hoạt động tốt qua Internet công cộng.
Chúng ta vẫn có thể sử dụng bộ chuyển đổi và bộ điều hợp để biến đổi dữ liệu sang định dạng danh mục nội bộ của chúng ta. Tuy nhiên, những bộ chuyển đổi này xử lý toàn bộ danh mục cùng một lúc thay vì một mục từng lần. Cách tiếp cận này hiệu quả hơn nhiều nếu chúng ta đang xử lý một lượng lớn dữ liệu có cùng định dạng.
Cập nhật dữ liệu danh mục qua chuyển giao tệp

Để cải thiện kinh doanh, chúng tôi muốn thông báo các chương trình khuyến mãi cho khách hàng của mình thỉnh thoảng. Để tránh làm phiền khách hàng, chúng tôi cho phép mỗi khách hàng chỉ định những tin nhắn mà họ quan tâm. Chúng tôi cũng muốn nhắm mục tiêu các tin nhắn cụ thể đến một tập hợp khách hàng cụ thể. Ví dụ, chúng tôi có thể thông báo các ưu đãi đặc biệt chỉ cho những khách hàng ưu tiên. Khi chúng tôi cần gửi thông tin đến nhiều người nhận, một Kênh Công Bố-Đăng Ký lập tức xuất hiện trong tâm trí. Tuy nhiên, Kênh Công Bố-Đăng Ký có một số bất lợi. Thứ nhất, nó cho phép bất kỳ người đăng ký nào nghe các tin nhắn đã được công bố mà không có sự biết đến của người công bố. Ví dụ, chúng tôi không muốn những khách hàng nhỏ nhận được các ưu đãi đặc biệt dành cho những khách hàng có khối lượng lớn. Nhược điểm thứ hai của Kênh Công Bố-Đăng Ký là chúng chỉ hoạt động hiệu quả trên các mạng cục bộ. Nếu chúng tôi gửi dữ liệu qua các mạng diện rộng qua Kênh Công Bố-Đăng Ký, chúng tôi phải gửi một bản sao riêng của tin nhắn đến từng người nhận. Nếu một người nhận không quan tâm đến tin nhắn, chúng tôi sẽ phải gánh chịu lưu lượng mạng không cần thiết.
Do đó, chúng ta nên tìm kiếm một giải pháp cho phép người đăng ký đưa ra sở thích đăng ký của họ và sau đó gửi tin nhắn riêng lẻ chỉ đến những khách hàng quan tâm (và được ủy quyền). Để thực hiện chức năng này, chúng tôi sử dụng Danh sách Người Nhận Động. Danh sách Người Nhận Động là sự kết hợp của hai mẫu Định tuyến Tin nhắn. Danh sách Người Nhận là một bộ định tuyến truyền bá một tin nhắn duy nhất đến một tập hợp các người nhận. Sự khác biệt chính giữa Danh sách Người Nhận và Kênh Xuất Bản-Đăng Ký là Danh sách Người Nhận nhắm đến từng người nhận cụ thể và do đó có kiểm soát chặt chẽ hơn về việc ai nhận tin nhắn. Bộ Định tuyến Động là một bộ định tuyến mà thuật toán định tuyến của nó có thể thay đổi dựa trên các tin nhắn điều khiển. Các tin nhắn điều khiển này có thể dưới dạng sở thích đăng ký được phát hành bởi các người đăng ký. Danh sách Người Nhận Động là kết quả của việc kết hợp hai mẫu này.
Gửi Thông Báo với Danh Sách Người Nhận Động

Nếu khách hàng nhận thông báo qua e-mail, việc thực hiện các mẫu này có thể sử dụng các tính năng của danh sách gửi thư thường được cung cấp bởi các hệ thống e-mail. Mỗi kênh người nhận sau đó được xác định bằng một địa chỉ e-mail. Tương tự, nếu khách hàng thích nhận thông báo qua giao diện dịch vụ Web, mỗi kênh người nhận được triển khai bằng một yêu cầu SOAP, và địa chỉ kênh là URI của dịch vụ Web. Ví dụ này minh họa rằng các mẫu mà chúng tôi sử dụng để mô tả thiết kế giải pháp là độc lập với một công nghệ vận chuyển cụ thể.
Việc theo dõi sự thực hiện đúng đắn của các tin nhắn là một chức năng quan trọng trong hoạt động và hỗ trợ. Kho tin nhắn có thể cung cấp cho chúng ta một số chỉ số kinh doanh quan trọng, chẳng hạn như thời gian trung bình để hoàn thành một đơn hàng. Tuy nhiên, chúng ta có thể cần thông tin chi tiết hơn để hoạt động thành công của một giải pháp tích hợp. Giả sử chúng ta nâng cao giải pháp của mình để truy cập một cơ quan tín dụng bên ngoài nhằm đánh giá tốt hơn tình trạng tín dụng của khách hàng. Ngay cả khi chúng ta không có khoản thanh toán nào đang nợ, chúng ta có thể muốn từ chối đơn hàng của khách hàng nếu xếp hạng tín dụng của khách hàng đó đặc biệt kém. Điều này đặc biệt hữu ích cho các khách hàng mới không có lịch sử thanh toán với chúng ta. Bởi vì dịch vụ này được cung cấp bởi một nhà cung cấp bên ngoài, chúng ta phải trả phí sử dụng. Để xác minh hóa đơn của nhà cung cấp, chúng ta muốn theo dõi mức sử dụng thực tế của mình và đối chiếu hai báo cáo. Chúng ta không thể chỉ dựa vào số lượng đơn hàng, vì logic kinh doanh có thể không yêu cầu kiểm tra tín dụng bên ngoài cho các khách hàng lâu năm. Ngoài ra, chúng ta có thể có một thỏa thuận về chất lượng dịch vụ (QoS) với nhà cung cấp bên ngoài. Ví dụ, nếu thời gian phản hồi vượt quá thời gian quy định, chúng ta có thể không phải trả tiền cho yêu cầu đó.
Để đảm bảo chúng tôi được tính phí đúng, chúng tôi muốn theo dõi số lượng yêu cầu mà chúng tôi thực hiện và thời gian mà phản hồi liên quan đến đó mất để đến. Chúng tôi phải có khả năng xử lý hai tình huống cụ thể. Thứ nhất, dịch vụ bên ngoài có thể xử lý hơn một yêu cầu cùng một lúc, vì vậy chúng tôi cần có khả năng kết nối giữa yêu cầu và tin nhắn trả lời. Thứ hai, vì chúng tôi coi dịch vụ bên ngoài là một dịch vụ chia sẻ trong nội bộ doanh nghiệp, chúng tôi muốn cho phép người tiêu dùng dịch vụ chỉ định một Địa chỉ Trả lời, kênh mà dịch vụ nên gửi tin nhắn trả lời. Việc không biết kênh nào mà phản hồi được gửi đến có thể gây khó khăn cho việc kết nối giữa yêu cầu và tin nhắn trả lời.
Một lần nữa, Smart Proxy là câu trả lời. Chúng tôi chèn Smart Proxy giữa bất kỳ người tiêu dùng dịch vụ nào và dịch vụ bên ngoài. Smart Proxy chặn mỗi yêu cầu tới dịch vụ và thay thế Địa chỉ Trả về được chỉ định bởi người tiêu dùng dịch vụ bằng một kênh trả lời cố định. Điều này khiến dịch vụ gửi tất cả các tin nhắn trả về tới kênh được chỉ định bởi Smart Proxy. Proxy lưu trữ Địa chỉ Trả về gốc để có thể chuyển tiếp tin nhắn trả về tới kênh nguyên gốc được chỉ định bởi người tiêu dùng. Smart Proxy cũng đo thời gian giữa các tin nhắn yêu cầu và trả lời từ dịch vụ bên ngoài. Smart Proxy công bố dữ liệu này lên Bus Điều khiển. Bus Điều khiển kết nối với một bảng điều khiển quản lý thu thập các chỉ số từ nhiều thành phần khác nhau.
Chèn một Proxy Thông Minh để Theo Dõi Thời Gian Phản Hồi

Ngoài việc theo dõi việc sử dụng dịch vụ tín dụng bên ngoài, chúng tôi cũng muốn đảm bảo rằng dịch vụ hoạt động đúng cách. Smart Proxy có thể báo cáo cho bảng điều khiển quản lý những trường hợp mà không nhận được tin nhắn phản hồi trong một khoảng thời gian xác định. Những trường hợp khó phát hiện hơn là khi dịch vụ bên ngoài trả về tin nhắn phản hồi nhưng kết quả trong tin nhắn là sai. Ví dụ, nếu dịch vụ bên ngoài gặp sự cố và trả về điểm tín dụng bằng không cho mọi khách hàng, chúng tôi sẽ từ chối mọi đơn hàng. Có hai cơ chế có thể giúp chúng tôi bảo vệ chống lại kịch bản như vậy. Thứ nhất, chúng tôi có thể định kỳ chèn một Tin Nhắn Kiểm Tra vào dòng yêu cầu. Tin Nhắn Kiểm Tra này yêu cầu điểm cho một người cụ thể để kết quả được biết. Chúng tôi có thể sử dụng một trình xác minh dữ liệu kiểm tra để kiểm tra không chỉ việc nhận được phản hồi mà còn cả độ chính xác của nội dung tin nhắn. Bởi vì Smart Proxy hỗ trợ Địa Chỉ Trả Lại, trình tạo dữ liệu kiểm tra có thể chỉ định một kênh phản hồi đặc biệt để tách biệt các phản hồi kiểm tra khỏi các phản hồi thông thường.
Chèn Thông Điệp Kiểm Tra để Xác Minh Kết Quả Chính Xác

Một chiến lược hiệu quả khác để phát hiện các dịch vụ gặp sự cố là lấy một mẫu thống kê. Ví dụ, chúng ta có thể mong đợi từ chối trung bình ít hơn một trong 10 đơn hàng do khách hàng có tình trạng kém. Nếu chúng ta từ chối hơn năm đơn hàng liên tiếp, điều này có thể là dấu hiệu cho thấy một dịch vụ bên ngoài hoặc một số logic kinh doanh đang gặp trục trặc. Bảng điều khiển quản lý có thể gửi email năm đơn hàng cho một quản trị viên, người sau đó có thể nhanh chóng xem xét dữ liệu để xác minh xem các từ chối có hợp lý hay không.
Chúng tôi đã đi qua một kịch bản tích hợp khá rộng với việc sử dụng các chiến lược tích hợp khác nhau như Chuyển File, Cơ sở Dữ liệu Chia sẻ và Giao tiếp không đồng bộ. Chúng tôi đã định tuyến, chia nhỏ và tổng hợp các thông điệp. Chúng tôi đã giới thiệu một Quản lý Quy trình để cho phép tính linh hoạt hơn. Chúng tôi cũng đã thêm các chức năng để theo dõi hoạt động chính xác của giải pháp. Mặc dù các yêu cầu cho ví dụ này được thừa nhận là đã đơn giản hóa, nhưng các vấn đề và sự đánh đổi trong thiết kế mà chúng tôi phải xem xét lại rất thực tế. Các sơ đồ và mô tả giải pháp làm nổi bật cách chúng tôi có thể mô tả mỗi giải pháp bằng ngôn ngữ trung lập với nhà cung cấp và công nghệ, chính xác hơn nhiều so với một sơ đồ tuần tự cấp cao.
Kịch bản tích hợp trong chương này chủ yếu tập trung vào cách kết nối các ứng dụng hiện có. Để có mô tả chi tiết về cách xuất bản và tiêu thụ tin nhắn từ bên trong một ứng dụng tùy chỉnh, hãy xem các ví dụ trong Chương 6, "Giữa chừng: Tin nhắn đơn giản," và Chương 9, "Giữa chừng: Tin nhắn phức hợp."
Phần còn lại của cuốn sách chứa những mô tả chi tiết và ví dụ mã cho từng mẫu mà chúng tôi đã sử dụng trong thiết kế giải pháp, cùng với nhiều mẫu liên quan. Các mẫu được phân loại theo ý định chính của chúng, bao gồm các mẫu cơ bản, mẫu kênh, mẫu tin nhắn, mẫu định tuyến, mẫu biến đổi, mẫu điểm cuối và mẫu quản lý hệ thống. Cách sắp xếp này giúp dễ dàng đọc tất cả các mẫu theo trình tự hoặc tra cứu các mẫu riêng lẻ như một tài liệu tham khảo.
Tích hợp doanh nghiệp là nhiệm vụ khiến các ứng dụng khác nhau hoạt động cùng nhau để tạo ra một tập hợp chức năng thống nhất. Các ứng dụng này có thể được phát triển tùy chỉnh tại chỗ hoặc mua từ các nhà cung cấp bên thứ ba. Chúng có thể chạy trên nhiều máy tính, có thể đại diện cho nhiều nền tảng khác nhau và có thể phân bố ở nhiều vị trí địa lý khác nhau. Một số ứng dụng có thể được vận hành bên ngoài doanh nghiệp bởi các đối tác kinh doanh hoặc khách hàng. Các ứng dụng khác có thể không được thiết kế với mục đích tích hợp và khó thay đổi. Những vấn đề này và những vấn đề tương tự khiến tích hợp ứng dụng trở nên phức tạp. Chương này khám phá nhiều phương pháp tích hợp có thể giúp vượt qua những thách thức này.
Những yếu tố nào tạo nên sự tích hợp ứng dụng tốt? Nếu nhu cầu tích hợp luôn giống nhau, sẽ chỉ có một kiểu tích hợp. Tuy nhiên, như bất kỳ nỗ lực công nghệ phức tạp nào, việc tích hợp ứng dụng liên quan đến một loạt các cân nhắc và hệ quả cần được xem xét cho bất kỳ cơ hội tích hợp nào.
Tiêu chí cơ bản là có nên sử dụng tích hợp ứng dụng hay không. Nếu bạn có thể phát triển một ứng dụng độc lập duy nhất mà không cần hợp tác với bất kỳ ứng dụng nào khác, bạn có thể hoàn toàn tránh được vấn đề tích hợp. Tuy nhiên, thực tế là ngay cả một doanh nghiệp đơn giản cũng có nhiều ứng dụng cần hoạt động cùng nhau để cung cấp trải nghiệm thống nhất cho nhân viên, đối tác và khách hàng của doanh nghiệp.
Dưới đây là một số tiêu chí quyết định chính khác.
Liên kết ứng dụng Các ứng dụng tích hợp nên giảm thiểu sự phụ thuộc vào nhau để mỗi ứng dụng có thể phát triển mà không gây ra vấn đề cho những ứng dụng khác. Như đã giải thích trong Chương 1, "Giải quyết các vấn đề tích hợp bằng cách sử dụng mẫu," các ứng dụng kết nối chặt chẽ thường đưa ra nhiều giả định về cách hoạt động của các ứng dụng khác; khi các ứng dụng thay đổi và phá vỡ những giả định đó, sự tích hợp giữa chúng cũng bị phá vỡ. Do đó, các giao diện để tích hợp ứng dụng nên cụ thể đủ để thực hiện chức năng hữu ích nhưng cũng đủ chung để cho phép việc thực hiện thay đổi khi cần thiết.
Tính xâm phạm Khi tích hợp một ứng dụng vào doanh nghiệp, các nhà phát triển nên nỗ lực để giảm thiểu cả thay đổi đối với ứng dụng và lượng mã tích hợp cần thiết. Tuy nhiên, những thay đổi và mã mới thường cần thiết để cung cấp chức năng tích hợp tốt, và những cách tiếp cận có ít tác động nhất đến ứng dụng có thể không cung cấp tích hợp tốt nhất vào doanh nghiệp.
Chọn lựa công nghệ Các kỹ thuật tích hợp khác nhau đòi hỏi những loại phần mềm và phần cứng chuyên dụng khác nhau. Những công cụ này có thể tốn kém, có thể dẫn đến việc bị khóa bởi nhà cung cấp, và có thể làm tăng độ khó học hỏi cho các nhà phát triển. Ngược lại, việc tạo ra một giải pháp tích hợp từ đầu thường dẫn đến nhiều nỗ lực hơn dự kiến ban đầu và có thể có nghĩa là phải phát minh lại bánh xe.
Định dạng dữ liệu Các ứng dụng tích hợp phải thống nhất về định dạng dữ liệu mà chúng trao đổi. Việc thay đổi các ứng dụng hiện có để sử dụng định dạng dữ liệu thống nhất có thể khó khăn hoặc không khả thi. Ngoài ra, một trình dịch trung gian có thể thống nhất các ứng dụng yêu cầu định dạng dữ liệu khác nhau. Một vấn đề liên quan là sự tiến hóa và khả năng mở rộng của định dạng dữ liệu - cách mà định dạng có thể thay đổi theo thời gian và cách mà sự thay đổi đó sẽ ảnh hưởng đến các ứng dụng.
Thời gian dữ liệu Sự tích hợp nên giảm thiểu khoảng thời gian giữa lúc một ứng dụng quyết định chia sẻ dữ liệu và các ứng dụng khác có được dữ liệu đó. Điều này có thể được thực hiện bằng cách trao đổi dữ liệu thường xuyên và theo từng khối nhỏ. Tuy nhiên, việc chia nhỏ một tập dữ liệu lớn thành các phần nhỏ có thể gây ra sự không hiệu quả. Thời gian trễ trong việc chia sẻ dữ liệu cần được xem xét trong thiết kế tích hợp. Lý tưởng nhất, các ứng dụng nhận nên được thông báo ngay khi dữ liệu đã chia sẻ sẵn sàng để tiêu thụ. Thời gian chia sẻ càng dài, cơ hội cho các ứng dụng bị mất đồng bộ càng lớn và sự tích hợp có thể trở nên phức tạp hơn.
Dữ liệu hoặc chức năng Nhiều giải pháp tích hợp cho phép các ứng dụng chia sẻ không chỉ dữ liệu mà còn cả chức năng, vì việc chia sẻ chức năng có thể cung cấp sự trừu tượng tốt hơn giữa các ứng dụng. Mặc dù việc gọi một chức năng trong một ứng dụng từ xa có thể có vẻ giống như việc gọi chức năng cục bộ, nhưng nó hoạt động khá khác biệt, với những hậu quả đáng kể cho cách thức tích hợp hoạt động.
Giao tiếp từ xa Xử lý máy tính thường là đồng bộ, tức là một quy trình chờ đợi trong khi thủ tục con của nó thực thi. Tuy nhiên, việc gọi một thủ tục con từ xa chậm hơn nhiều so với một thủ tục cục bộ, do đó một quy trình có thể không muốn chờ đợi thủ tục con hoàn thành; thay vào đó, nó có thể muốn gọi thủ tục con một cách không đồng bộ, tức là khởi động thủ tục con nhưng tiếp tục xử lý của chính nó đồng thời. Tính không đồng bộ có thể tạo ra một giải pháp hiệu quả hơn nhiều, nhưng giải pháp như vậy cũng phức tạp hơn để thiết kế, phát triển và gỡ lỗi.
Độ tin cậy Kết nối từ xa không chỉ chậm mà còn kém đáng tin cậy hơn nhiều so với một cuộc gọi hàm cục bộ. Khi một quy trình gọi một tiểu quy trình bên trong một ứng dụng, điều đó được xem là hiển nhiên rằng tiểu quy trình đó có sẵn. Điều này không nhất thiết đúng khi giao tiếp từ xa; ứng dụng từ xa có thể không chạy hoặc mạng có thể tạm thời không khả dụng. Giao tiếp bất đồng bộ đáng tin cậy cho phép ứng dụng nguồn tiếp tục công việc khác, với sự tự tin rằng ứng dụng từ xa sẽ thực hiện vào một thời điểm nào đó sau đó.
Vì vậy, như bạn có thể thấy, có một số tiêu chí khác nhau cần được xem xét khi chọn và thiết kế một phương pháp tích hợp. Câu hỏi trở thành, Phương pháp tích hợp nào tốt nhất đáp ứng được tiêu chí nào trong số này?
Không có một phương pháp tích hợp nào đáp ứng tất cả các tiêu chí một cách đồng đều. Do đó, nhiều phương pháp tích hợp ứng dụng đã phát triển theo thời gian. Các phương pháp khác nhau có thể được tóm gọn trong bốn phong cách tích hợp chính.
Chuyển Giao Tệp Yêu cầu mỗi ứng dụng tạo ra các tệp dữ liệu chia sẻ để các ứng dụng khác tiêu thụ và tiêu thụ các tệp mà các ứng dụng khác đã tạo ra.
Cơ sở dữ liệu chia sẻ Hãy để các ứng dụng lưu trữ dữ liệu mà chúng muốn chia sẻ trong một cơ sở dữ liệu chung.
Gọi Thủ tục Từ xa Hãy để mỗi ứng dụng cung cấp một số thủ tục của nó để có thể được gọi từ xa, và cho phép các ứng dụng gọi những thủ tục đó để khởi động hành vi và trao đổi dữ liệu.
Gửi tin nhắn Hãy để mỗi ứng dụng kết nối với một hệ thống nhắn tin chung và trao đổi dữ liệu cũng như kích hoạt hành vi bằng cách sử dụng tin nhắn.
Chương này trình bày mỗi phong cách như một mẫu. Bốn mẫu đều chia sẻ cùng một tuyên bố vấn đề: nhu cầu tích hợp các ứng dụng và những bối cảnh rất tương tự. Điều phân biệt chúng là các lực lượng tìm kiếm một giải pháp tinh tế hơn. Mỗi mẫu xây dựng dựa trên mẫu trước đó, tìm kiếm một cách tiếp cận tinh vi hơn để giải quyết những thiếu sót của các mẫu tiền nhiệm. Do đó, thứ tự các mẫu phản ánh một trật tự ngày càng tăng của sự tinh vi, nhưng cũng là sự phức tạp ngày càng tăng.
Mẹo là không chọn một phong cách nào để sử dụng mỗi lần, mà là chọn phong cách tốt nhất cho một cơ hội tích hợp cụ thể. Mỗi phong cách đều có những ưu điểm và nhược điểm của nó. Ứng dụng có thể tích hợp bằng nhiều phong cách khác nhau để mỗi điểm tích hợp tận dụng phong cách phù hợp nhất với nó. Tương tự, một ứng dụng có thể sử dụng các phong cách khác nhau để tích hợp với các ứng dụng khác nhau, chọn phong cách hoạt động tốt nhất cho ứng dụng kia. Kết quả là, nhiều phương pháp tích hợp có thể được nhìn nhận tốt nhất như là một sự kết hợp của nhiều phong cách tích hợp. Để hỗ trợ loại tích hợp này, nhiều sản phẩm phần mềm trung gian tích hợp và EAI sử dụng sự kết hợp của các phong cách, tất cả đều được ẩn giấu hiệu quả trong cách triển khai của sản phẩm.
Các mẫu trong phần còn lại của cuốn sách này mở rộng về phong cách tích hợp truyền thông. Chúng tôi tập trung vào truyền thông vì chúng tôi tin rằng nó cung cấp một sự cân bằng tốt giữa các tiêu chí tích hợp nhưng cũng là phong cách khó làm việc nhất. Do đó, truyền thông vẫn là phong cách tích hợp ít được hiểu rõ nhất và là một công nghệ đầy tiềm năng với nhiều mẫu giải thích nhanh chóng cách sử dụng nó một cách tốt nhất. Cuối cùng, truyền thông là cơ sở cho nhiều sản phẩm EAI thương mại, vì vậy việc giải thích cách sử dụng truyền thông hiệu quả cũng giúp bạn rất nhiều trong việc dạy bạn cách sử dụng những sản phẩm đó. Mục tiêu của phần này là làm nổi bật các vấn đề liên quan đến tích hợp ứng dụng và cách mà truyền thông phù hợp vào bối cảnh.
bởi Martin Fowler
Một doanh nghiệp có nhiều ứng dụng đang được xây dựng độc lập, với các ngôn ngữ và nền tảng khác nhau.
| Làm thế nào tôi có thể tích hợp nhiều ứng dụng để chúng hoạt động cùng nhau và có thể trao đổi thông tin? |
Trong một thế giới lý tưởng, bạn có thể tưởng tượng một tổ chức hoạt động từ một phần mềm thống nhất, được thiết kế ngay từ đầu để hoạt động theo cách đồng bộ và hợp lý. Tất nhiên, ngay cả những hoạt động nhỏ nhất cũng không hoạt động như vậy. Nhiều phần mềm khác nhau xử lý các khía cạnh khác nhau của doanh nghiệp. Điều này xảy ra vì nhiều lý do.
Mọi người mua các gói được phát triển bởi các tổ chức bên ngoài.
Các hệ thống khác nhau được xây dựng vào những thời điểm khác nhau, dẫn đến những lựa chọn công nghệ khác nhau.
Các hệ thống khác nhau được xây dựng bởi những người khác nhau, những người có kinh nghiệm và sở thích dẫn họ đến những cách tiếp cận khác nhau trong việc xây dựng ứng dụng.
Việc phát hành một ứng dụng và mang lại giá trị quan trọng hơn việc đảm bảo rằng tích hợp được giải quyết, đặc biệt khi sự tích hợp đó không mang lại giá trị nào cho ứng dụng đang được phát triển.
Kết quả là, bất kỳ tổ chức nào cũng phải lo lắng về việc chia sẻ thông tin giữa các ứng dụng rất khác nhau. Chúng có thể được viết bằng các ngôn ngữ khác nhau, dựa trên các nền tảng khác nhau và có những giả định khác nhau về cách mà doanh nghiệp hoạt động.
Kết nối những ứng dụng như vậy đòi hỏi một sự hiểu biết sâu sắc về cách liên kết các ứng dụng ở cả cấp độ kinh doanh và kỹ thuật. Điều này sẽ dễ dàng hơn nhiều nếu bạn giảm thiểu những gì cần biết về cách mỗi ứng dụng hoạt động.
Điều cần thiết là một cơ chế chuyển giao dữ liệu chung có thể được sử dụng bởi nhiều ngôn ngữ và nền tảng khác nhau nhưng vẫn mang lại cảm giác tự nhiên cho từng loại. Nó nên yêu cầu một lượng phần cứng và phần mềm chuyên dụng tối thiểu, tận dụng những gì mà doanh nghiệp đã có sẵn.
Tệp là một cơ chế lưu trữ phổ quát, được tích hợp vào bất kỳ hệ điều hành doanh nghiệp nào và có sẵn từ bất kỳ ngôn ngữ doanh nghiệp nào. Cách tiếp cận đơn giản nhất sẽ là tích hợp các ứng dụng bằng cách sử dụng tệp.
| Hãy để mỗi ứng dụng tạo ra các tệp chứa thông tin mà các ứng dụng khác cần tiêu thụ. Những người tích hợp sẽ chịu trách nhiệm chuyển đổi các tệp thành các định dạng khác nhau. Sản xuất các tệp đó theo các khoảng thời gian định kỳ tùy thuộc vào tính chất của doanh nghiệp.
|
Một quyết định quan trọng liên quan đến tệp là định dạng nào để sử dụng. Rất hiếm khi đầu ra của một ứng dụng lại hoàn toàn phù hợp với yêu cầu của một ứng dụng khác, vì vậy bạn sẽ phải thực hiện khá nhiều quá trình xử lý các tệp trong suốt quá trình. Điều này có nghĩa là không chỉ tất cả các ứng dụng sử dụng một tệp phải đọc được nó, mà bạn cũng phải có khả năng sử dụng các công cụ xử lý trên nó. Kết quả là, các định dạng tệp chuẩn đã phát triển theo thời gian. Các hệ thống mainframe thường sử dụng các nguồn dữ liệu dựa trên định dạng hệ thống tệp của COBOL. Các hệ thống UNIX sử dụng các tệp dựa trên văn bản. Phương pháp hiện tại là sử dụng XML. Một ngành công nghiệp các công cụ đọc, viết và chuyển đổi đã hình thành xung quanh từng định dạng này.
Một vấn đề khác với các tệp tin là khi nào nên sản xuất và tiêu thụ chúng. Bởi vì có một lượng công sức nhất định cần thiết để sản xuất và xử lý một tệp tin, bạn thường không muốn làm việc với chúng quá thường xuyên. Thông thường, bạn có một chu kỳ kinh doanh đều đặn nào đó quyết định thời điểm: hàng đêm, hàng tuần, hàng quý, và như vậy. Các ứng dụng sẽ quen với thời điểm khi một tệp tin mới có sẵn và xử lý nó vào thời điểm đó.
Lợi thế lớn của việc sử dụng tệp tin là các tích hợp viên không cần phải hiểu biết về nội bộ của một ứng dụng. Đội ngũ ứng dụng thường tự cung cấp tệp tin. Nội dung và định dạng của tệp tin được thảo luận với các tích hợp viên, mặc dù nếu sử dụng một gói, các lựa chọn thường bị hạn chế. Các tích hợp viên sau đó sẽ xử lý các biến đổi cần thiết cho các ứng dụng khác, hoặc họ để cho các ứng dụng tiêu thụ quyết định cách mà họ muốn thao tác và đọc tệp tin. Kết quả là, các ứng dụng khác nhau được tách rời khá tốt khỏi nhau. Mỗi ứng dụng có thể thực hiện các thay đổi nội bộ một cách tự do mà không ảnh hưởng đến các ứng dụng khác, với điều kiện chúng vẫn sản xuất ra cùng một dữ liệu trong các tệp tin với cùng một định dạng. Các tệp tin thực sự trở thành giao diện công cộng của mỗi ứng dụng.
Một phần lý do khiến việc Chuyển File trở nên đơn giản là không cần thêm công cụ hoặc gói tích hợp nào, nhưng điều đó cũng có nghĩa là các nhà phát triển phải tự làm nhiều việc. Các ứng dụng phải đồng ý về quy ước đặt tên file và các thư mục mà chúng xuất hiện. Người viết file phải triển khai một chiến lược để giữ cho tên file là duy nhất. Các ứng dụng phải đồng ý về việc ai sẽ xóa các file cũ, và ứng dụng có trách nhiệm đó sẽ phải biết khi nào một file đã cũ và không còn cần thiết nữa. Các ứng dụng sẽ cần triển khai một cơ chế khóa hoặc tuân theo một quy tắc thời gian để đảm bảo rằng một ứng dụng không cố gắng đọc file trong khi một ứng dụng khác vẫn đang ghi vào nó. Nếu tất cả các ứng dụng không có quyền truy cập vào cùng một đĩa, thì một ứng dụng nào đó phải chịu trách nhiệm chuyển file từ đĩa này sang đĩa khác.
Một trong những vấn đề rõ ràng nhất với việc Chuyển File là các bản cập nhật thường xảy ra không thường xuyên, và vì vậy các hệ thống có thể bị mất đồng bộ. Một hệ thống quản lý khách hàng có thể xử lý việc thay đổi địa chỉ và sản xuất một tệp trích xuất mỗi đêm, nhưng hệ thống lập hóa đơn có thể gửi hóa đơn đến một địa chỉ cũ trong cùng ngày. Đôi khi, việc thiếu đồng bộ không phải là vấn đề lớn. Mọi người thường mong đợi một khoảng thời gian trễ trong việc nhận thông tin, ngay cả với máy tính. Tuy nhiên, đôi khi kết quả của việc sử dụng thông tin lỗi thời lại là một thảm họa. Khi quyết định thời điểm sản xuất các tệp, bạn phải cân nhắc đến nhu cầu về độ tươi mới của người tiêu dùng.
Trên thực tế, vấn đề lớn nhất với sự cũ kỹ thường nằm ở chính đội ngũ phát triển phần mềm, những người thường phải đối mặt với dữ liệu không hoàn toàn chính xác. Điều này có thể dẫn đến những sự không nhất quán khó giải quyết. Nếu một khách hàng thay đổi địa chỉ vào cùng một ngày trên hai hệ thống khác nhau, nhưng một trong số đó xảy ra lỗi và ghi sai tên đường, bạn sẽ có hai địa chỉ khác nhau cho một khách hàng. Bạn sẽ cần một cách nào đó để tìm ra cách giải quyết vấn đề này. Thời gian càng dài giữa các lần chuyển tập tin, vấn đề này càng có khả năng xảy ra và càng đau đớn hơn.
Tất nhiên, không có lý do gì mà bạn không thể sản xuất các tệp thường xuyên hơn. Thực tế, bạn có thể nghĩ về Messaging như là Chuyển giao tệp, nơi bạn tạo ra một tệp với mỗi thay đổi trong một ứng dụng. Vấn đề là quản lý tất cả các tệp được sản xuất, đảm bảo rằng tất cả đều được đọc và không tệp nào bị mất. Điều này vượt ra ngoài những gì mà các phương pháp dựa trên hệ thống tệp có thể làm, đặc biệt là vì có những chi phí tài nguyên đắt đỏ liên quan đến việc xử lý một tệp, điều này có thể trở nên cản trở nếu bạn muốn sản xuất nhiều tệp một cách nhanh chóng. Kết quả là, một khi bạn có rất nhiều tệp chi tiết, dễ dàng hơn để nghĩ về chúng như là Messaging.
Để làm cho dữ liệu có sẵn nhanh hơn và đảm bảo một tập hợp định dạng dữ liệu đã được thống nhất, hãy sử dụng Cơ sở Dữ liệu Chia sẻ. Để tích hợp chức năng của các ứng dụng thay vì dữ liệu của chúng, hãy sử dụng Gọi Thủ tục Từ xa. Để cho phép trao đổi thường xuyên các lượng dữ liệu nhỏ, có thể được sử dụng để gọi chức năng từ xa, hãy sử dụng Nhắn tin.
bởi Martin Fowler
Một doanh nghiệp có nhiều ứng dụng đang được xây dựng độc lập, với các ngôn ngữ và nền tảng khác nhau. Doanh nghiệp cần thông tin được chia sẻ nhanh chóng và nhất quán.
| Làm thế nào tôi có thể tích hợp nhiều ứng dụng để chúng hoạt động cùng nhau và có thể trao đổi thông tin? |
Chuyển file cho phép các ứng dụng chia sẻ dữ liệu, nhưng có thể thiếu tính kịp thời, trong khi tính kịp thời của việc tích hợp thường rất quan trọng. Nếu các thay đổi không nhanh chóng được đưa vào một gia đình ứng dụng, bạn có khả năng mắc sai lầm do dữ liệu lỗi thời. Đối với các doanh nghiệp hiện đại, điều quan trọng là mọi người phải có dữ liệu mới nhất. Điều này không chỉ giảm thiểu sai sót, mà còn tăng cường niềm tin của mọi người vào chính dữ liệu đó.
Cập nhật nhanh cũng cho phép xử lý các bất nhất tốt hơn. Càng đồng bộ hóa thường xuyên, bạn càng ít có khả năng gặp phải các bất nhất và càng ít nỗ lực để giải quyết chúng. Nhưng dù có nhanh chóng đến đâu, vẫn sẽ có vấn đề xảy ra. Nếu một địa chỉ được cập nhật không nhất quán trong một khoảng thời gian ngắn, bạn làm thế nào để quyết định địa chỉ nào là địa chỉ thực tế? Bạn có thể lấy từng mảnh dữ liệu và nói rằng một ứng dụng là nguồn chính cho dữ liệu đó, nhưng sau đó bạn sẽ phải nhớ ứng dụng nào là nguồn chính cho dữ liệu nào.
Việc chuyển giao tệp cũng có thể không thực thi định dạng dữ liệu một cách đủ chặt chẽ. Nhiều vấn đề trong việc tích hợp xuất phát từ những cách không tương thích trong việc nhìn nhận dữ liệu. Thường thì những vấn đề này thể hiện những vấn đề kinh doanh tinh tế có thể ảnh hưởng lớn. Một cơ sở dữ liệu địa chất có thể định nghĩa một giếng dầu là một lỗ khoan duy nhất có thể hoặc không thể sản xuất dầu. Một cơ sở dữ liệu sản xuất có thể định nghĩa một giếng là nhiều lỗ được che phủ bởi một thiết bị duy nhất. Những trường hợp sai lệch nghĩa này khó giải quyết hơn nhiều so với định dạng dữ liệu không nhất quán. (Để thảo luận sâu hơn về những vấn đề này, thật sự đáng để đọc cuốn sách "Dữ liệu và Thực tế" [Kent].) Cần có một kho dữ liệu trung tâm đã được thống nhất mà tất cả các ứng dụng chia sẻ, để mỗi ứng dụng có thể truy cập bất kỳ dữ liệu nào được chia sẻ khi cần.
| Tích hợp các ứng dụng bằng cách để chúng lưu trữ dữ liệu của mình trong một Cơ sở Dữ liệu Chung, và định nghĩa lược đồ của cơ sở dữ liệu để đáp ứng tất cả các nhu cầu của các ứng dụng khác nhau.
|
Nếu một gia đình các ứng dụng tích hợp đều phụ thuộc vào cùng một cơ sở dữ liệu, thì bạn có thể khá chắc chắn rằng chúng luôn nhất quán mọi lúc. Nếu bạn nhận được các cập nhật đồng thời cho cùng một dữ liệu từ các nguồn khác nhau, thì bạn có các hệ thống quản lý giao dịch xử lý việc đó một cách duyên dáng như có thể. Do khoảng thời gian giữa các bản cập nhật rất ngắn, nên bất kỳ lỗi nào cũng dễ dàng tìm thấy và sửa chữa hơn.
Cơ sở dữ liệu chia sẻ trở nên dễ dàng hơn rất nhiều nhờ sự phổ biến của các cơ sở dữ liệu quan hệ dựa trên SQL. Hầu như tất cả các nền tảng phát triển ứng dụng đều có thể làm việc với SQL, thường với những công cụ khá tinh vi. Vì vậy, bạn không phải lo lắng về nhiều định dạng tệp khác nhau. Do bất kỳ ứng dụng nào cũng phải sử dụng SQL, điều này giúp tránh việc thêm một công nghệ khác mà mọi người phải làm chủ.
Vì mọi ứng dụng đều sử dụng cùng một cơ sở dữ liệu, điều này buộc phải đối mặt với các vấn đề về sự không nhất quán ngữ nghĩa. Thay vì để cho những vấn đề này tiếp tục tồn tại cho đến khi chúng trở nên khó giải quyết bằng các quá trình chuyển đổi, bạn buộc phải đối mặt và giải quyết chúng trước khi phần mềm được đưa vào sử dụng và bạn thu thập một khối lượng lớn dữ liệu không tương thích.
Một trong những khó khăn lớn nhất với Cơ sở Dữ liệu Chia sẻ là việc đưa ra một thiết kế phù hợp cho cơ sở dữ liệu chia sẻ. Việc tạo ra một lược đồ thống nhất có thể đáp ứng nhu cầu của nhiều ứng dụng là một bài tập rất khó khăn, thường dẫn đến một lược đồ mà các lập trình viên ứng dụng cảm thấy khó làm việc. Và nếu những khó khăn kỹ thuật trong việc thiết kế một lược đồ thống nhất chưa đủ, còn có những khó khăn chính trị nghiêm trọng. Nếu một ứng dụng quan trọng có khả năng bị chậm lại để làm việc với một lược đồ thống nhất, thì thường sẽ có áp lực không thể cưỡng lại để tách biệt. Những xung đột giữa các phòng ban con thường làm trầm trọng thêm vấn đề này.
Một giới hạn khác, khắt khe hơn đối với Cơ sở Dữ liệu Chia sẻ là các gói phần mềm bên ngoài. Hầu hết các ứng dụng đóng gói sẽ không hoạt động với một lược đồ khác ngoài lược đồ của chính chúng. Ngay cả khi có một số không gian cho sự thích ứng, có khả năng nó sẽ bị giới hạn nhiều hơn so với những gì các nhà tích hợp mong muốn. Thêm vào đó, các nhà cung cấp phần mềm thường bảo lưu quyền thay đổi lược đồ với mỗi lần phát hành mới của phần mềm.
Vấn đề này cũng mở rộng đến việc tích hợp sau khi phát triển. Ngay cả khi bạn có thể tổ chức tất cả các ứng dụng của mình, bạn vẫn gặp phải vấn đề tích hợp nếu xảy ra sự sáp nhập công ty.
Nhiều ứng dụng sử dụng một cơ sở dữ liệu chung để thường xuyên đọc và sửa đổi cùng một dữ liệu có thể biến cơ sở dữ liệu thành một nút thắt về mặt hiệu suất và có thể gây ra tình trạng deadlock khi mỗi ứng dụng khóa dữ liệu của nhau. Khi các ứng dụng được phân phối qua nhiều vị trí, việc truy cập một cơ sở dữ liệu chung qua mạng diện rộng thường quá chậm để thực tiễn. Phân tán cơ sở dữ liệu cũng cho phép mỗi ứng dụng truy cập cơ sở dữ liệu qua kết nối mạng cục bộ, nhưng gây nhầm lẫn về việc dữ liệu nên được lưu trữ trên máy tính nào. Một cơ sở dữ liệu phân tán với xung đột khóa có thể dễ dàng trở thành một cơn ác mộng về hiệu suất.
Để tích hợp chức năng của ứng dụng thay vì dữ liệu của chúng, hãy sử dụng Gọi Thủ tục Từ xa. Để cho phép trao đổi thường xuyên các lượng dữ liệu nhỏ bằng cách sử dụng định dạng theo loại dữ liệu thay vì một sơ đồ chung, hãy sử dụng Nhắn tin.
bởi Martin Fowler
Một doanh nghiệp có nhiều ứng dụng đang được xây dựng độc lập, với các ngôn ngữ và nền tảng khác nhau. Doanh nghiệp cần chia sẻ dữ liệu và quy trình một cách nhạy bén.
| Làm thế nào tôi có thể tích hợp nhiều ứng dụng để chúng hoạt động cùng nhau và có thể trao đổi thông tin? |
Chuyển giao tệp và cơ sở dữ liệu chia sẻ cho phép các ứng dụng chia sẻ dữ liệu của chúng, điều này là một phần quan trọng trong tích hợp ứng dụng, nhưng chỉ chia sẻ dữ liệu thường không đủ. Những thay đổi trong dữ liệu thường yêu cầu có hành động được thực hiện giữa các ứng dụng khác nhau. Ví dụ, thay đổi địa chỉ có thể chỉ là một thay đổi đơn giản trong dữ liệu, hoặc nó có thể kích hoạt các quy trình đăng ký và pháp lý để xem xét các quy định khác nhau ở các khu vực pháp lý khác nhau. Việc một ứng dụng kích hoạt các quy trình như vậy trực tiếp trong các ứng dụng khác sẽ yêu cầu các ứng dụng phải biết quá nhiều về cấu trúc bên trong của các ứng dụng khác.
Vấn đề này phản ánh một tình huống cổ điển trong thiết kế ứng dụng. Một trong những cơ chế cấu trúc mạnh mẽ nhất trong thiết kế ứng dụng là đóng gói, nơi các mô-đun che giấu dữ liệu của chúng thông qua giao diện gọi hàm. Bằng cách này, chúng có thể chặn các thay đổi trong dữ liệu để thực hiện các hành động khác nhau mà chúng cần thực hiện khi dữ liệu bị thay đổi. Cơ sở dữ liệu chia sẻ cung cấp một cấu trúc dữ liệu lớn, không được đóng gói, điều này làm cho việc này trở nên khó khăn hơn. Chuyển file cho phép một ứng dụng phản ứng với các thay đổi khi nó xử lý file, nhưng quá trình này bị trì hoãn.
Sự thật rằng Cơ sở dữ liệu Chia sẻ có dữ liệu không được đóng gói cũng làm cho việc duy trì một loạt các ứng dụng tích hợp trở nên khó khăn hơn. Nhiều thay đổi trong bất kỳ ứng dụng nào có thể kích hoạt một thay đổi trong cơ sở dữ liệu, và những thay đổi này có ảnh hưởng đáng kể trong mọi ứng dụng. Kết quả là, các tổ chức sử dụng Cơ sở dữ liệu Chia sẻ thường rất ngần ngại trong việc thay đổi cơ sở dữ liệu, điều này có nghĩa là công việc phát triển ứng dụng kém phản ứng hơn với những nhu cầu thay đổi của doanh nghiệp.
Cần có một cơ chế để một ứng dụng có thể gọi một hàm trong ứng dụng khác, truyền dữ liệu cần chia sẻ và gọi hàm cho ứng dụng nhận biết cách xử lý dữ liệu.
| Phát triển mỗi ứng dụng như một đối tượng hoặc thành phần quy mô lớn với dữ liệu được đóng gói. Cung cấp một giao diện để cho phép các ứng dụng khác tương tác với ứng dụng đang chạy.
|
Gọi thủ tục từ xa áp dụng nguyên tắc đóng gói để tích hợp các ứng dụng. Nếu một ứng dụng cần thông tin mà thuộc sở hữu của một ứng dụng khác, nó sẽ yêu cầu ứng dụng đó trực tiếp. Nếu một ứng dụng cần sửa đổi dữ liệu của ứng dụng khác, nó thực hiện bằng cách gọi vào ứng dụng kia. Điều này cho phép mỗi ứng dụng duy trì tính toàn vẹn của dữ liệu mà nó sở hữu. Hơn nữa, mỗi ứng dụng có thể thay đổi định dạng dữ liệu nội bộ của mình mà không ảnh hưởng đến các ứng dụng khác.
Một số công nghệ, chẳng hạn như CORBA, COM, .NET Remoting và Java RMI, thực hiện Gọi Thủ Tục Từ Xa (còn được gọi là Gọi Thủ Tục Từ Xa, hay RPC). Những phương pháp này khác nhau về số lượng hệ thống hỗ trợ chúng và mức độ dễ sử dụng. Thường thì những môi trường này bổ sung các khả năng bổ sung, chẳng hạn như giao dịch. Để nói về tính phổ biến, hiện nay, dịch vụ Web là lựa chọn ưa thích, sử dụng các tiêu chuẩn như SOAP và XML. Một đặc điểm đặc biệt có giá trị của dịch vụ Web là chúng hoạt động dễ dàng với HTTP, điều này dễ dàng vượt qua các tường lửa.
Sự thật là có những phương pháp bọc dữ liệu giúp dễ dàng hơn trong việc xử lý sự không đồng bộ về ngữ nghĩa. Các ứng dụng có thể cung cấp nhiều giao diện cho cùng một dữ liệu, cho phép một số khách hàng thấy một kiểu và những người khác thấy một kiểu khác. Ngay cả cập nhật cũng có thể sử dụng nhiều giao diện. Điều này cung cấp khả năng hỗ trợ nhiều quan điểm hơn so với những gì có thể đạt được bằng các quan điểm liên quan. Tuy nhiên, việc các nhà tích hợp thêm các thành phần biến đổi là khá khó khăn, vì vậy mỗi ứng dụng cần phải thương lượng giao diện của mình với các ứng dụng lân cận.
Vì các nhà phát triển phần mềm đã quen với các cuộc gọi thủ tục, Gọi Thủ Tục Từ Xa phù hợp với những gì họ đã quen. Thực ra, đây nhiều hơn là một bất lợi hơn là một lợi thế. Có những khác biệt lớn về hiệu suất và độ tin cậy giữa các cuộc gọi thủ tục từ xa và cục bộ. Nếu mọi người không hiểu điều này, thì Gọi Thủ Tục Từ Xa có thể dẫn đến những hệ thống chậm và không đáng tin cậy.
Mặc dù việc đóng gói giúp giảm sự liên kết giữa các ứng dụng bằng cách loại bỏ một cấu trúc dữ liệu chung lớn, các ứng dụng vẫn khá chặt chẽ với nhau. Các cuộc gọi từ xa mà mỗi hệ thống hỗ trợ có xu hướng buộc các hệ thống khác nhau vào một cái nút ngày càng phức tạp. Cụ thể, việc sắp xếp – thực hiện một số việc theo một thứ tự cụ thể – có thể gây khó khăn trong việc thay đổi các hệ thống một cách độc lập. Những loại vấn đề này thường phát sinh vì những vấn đề không quan trọng trong một ứng dụng đơn lẻ trở nên quan trọng khi tích hợp các ứng dụng. Mọi người thường thiết kế sự tích hợp theo cách mà họ sẽ thiết kế một ứng dụng đơn lẻ, không nhận ra rằng các quy tắc của sự tham gia thay đổi đáng kể.
Để tích hợp các ứng dụng theo cách lỏng lẻo hơn và bất đồng bộ, hãy sử dụng Tin nhắn để cho phép các trao đổi thường xuyên của lượng dữ liệu nhỏ, có thể được sử dụng để kích hoạt chức năng từ xa.
Một doanh nghiệp có nhiều ứng dụng đang được xây dựng độc lập, với các ngôn ngữ và nền tảng khác nhau. Doanh nghiệp cần chia sẻ dữ liệu và quy trình một cách linh hoạt.
| Làm thế nào tôi có thể tích hợp nhiều ứng dụng để chúng hoạt động cùng nhau và có thể trao đổi thông tin? |
Chuyển giao tệp và cơ sở dữ liệu chia sẻ cho phép các ứng dụng chia sẻ dữ liệu của chúng nhưng không phải là chức năng của chúng. Gọi thủ tục từ xa cho phép các ứng dụng chia sẻ chức năng, nhưng cũng làm cho chúng trở nên chặt chẽ với nhau. Thường thì thách thức trong việc tích hợp là làm cho sự hợp tác giữa các hệ thống khác nhau diễn ra kịp thời nhất có thể, mà không làm cho các hệ thống trở nên phụ thuộc vào nhau đến mức không đáng tin cậy, cả về mặt thực thi ứng dụng lẫn phát triển ứng dụng.
Chuyển giao tệp cho phép bạn giữ cho các ứng dụng tách biệt tốt, nhưng phải trả giá bằng tính kịp thời. Các hệ thống chỉ không thể theo kịp nhau. Hành vi cộng tác quá chậm. Cơ sở dữ liệu chia sẻ giữ dữ liệu cùng nhau một cách nhanh nhẹn nhưng phải trả giá bằng việc làm cho mọi thứ phụ thuộc vào cơ sở dữ liệu. Nó cũng không thể xử lý hành vi cộng tác.
Đối mặt với những vấn đề này, Gọi Thủ Tục Từ Xa (RPC) có vẻ là một sự lựa chọn hấp dẫn. Nhưng việc mở rộng một mô hình ứng dụng đơn lẻ cho việc tích hợp ứng dụng sẽ làm nổi bật rất nhiều điểm yếu khác. Những điểm yếu này bắt đầu từ những vấn đề thiết yếu của phát triển phân tán. Mặc dù các RPC trông giống như các cuộc gọi cục bộ, nhưng chúng không hành xử theo cách tương tự. Các cuộc gọi từ xa chậm hơn, và chúng có khả năng thất bại cao hơn rất nhiều. Khi có nhiều ứng dụng giao tiếp qua một doanh nghiệp, bạn không muốn sự cố của một ứng dụng làm ảnh hưởng đến tất cả các ứng dụng khác. Ngoài ra, bạn không muốn thiết kế một hệ thống với giả định rằng các cuộc gọi là nhanh chóng, và bạn không muốn mỗi ứng dụng phải biết chi tiết về các ứng dụng khác, ngay cả khi chỉ là chi tiết về giao diện của chúng.
Điều chúng ta cần là một cái gì đó giống như Chuyển Giao Tệp, trong đó rất nhiều gói dữ liệu nhỏ có thể được sản xuất nhanh chóng và dễ dàng chuyển giao, và ứng dụng nhận sẽ tự động được thông báo khi một gói mới có sẵn để tiêu thụ. Việc chuyển giao cần có cơ chế thử lại để đảm bảo thành công. Chi tiết về bất kỳ cấu trúc đĩa hoặc cơ sở dữ liệu nào để lưu trữ dữ liệu cần được giấu kín khỏi các ứng dụng để, khác với Cơ Sở Dữ Liệu Chia Sẻ, lược đồ lưu trữ và chi tiết có thể dễ dàng thay đổi để phản ánh những nhu cầu thay đổi của doanh nghiệp. Một ứng dụng nên có thể gửi một gói dữ liệu đến một ứng dụng khác để kích hoạt hành vi trong ứng dụng đó, giống như Gọi Thủ Tục Từ Xa, nhưng không bị dễ hỏng. Việc chuyển giao dữ liệu nên là không đồng bộ để người gửi không cần phải chờ đợi người nhận, đặc biệt là khi cần thử lại.
| Sử dụng Nhắn tin để truyền tải các gói dữ liệu thường xuyên, ngay lập tức, đáng tin cậy và không đồng bộ, sử dụng các định dạng tùy chỉnh.
|
Gửi tin nhắn không yêu cầu cả hai hệ thống phải hoạt động và sẵn sàng cùng lúc. Hơn nữa, suy nghĩ về giao tiếp theo cách không đồng bộ buộc các nhà phát triển nhận ra rằng làm việc với một ứng dụng từ xa chậm hơn, điều này khuyến khích việc thiết kế các thành phần có tính gắn kết cao (nhiều công việc thực hiện cục bộ) và độ kết dính thấp (công việc chọn lọc từ xa).
Hệ thống nhắn tin cũng cho phép nhiều phần tách rời mà bạn nhận được khi sử dụng Chuyển File. Tin nhắn có thể được biến đổi trong quá trình truyền tải mà không cần người gửi hoặc người nhận biết về sự biến đổi đó. Sự tách rời này cho phép những người tích hợp lựa chọn giữa việc phát tin nhắn đến nhiều người nhận, định tuyến một tin nhắn đến một trong nhiều người nhận, hoặc các cấu trúc khác. Điều này tách biệt các quyết định tích hợp khỏi việc phát triển ứng dụng. Vì những vấn đề liên quan đến con người thường tách rời việc phát triển ứng dụng khỏi việc tích hợp ứng dụng, nên phương pháp này hoạt động với bản chất con người chứ không phải chống lại nó.
Sự biến đổi này có nghĩa là các ứng dụng riêng biệt có thể có những mô hình khái niệm hoàn toàn khác nhau. Tất nhiên, điều này có nghĩa là sẽ xảy ra sự không đồng nhất về nghĩa. Tuy nhiên, quan điểm của thông điệp là các biện pháp được sử dụng bởi Cơ sở Dữ liệu Chia sẻ để tránh sự không đồng nhất về nghĩa là quá phức tạp để hoạt động trong thực tế. Ngoài ra, sự không đồng nhất về nghĩa sẽ xảy ra với các ứng dụng của bên thứ ba và với các ứng dụng được thêm vào như một phần của cuộc sáp nhập công ty, vì vậy phương pháp thông điệp là giải quyết vấn đề này thay vì thiết kế các ứng dụng để tránh nó.
Bằng cách gửi các tin nhắn nhỏ thường xuyên, bạn cũng cho phép các ứng dụng hợp tác hành vi cũng như chia sẻ dữ liệu. Nếu một quy trình cần được khởi động khi một yêu cầu bồi thường bảo hiểm được nhận, nó có thể được thực hiện ngay lập tức bằng cách gửi một tin nhắn khi một yêu cầu duy nhất đến. Thông tin có thể được yêu cầu và phản hồi nhanh chóng. Mặc dù sự hợp tác như vậy sẽ không nhanh như Gọi Thủ tục Từ xa, nhưng người gọi không cần dừng lại trong khi tin nhắn đang được xử lý và phản hồi được trả về. Và nhắn tin không chậm như nhiều người nghĩ; nhiều giải pháp nhắn tin xuất phát từ ngành dịch vụ tài chính, nơi hàng ngàn báo giá cổ phiếu hoặc giao dịch phải được truyền qua một hệ thống nhắn tin mỗi giây.
Cuốn sách này nói về Messaging, vì vậy bạn có thể yên tâm rằng chúng tôi coi Messaging là phương pháp tốt nhất cho việc tích hợp ứng dụng doanh nghiệp. Tuy nhiên, bạn không nên cho rằng nó hoàn toàn không có vấn đề. Tần suất cao của các thông điệp trong Messaging giảm nhiều vấn đề không nhất quán mà File Transfer gặp phải, nhưng nó không hoàn toàn loại bỏ được chúng. Vẫn sẽ có một số vấn đề chậm trễ với các hệ thống không được cập nhật hoàn toàn đồng thời. Thiết kế bất đồng bộ không phải là cách mà hầu hết các chuyên gia phần mềm được đào tạo, và kết quả là có nhiều quy tắc và kỹ thuật khác nhau được áp dụng. Bối cảnh messaging làm cho điều này dễ dàng hơn một chút so với lập trình trong môi trường ứng dụng bất đồng bộ như X Windows, nhưng tính bất đồng bộ vẫn có một đường cong học tập. Việc kiểm tra và gỡ lỗi cũng khó khăn hơn trong môi trường này.
Khả năng chuyển đổi thông điệp mang lại lợi ích lớn là cho phép các ứng dụng trở nên tách biệt hơn so với việc Gọi Thủ Tục Từ Xa. Tuy nhiên, sự độc lập này có nghĩa là các nhà tích hợp thường phải viết rất nhiều mã nối không gọn gàng để kết nối mọi thứ lại với nhau.
Khi bạn quyết định rằng bạn muốn sử dụng Tin nhắn cho tích hợp hệ thống, có một số vấn đề mới cần xem xét và các phương pháp bạn có thể áp dụng.
Bạn truyền tải các gói dữ liệu như thế nào?
Một người gửi gửi dữ liệu đến một người nhận bằng cách gửi một Thông điệp qua Kênh Thông điệp kết nối người gửi và người nhận.
Bạn biết gửi dữ liệu đến đâu?
Nếu người gửi không biết gửi dữ liệu đến đâu, họ có thể gửi dữ liệu đến một Bộ định tuyến Tin nhắn, bộ này sẽ chuyển dữ liệu đến người nhận thích hợp.
Làm thế nào bạn biết sử dụng định dạng dữ liệu nào?
Nếu người gửi và người nhận không đồng ý về định dạng dữ liệu, người gửi có thể chỉ định dữ liệu đến một Bộ dịch Tin nhắn, bộ này sẽ chuyển đổi dữ liệu sang định dạng của người nhận và sau đó chuyển tiếp dữ liệu đến người nhận.
Nếu bạn là một nhà phát triển ứng dụng, bạn kết nối ứng dụng của mình với hệ thống nhắn tin như thế nào?
Một ứng dụng muốn sử dụng nhắn tin sẽ triển khai Điểm cuối Tin nhắn để thực hiện việc gửi và nhận thực tế.
Giới thiệu
Kênh Tin nhắn
Tin nhắn
"Ống và bộ lọc"
Bộ định tuyến tin nhắn
Người dịch tin nhắn
Điểm cuối thông điệp
Trong Chương 2, "Cách Tích Hợp," chúng ta đã thảo luận về các tùy chọn khác nhau để kết nối các ứng dụng với nhau, bao gồm cả Nhắn Tin. Nhắn Tin làm cho các ứng dụng lỏng lẻo liên kết với nhau bằng cách giao tiếp không đồng bộ, điều này cũng giúp cho việc giao tiếp trở nên đáng tin cậy hơn vì hai ứng dụng không cần phải chạy cùng một lúc. Nhắn Tin khiến hệ thống nhắn tin chịu trách nhiệm chuyển dữ liệu từ ứng dụng này sang ứng dụng khác, vì vậy các ứng dụng có thể tập trung vào việc dữ liệu nào cần được chia sẻ thay vì phải lo lắng về cách chia sẻ nó.
Giống như hầu hết các công nghệ, Nhắn tin liên quan đến một số khái niệm cơ bản nhất định. Một khi bạn hiểu những khái niệm này, bạn có thể hiểu công nghệ ngay cả trước khi bạn nắm rõ tất cả các chi tiết về cách sử dụng nó. Dưới đây là những khái niệm nhắn tin cơ bản.
Kênh Các ứng dụng nhắn tin truyền dữ liệu qua một Kênh Tin Nhắn, một ống dẫn ảo kết nối người gửi với người nhận. Một hệ thống nhắn tin mới được cài đặt thường không chứa bất kỳ kênh nào; bạn phải xác định cách mà các ứng dụng của bạn cần giao tiếp và sau đó tạo ra các kênh để thuận tiện cho việc đó.
Tin nhắn Một tin nhắn là một gói dữ liệu nguyên tử có thể được truyền trên một kênh. Do đó, để truyền dữ liệu, một ứng dụng phải chia dữ liệu thành một hoặc nhiều gói, bọc mỗi gói thành một tin nhắn, và sau đó gửi tin nhắn trên một kênh. Tương tự, một ứng dụng nhận sẽ nhận tin nhắn và phải trích xuất dữ liệu từ tin nhắn để xử lý nó. Hệ thống tin nhắn sẽ cố gắng lặp đi lặp lại để giao tin nhắn (ví dụ: truyền từ người gửi đến người nhận) cho đến khi thành công.
Hệ thống ống và bộ lọc Trong trường hợp đơn giản nhất, hệ thống nhắn tin chuyển một tin nhắn trực tiếp từ máy tính của người gửi đến máy tính của người nhận. Tuy nhiên, một số hành động thường cần được thực hiện trên tin nhắn sau khi nó được gửi bởi người gửi ban đầu nhưng trước khi nó được nhận bởi người nhận cuối cùng. Ví dụ, tin nhắn có thể cần được xác thực hoặc biến đổi vì người nhận mong đợi một định dạng tin nhắn khác so với người gửi. Kiến trúc ống và bộ lọc mô tả cách mà nhiều bước xử lý có thể được liên kết với nhau bằng cách sử dụng các kênh.
Chuyển hướng Trong một doanh nghiệp lớn với nhiều ứng dụng và kênh để kết nối chúng, một thông điệp có thể phải qua một số kênh để đến đích cuối cùng. Đường đi mà một thông điệp phải theo có thể phức tạp đến nỗi người gửi ban đầu không biết kênh nào sẽ đưa thông điệp đến người nhận cuối cùng. Thay vào đó, người gửi ban đầu gửi thông điệp đến một Bộ định tuyến Thông điệp, một thành phần ứng dụng thay thế cho bộ lọc trong kiến trúc Ống và Bộ lọc. Bộ định tuyến sau đó xác định cách điều hướng cấu trúc kênh và hướng thông điệp đến người nhận cuối cùng, hoặc ít nhất là đến bộ định tuyến tiếp theo.
Biến đổi Các ứng dụng khác nhau có thể không đồng ý về định dạng cho cùng một dữ liệu khái niệm; người gửi định dạng thông điệp theo một cách, nhưng người nhận mong đợi nó được định dạng theo cách khác. Để hòa giải điều này, thông điệp phải đi qua một bộ lọc trung gian, một Bộ dịch Thông điệp, mà chuyển đổi thông điệp từ định dạng này sang định dạng khác.
Điểm cuối Hầu hết các ứng dụng không có khả năng tích hợp sẵn để kết nối với hệ thống nhắn tin. Thay vào đó, chúng phải có một lớp mã nhận biết cả cách thức hoạt động của ứng dụng lẫn cách thức hoạt động của hệ thống nhắn tin, tạo cầu nối giữa hai bên để chúng hoạt động cùng nhau. Mã cầu nối này là một tập hợp các Điểm cuối Tin nhắn phối hợp, cho phép ứng dụng gửi và nhận tin nhắn.
Các mẫu trong chương này cung cấp cho bạn từ vựng cơ bản và hiểu biết về cách đạt được tích hợp doanh nghiệp thông qua Messaging. Mỗi chương tiếp theo xây dựng dựa trên một trong những mẫu cơ bản trong chương này và giải quyết chủ đề cụ thể đó chi tiết hơn.
Mối quan hệ giữa Mô hình Gốc và Chương mục

Bạn có thể đọc chương này một mạch để có cái nhìn tổng quan về những chủ đề chính trong Messaging. Để biết thêm chi tiết về bất kỳ chủ đề nào trong số này, hãy chuyển tới chương liên quan đến mẫu cụ thể đó.
Một doanh nghiệp có hai ứng dụng riêng biệt cần giao tiếp bằng cách sử dụng Tin nhắn.
| "Làm thế nào một ứng dụng có thể giao tiếp với ứng dụng khác bằng cách sử dụng tin nhắn?" |
Khi một nhóm các ứng dụng có hệ thống nhắn tin sẵn có, thật hấp dẫn khi nghĩ rằng bất kỳ ứng dụng nào cũng có thể giao tiếp với bất kỳ ứng dụng nào khác bất cứ lúc nào bạn muốn. Tuy nhiên, hệ thống nhắn tin không tự động kết nối tất cả các ứng dụng lại với nhau.
Các Ứng Dụng Kết Nối Một Cách Kỳ Diệu

Tương tự, không phải là một ứng dụng chỉ ngẫu nhiên đưa ra thông tin vào hệ thống nhắn tin trong khi các ứng dụng khác chỉ ngẫu nhiên lấy bất kỳ thông tin nào mà chúng tình cờ gặp phải. (Ngay cả khi điều này hoạt động, nó cũng sẽ không hiệu quả lắm.) Thay vào đó, ứng dụng gửi thông tin biết loại thông tin nào nó đang gửi, và các ứng dụng muốn nhận thông tin không chỉ tìm kiếm bất kỳ thông tin nào mà là những loại thông tin cụ thể mà họ có thể sử dụng. Vì vậy, hệ thống nhắn tin không phải là một cái thùng lớn mà các ứng dụng đổ thông tin vào và lấy thông tin ra. Nó là một tập hợp các kết nối cho phép các ứng dụng giao tiếp bằng cách truyền tải thông tin theo những cách xác định trước và có thể dự đoán được.
| Kết nối các ứng dụng bằng một Kênh Tin nhắn, nơi một ứng dụng ghi thông tin vào kênh và ứng dụng kia đọc thông tin đó từ kênh.
|
Khi một ứng dụng có thông tin cần truyền đạt, nó không chỉ ném thông tin vào hệ thống nhắn tin mà còn thêm thông tin vào một Kênh Tin Nhắn cụ thể. Một ứng dụng nhận thông tin không chỉ lấy ngẫu nhiên từ hệ thống nhắn tin; nó truy xuất thông tin từ một Kênh Tin Nhắn cụ thể.
Hệ thống gửi thông tin không nhất thiết phải biết ứng dụng cụ thể nào sẽ nhận thông tin đó, nhưng có thể đảm bảo rằng ứng dụng nhận thông tin có quan tâm đến thông tin đó. Điều này là do hệ thống nhắn tin có các Kênh Tin nhắn khác nhau cho các loại thông tin khác nhau mà các ứng dụng muốn truyền đạt. Khi một ứng dụng gửi thông tin, nó không ngẫu nhiên thêm thông tin vào bất kỳ kênh nào có sẵn; thay vào đó, nó thêm thông tin vào một kênh có mục đích cụ thể để truyền đạt loại thông tin đó. Tương tự, một ứng dụng muốn nhận thông tin cụ thể không lấy thông tin từ một kênh ngẫu nhiên; nó chọn kênh nào để nhận thông tin dựa trên loại thông tin mà nó muốn.
Các kênh là địa chỉ logic trong hệ thống nhắn tin. Cách chúng được triển khai thực tế phụ thuộc vào sản phẩm hệ thống nhắn tin và cách cài đặt của nó. Có thể mỗi Điểm Kết Nối Tin Nhắn có một kết nối trực tiếp đến mọi điểm kết nối khác, hoặc có thể tất cả được kết nối qua một trung tâm trung gian. Có thể một số kênh logic riêng biệt được cấu hình như một kênh vật lý mà vẫn giữ được các thông điệp dành cho từng đích đến. Tập hợp các kênh logic đã được định nghĩa ẩn giấu chi tiết cấu hình này khỏi các ứng dụng.
Một hệ thống nhắn tin không tự động được cấu hình sẵn với tất cả các kênh nhắn tin mà các ứng dụng cần để giao tiếp. Thay vào đó, các nhà phát triển thiết kế ứng dụng và giao tiếp giữa chúng phải quyết định những kênh nào họ cần cho giao tiếp. Sau đó, người quản trị hệ thống cài đặt phần mềm hệ thống nhắn tin cũng phải cấu hình nó để thiết lập các kênh mà các ứng dụng mong đợi. Mặc dù một số triển khai hệ thống nhắn tin hỗ trợ tạo mới các kênh trong khi các ứng dụng đang chạy, điều này không rất hữu ích vì các ứng dụng khác bên cạnh ứng dụng tạo kênh phải biết về kênh mới để họ cũng có thể bắt đầu sử dụng. Do đó, số lượng và mục đích của các kênh có sẵn thường cố định tại thời điểm triển khai. (Có những ngoại lệ cho quy tắc này; xem phần giới thiệu của Chương 4, "Các Kênh Nhắn Tin.")
A Little Bit of Messaging VocabularyVậy chúng ta gọi các ứng dụng giao tiếp qua Kênh Tin nhắn là gì? Có một số thuật ngữ ngoài kia chủ yếu tương đương với nhau. Thuật ngữ chung chung nhất có lẽ là người gửi và người nhận; một ứng dụng gửi một tin nhắn tới Kênh Tin nhắn để được nhận bởi một ứng dụng khác. Các thuật ngữ phổ biến khác là nhà sản xuất và người tiêu thụ. Bạn cũng sẽ thấy nhà phát hành và người đăng ký, nhưng chúng thường hướng nhiều hơn đến các Kênh Xuất Bản-Đăng Ký và thường được sử dụng theo hình thức tổng quát. Đôi khi chúng ta nói rằng một ứng dụng lắng nghe trên một kênh mà một ứng dụng khác nói chuyện. Trong thế giới dịch vụ Web, chúng ta thường nói về người yêu cầu và nhà cung cấp. Những thuật ngữ này thường ngụ ý rằng người yêu cầu gửi một tin nhắn tới nhà cung cấp và nhận lại một phản hồi. Trong những ngày xưa, chúng ta gọi chúng là máy khách và máy chủ (các thuật ngữ này là tương đương, nhưng nói "máy khách" và "máy chủ" thì không được hay cho lắm). Bây giờ nó trở nên hơi rắc rối. Khi xử lý các dịch vụ Web, ứng dụng gửi tin nhắn đến nhà cung cấp dịch vụ thường được gọi là bên tiêu thụ dịch vụ, mặc dù nó gửi tin nhắn yêu cầu. Chúng ta có thể nghĩ rằng bên tiêu thụ gửi một tin nhắn đến nhà cung cấp và sau đó tiêu thụ phản hồi. May mắn thay, việc sử dụng thuật ngữ với ý nghĩa này chỉ giới hạn trong các kịch bản Gọi Thủ tục Từ xa. Một ứng dụng gửi hoặc nhận tin nhắn có thể được gọi là khách hàng của hệ thống nhắn tin; một thuật ngữ cụ thể hơn là điểm cuối hoặc điểm cuối tin nhắn. |
Một điều thường khiến các nhà phát triển nhầm lẫn khi họ lần đầu bắt đầu sử dụng hệ thống nhắn tin là cần phải làm gì chính xác để tạo ra một kênh. Một nhà phát triển có thể viết mã Java gọi phương thức createQueue được định nghĩa trong API JMS hoặc mã .NET bao gồm câu lệnh new MessageQueue, nhưng không có mã nào thực sự cấp phát một tài nguyên hàng đợi mới trong hệ thống nhắn tin. Thay vào đó, những đoạn mã này chỉ đơn giản là khởi tạo một đối tượng chạy tại thời gian cung cấp quyền truy cập vào một tài nguyên đã được tạo ra trong hệ thống nhắn tin bằng cách sử dụng các công cụ quản trị của nó.
Có một vấn đề khác bạn nên lưu ý khi thiết kế các kênh cho một hệ thống nhắn tin: Các kênh rất rẻ, nhưng không miễn phí. Các ứng dụng cần nhiều kênh để truyền tải các loại thông tin khác nhau và truyền tải cùng một thông tin đến nhiều ứng dụng khác. Mỗi kênh cần bộ nhớ để đại diện cho các tin nhắn; các kênh bền vững cũng cần không gian lưu trữ. Ngay cả khi một hệ thống doanh nghiệp có bộ nhớ và không gian lưu trữ không giới hạn, bất kỳ triển khai hệ thống nhắn tin nào cũng thường áp đặt một số giới hạn cứng hoặc thực tiễn về số lượng kênh mà nó có thể phục vụ một cách nhất quán. Vì vậy, hãy lên kế hoạch tạo ra các kênh mới khi ứng dụng của bạn cần, nhưng nếu nó cần hàng ngàn kênh hoặc cần mở rộng theo cách có thể yêu cầu hàng ngàn kênh, bạn sẽ cần chọn một triển khai hệ thống nhắn tin có khả năng mở rộng cao và kiểm tra khả năng mở rộng đó để đảm bảo nó đáp ứng được nhu cầu của bạn.
Channel NamesNếu các kênh là địa chỉ logic, thì các địa chỉ này trông như thế nào? Giống như trong nhiều trường hợp, câu trả lời chi tiết phụ thuộc vào việc triển khai của hệ thống nhắn tin. Tuy nhiên, trong hầu hết các trường hợp, các kênh được tham chiếu bởi một tên alphanumeric, chẳng hạn như MyChannel. Nhiều hệ thống nhắn tin hỗ trợ một sơ đồ đặt tên kênh phân cấp, cho phép bạn tổ chức các kênh theo cách tương tự như một hệ thống tệp với các thư mục và thư mục con. Ví dụ, MyCorp/Prod/OrderProcessing/NewOrders sẽ chỉ ra một kênh được sử dụng trong một ứng dụng sản xuất tại MyCorp và chứa các đơn hàng mới. |
Có hai loại kênh tin nhắn khác nhau: Kênh Điểm-Điểm và Kênh Xuất-Bản-Đăng-Ký. Việc trộn các loại dữ liệu khác nhau trên cùng một kênh có thể gây ra nhiều nhầm lẫn; để tránh điều này, hãy sử dụng các Kênh Dữ Liệu riêng biệt. Người Tiêu Thụ Chọn Lọc làm cho một kênh vật lý hoạt động logic như nhiều kênh. Các ứng dụng sử dụng tin nhắn thường được hưởng lợi từ một kênh đặc biệt cho các tin nhắn không hợp lệ, Kênh Tin Nhắn Không Hợp Lệ. Các ứng dụng muốn sử dụng Tin Nhắn nhưng không có quyền truy cập vào một khách hàng tin nhắn vẫn có thể kết nối với hệ thống tin nhắn bằng cách sử dụng Bộ Chuyển Đổi Kênh. Một tập hợp kênh được thiết kế tốt hình thành một Bus Tin Nhắn hoạt động như một API tin nhắn cho cả một nhóm ứng dụng.
| Ví dụ: Giao dịch Chứng khoán Khi một ứng dụng giao dịch chứng khoán thực hiện một giao dịch, nó đặt yêu cầu lên một Kênh Tin nhắn cho các yêu cầu giao dịch. Một ứng dụng khác xử lý các yêu cầu giao dịch sẽ tìm kiếm những yêu cầu mà nó có thể xử lý trên cùng một kênh tin nhắn đó. Nếu ứng dụng yêu cầu cần phải yêu cầu một báo giá chứng khoán, nó có thể sẽ sử dụng một Kênh Tin nhắn khác, một kênh được thiết kế cho báo giá chứng khoán, để các yêu cầu báo giá được tách biệt khỏi các yêu cầu giao dịch. |
| Ví dụ: Triển khai tham khảo J2EE JMS Hãy cùng xem cách tạo một Kênh Tin nhắn trong JMS. Bộ phát triển J2EE đi kèm với một triển khai tham khảo của các dịch vụ J2EE, bao gồm cả JMS. Máy chủ tham chiếu có thể được khởi động bằng lệnh j2ee. Các kênh tin nhắn phải được cấu hình bằng công cụ j2eeadmin. Công cụ này có thể cấu hình cả hàng đợi và chủ đề. j2eeadmin -addJmsDestination jms/mytopic topic j2eeadmin -addJmsDestination jms/myqueue queue Khi các kênh đã được quản lý (tạo ra), chúng có thể được truy cập bởi mã khách hàng JMS. Context jndiContext = new InitialContext(); Queue myQueue = (Queue) jndiContext.lookup("jms/myqueue"); Topic myTopic = (Topic) jndiContext.lookup("jms/mytopic"); Tra cứu JNDI không tạo hàng đợi (hoặc chủ đề); nó đã được tạo ra bởi lệnh j2eeadmin. Tra cứu JNDI chỉ đơn giản tạo một thực thể Queue trong Java mô phỏng và cung cấp quyền truy cập vào cấu trúc hàng đợi trong hệ thống nhắn tin. |
| Ví dụ: IBM WebSphere MQ Nếu triển khai hệ thống nhắn tin của bạn là IBM's WebSphere MQ cho Java, sử dụng JMS, bạn sẽ sử dụng công cụ quản lý JMS của WebSphere MQ để tạo các đích đến. Điều này sẽ tạo ra một hàng đợi tên là myQueue. DEFINE Q(myQueue) Khi hàng đợi đó tồn tại trong WebSphere MQ, một ứng dụng có thể truy cập vào hàng đợi. WebSphere MQ, mà không có đầy đủ WebSphere Application Server, không bao gồm một triển khai JNDI, vì vậy chúng ta không thể sử dụng JNDI để tra cứu hàng đợi như chúng ta đã làm trong ví dụ J2EE. Thay vào đó, chúng ta phải truy cập hàng đợi thông qua một phiên JMS, như sau. Session session = // create the session Queue queue = session.createQueue("myQueue"); |
| Ví dụ: Microsoft MSMQ MSMQ cung cấp một số cách khác nhau để tạo một kênh tin nhắn, gọi là hàng đợi. Bạn có thể tạo một hàng đợi bằng cách sử dụng Trình khám phá hàng đợi của Microsoft hoặc bảng điều khiển Quản lý Máy tính (xem hình). Từ đây, bạn có thể thiết lập các thuộc tính hàng đợi hoặc xóa hàng đợi.
Ngoài ra, bạn có thể tạo hàng đợi bằng cách sử dụng mã. using System.Messaging; ... MessageQueue.Create("MyQueue"); Khi hàng đợi được tạo, một ứng dụng có thể truy cập nó bằng cách tạo một thể hiện MessageQueue, truyền tên của hàng đợi. MessageQueue mq = new MessageQueue("MyQueue"); |
Một doanh nghiệp có hai ứng dụng riêng biệt đang giao tiếp qua Tin nhắn, sử dụng một Kênh Tin nhắn kết nối chúng.
| Hai ứng dụng kết nối qua Kênh Tin nhắn có thể trao đổi thông tin như thế nào? |
Một Kênh Tin nhắn thường được nghĩ đến như một ống dẫn, một con đường từ ứng dụng này sang ứng dụng khác. Do đó, có thể hợp lý rằng dữ liệu có thể được đổ vào một đầu, như nước, và sẽ chảy ra ở đầu kia. Nhưng hầu hết dữ liệu ứng dụng không phải là một dòng liên tục; nó bao gồm các đơn vị, chẳng hạn như bản ghi, đối tượng, hàng trong cơ sở dữ liệu, và những thứ tương tự. Vì vậy, một kênh phải truyền tải các đơn vị dữ liệu.
"Truyền" dữ liệu có nghĩa là gì? Trong một cuộc gọi hàm, người gọi có thể truyền một tham số bằng cách tham chiếu bằng cách truyền một con trỏ đến địa chỉ của dữ liệu trong bộ nhớ; điều này hoạt động vì cả người gọi và hàm đều chia sẻ cùng một vùng nhớ. Tương tự, hai luồng trong cùng một tiến trình có thể truyền một bản ghi hoặc đối tượng bằng cách truyền một con trỏ, vì cả hai đều chia sẻ cùng một không gian bộ nhớ.
Hai quy trình riêng biệt truyền một mảnh dữ liệu sẽ phải thực hiện nhiều công việc hơn. Vì mỗi quy trình đều có không gian bộ nhớ riêng của nó, nên chúng cần phải sao chép dữ liệu từ không gian bộ nhớ này sang không gian bộ nhớ khác. Dữ liệu thường được truyền dưới dạng luồng byte, hình thức cơ bản nhất của dữ liệu. Điều này có nghĩa là quy trình đầu tiên phải biên dịch dữ liệu thành dạng byte, và sau đó sao chép nó từ quy trình đầu tiên sang quy trình thứ hai; quy trình thứ hai sẽ giải biên dữ liệu trở lại hình thức ban đầu của nó, sao cho quy trình thứ hai sau đó có một bản sao của dữ liệu gốc trong quy trình đầu tiên. Việc biên dịch là cách mà Cuộc gọi Thủ tục Từ xa (RPC) gửi các đối số đến quy trình từ xa và cách mà quy trình trả về kết quả.
Vì vậy, việc truyền tin nhắn chuyển giao các đơn vị dữ liệu rời rạc, và điều này được thực hiện bằng cách biên tập dữ liệu từ người gửi và giải biên dữ liệu ở người nhận để người nhận có bản sao cục bộ của riêng mình. Một cách đơn giản để bọc một đơn vị dữ liệu sao cho phù hợp để truyền dữ liệu qua một kênh nhắn tin sẽ rất hữu ích.
| Đóng gói thông tin vào một Tin nhắn, một bản ghi dữ liệu mà hệ thống nhắn tin có thể truyền qua một Kênh Tin nhắn.
|
Do đó, bất kỳ dữ liệu nào cần được truyền qua hệ thống nhắn tin phải được chuyển đổi thành một hoặc nhiều tin nhắn có thể được gửi qua các kênh nhắn tin.
Một thông điệp bao gồm hai phần cơ bản.
Tiêu đề Thông tin được hệ thống nhắn tin sử dụng để mô tả dữ liệu đang được truyền tải, nguồn gốc của nó, điểm đến của nó, và các thông tin khác.
Nội dung Dữ liệu đang được truyền đi, thường bị hệ thống nhắn tin bỏ qua và đơn giản được truyền đi như vậy.
Khái niệm này không chỉ độc đáo trong lĩnh vực nhắn tin. Cả dịch vụ bưu chính và email đều gửi dữ liệu dưới dạng các tin nhắn thư riêng biệt. Mạng Ethernet truyền dữ liệu dưới dạng các gói, giống như phần IP của TCP/IP chẳng hạn như Internet. Phương tiện truyền tải trên Internet thực sự là một chuỗi các gói.
Đối với hệ thống nhắn tin, tất cả các tin nhắn đều giống nhau: một bộ dữ liệu được truyền tải như được mô tả bởi tiêu đề. Tuy nhiên, đối với lập trình viên ứng dụng, có các loại tin nhắn khác nhau, tức là các phong cách ứng dụng khác nhau trong việc sử dụng. Sử dụng Tin Nhắn Lệnh để gọi một quy trình trong một ứng dụng khác. Sử dụng Tin Nhắn Tài Liệu để gửi một tập hợp dữ liệu đến một ứng dụng khác. Sử dụng Tin Nhắn Sự Kiện để thông báo cho một ứng dụng khác về sự thay đổi trong ứng dụng này. Nếu ứng dụng khác cần gửi lại phản hồi, hãy sử dụng Yêu Cầu-Phản Hồi.
Nếu một ứng dụng muốn gửi nhiều thông tin hơn một tin nhắn có thể chứa, hãy chia dữ liệu thành các phần nhỏ hơn và gửi các phần đó như một Chuỗi Tin Nhắn. Nếu dữ liệu chỉ hữu ích trong một khoảng thời gian hạn chế, hãy chỉ định thời gian hết hạn là một Thời Hạn Tin Nhắn. Vì tất cả các người gửi và người nhận khác nhau của các tin nhắn phải đồng ý về định dạng của dữ liệu trong các tin nhắn, hãy chỉ định định dạng đó là một Mô Hình Dữ Liệu Canonical.
| Ví dụ: Tin nhắn JMS Trong JMS, một tin nhắn được đại diện bởi loại Tin nhắn, loại này có nhiều kiểu con. Trong mỗi kiểu con, cấu trúc tiêu đề là giống nhau; định dạng nội dung thay đổi theo loại.
|
| Ví dụ: .NET Thông điệp Trong .NET, lớp Message triển khai loại tin nhắn. Nó có một thuộc tính, Body, chứa nội dung của tin nhắn dưới dạng Object; BodyStream lưu trữ nội dung dưới dạng Stream. Một thuộc tính khác, BodyType, xác định loại dữ liệu mà nội dung chứa, chẳng hạn như chuỗi, ngày, tiền tệ, số hoặc bất kỳ đối tượng nào khác. |
| Ví dụ: Thông điệp SOAP Trong giao thức SOAP [SOAP 1.1], một thông điệp SOAP là một ví dụ về Thông điệp. Một thông điệp SOAP là một tài liệu XML được cấu trúc như một bao bì (một phần tử gốc SOAP-ENV:Envelope) chứa một tiêu đề tùy chọn (một phần tử SOAP-ENV:Header) và một thân tài liệu bắt buộc (một phần tử SOAP-ENV:Body). Tài liệu XML này là một bản ghi dữ liệu nguyên tử có thể được truyền tải (thông thường giao thức truyền tải là HTTP) vì vậy nó được gọi là một thông điệp. Dưới đây là một ví dụ về một thông điệp SOAP từ đặc tả SOAP cho thấy một bìa chứa tiêu đề và một nội dung. [View full width] <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap SOAP cũng cho thấy tính chất đệ quy của thông điệp, vì một thông điệp SOAP có thể được truyền qua một hệ thống nhắn tin, điều này có nghĩa là một đối tượng thông điệp của hệ thống nhắn tin (ví dụ: một đối tượng loại javax.jms.Message trong JMS hoặc System.Messaging.Message trong .NET) chứa thông điệp SOAP (tài liệu XML SOAP-ENV:Envelope). Trong kịch bản này, giao thức truyền tải không phải là HTTP mà là giao thức nội bộ của hệ thống nhắn tin (giao thức này có thể sử dụng HTTP hoặc một giao thức mạng khác để truyền dữ liệu, nhưng hệ thống nhắn tin đảm bảo việc truyền tải là đáng tin cậy). Để biết thêm thông tin về việc truyền tải một thông điệp qua một hệ thống nhắn tin khác, xem Envelop Wrapper. |
Trong nhiều kịch bản tích hợp doanh nghiệp, một sự kiện đơn lẻ kích hoạt một chuỗi các bước xử lý, mỗi bước thực hiện một chức năng cụ thể. Ví dụ, hãy giả sử một đơn hàng mới đến doanh nghiệp của chúng ta dưới dạng một tin nhắn. Một yêu cầu có thể là tin nhắn này được mã hóa để ngăn chặn kẻ xâm nhập theo dõi đơn hàng của khách hàng. Yêu cầu thứ hai là tin nhắn phải chứa thông tin xác thực dưới dạng chứng chỉ số để đảm bảo rằng các đơn hàng chỉ được đặt bởi những khách hàng đáng tin cậy. Ngoài ra, các tin nhắn trùng lặp có thể được gửi từ các bên bên ngoài (hãy nhớ tất cả các cảnh báo trên các trang mua sắm phổ biến yêu cầu nhấn nút Đặt hàng ngay chỉ một lần?). Để tránh các lô hàng trùng lặp và khiến khách hàng không hài lòng, chúng ta cần loại bỏ các tin nhắn trùng lặp trước khi các bước xử lý đơn hàng tiếp theo được khởi động. Để đáp ứng những yêu cầu này, chúng ta cần chuyển đổi một loạt các tin nhắn có thể bị trùng lặp, được mã hóa và chứa dữ liệu xác thực thêm thành một loạt các tin nhắn đơn hàng duy nhất, đơn giản và không có các trường dữ liệu dư thừa.
| Làm thế nào chúng ta có thể thực hiện xử lý phức tạp trên một thông điệp trong khi vẫn duy trì tính độc lập và linh hoạt? |
Một giải pháp khả thi là viết một "module nhắn tin tin nhắn đến" toàn diện thực hiện tất cả các chức năng cần thiết. Tuy nhiên, cách tiếp cận như vậy sẽ không linh hoạt và khó kiểm tra. Thế nếu chúng ta cần thêm một bước hoặc bỏ một bước? Ví dụ, sẽ ra sao nếu đơn hàng có thể được đặt bởi những khách hàng lớn trên một mạng riêng và không yêu cầu mã hóa?
Việc triển khai tất cả các chức năng bên trong một thành phần duy nhất cũng giảm cơ hội tái sử dụng. Tạo ra các thành phần nhỏ hơn, được định nghĩa rõ ràng cho phép chúng ta tái sử dụng chúng trong các quy trình khác. Ví dụ, các thông điệp trạng thái đơn hàng có thể được mã hóa nhưng không cần phải loại bỏ bản sao vì các yêu cầu trạng thái trùng lặp thường không gây hại. Tách chức năng giải mã thành một mô-đun riêng cho phép chúng ta tái sử dụng chức năng này cho các thông điệp khác.
Các giải pháp tích hợp thường kết nối một tập hợp các hệ thống không đồng nhất. Kết quả là, các bước xử lý khác nhau có thể cần phải thực hiện trên các máy vật lý khác nhau, chẳng hạn như khi các bước xử lý riêng lẻ chỉ có thể thực hiện trên các hệ thống cụ thể. Ví dụ, có thể rằng khóa bí mật cần thiết để giải mã các thông điệp đến chỉ có sẵn trên một máy đã chỉ định và không thể truy cập từ bất kỳ máy nào khác vì lý do an ninh. Điều này có nghĩa là thành phần giải mã phải thực hiện trên máy đã chỉ định này, trong khi các bước khác có thể thực hiện trên các máy khác. Tương tự, các bước xử lý khác nhau có thể được triển khai bằng cách sử dụng các ngôn ngữ lập trình hoặc công nghệ khác nhau mà ngăn cản chúng chạy trong cùng một tiến trình hoặc thậm chí trên cùng một máy tính.
Việc triển khai mỗi chức năng trong một thành phần riêng biệt vẫn có thể tạo ra sự phụ thuộc giữa các thành phần. Ví dụ, nếu thành phần giải mã gọi thành phần xác thực với kết quả của quá trình giải mã, chúng ta không thể sử dụng chức năng giải mã mà không có chức năng xác thực. Chúng ta có thể giải quyết những sự phụ thuộc này nếu chúng ta có thể "kết hợp" các thành phần hiện có thành một chuỗi các bước xử lý theo cách mà mỗi thành phần độc lập với các thành phần khác trong hệ thống. Điều này sẽ ngụ ý rằng các thành phần cần phải cung cấp các giao diện bên ngoài chung để chúng có thể hoán đổi cho nhau.
Nếu chúng ta sử dụng việc truyền tin nhắn không đồng bộ, chúng ta nên tận dụng những khía cạnh không đồng bộ của việc gửi tin nhắn từ một thành phần này sang thành phần khác. Ví dụ, một thành phần có thể gửi một tin nhắn đến một thành phần khác để được xử lý thêm mà không cần chờ đợi kết quả. Bằng cách sử dụng kỹ thuật này, chúng ta có thể xử lý nhiều tin nhắn song song, mỗi tin nhắn trong từng thành phần.
| Sử dụng kiểu kiến trúc ống và bộ lọc để chia một nhiệm vụ xử lý lớn thành một chuỗi các bước xử lý nhỏ hơn, độc lập (bộ lọc) được kết nối bởi các kênh (ống).
|
Mỗi bộ lọc cung cấp một giao diện rất đơn giản: Nó nhận tin nhắn qua ống dẫn vào, xử lý tin nhắn và công bố kết quả lên ống dẫn ra. Ống dẫn kết nối một bộ lọc với bộ lọc tiếp theo, gửi các tin nhắn đầu ra từ bộ lọc này sang bộ lọc khác. Bởi vì tất cả các thành phần đều sử dụng cùng một giao diện bên ngoài, chúng có thể được cấu thành thành những giải pháp khác nhau bằng cách kết nối các thành phần với các ống dẫn khác nhau. Chúng ta có thể thêm bộ lọc mới, bỏ qua những bộ lọc hiện có, hoặc sắp xếp lại chúng thành một trình tự mới mà không cần phải thay đổi các bộ lọc đó. Kết nối giữa bộ lọc và ống dẫn đôi khi được gọi là cổng. Ở dạng cơ bản, mỗi thành phần bộ lọc có một cổng đầu vào và một cổng đầu ra.
Khi áp dụng cho bài toán ví dụ của chúng ta, kiến trúc Pipes and Filters dẫn đến ba bộ lọc được kết nối bởi hai ống (xem hình). Chúng ta cần một ống bổ sung để gửi tin nhắn đến thành phần giải mã và một ống để gửi các tin nhắn đơn đặt hàng rõ ràng từ bộ loại bỏ trùng lắp đến hệ thống quản lý đơn đặt hàng. Điều này tổng cộng tạo ra bốn ống.
"Pipe và bộ lọc mô tả một kiểu kiến trúc cơ bản cho các hệ thống nhắn tin: Các bước xử lý riêng lẻ (bộ lọc) được kết nối với nhau thông qua các kênh nhắn tin (ống dẫn). Nhiều mẫu trong phần này và các phần sau, chẳng hạn như các mẫu định tuyến và biến đổi, dựa trên kiểu kiến trúc Pipe và bộ lọc này. Điều này cho phép bạn dễ dàng kết hợp các mẫu riêng lẻ thành các giải pháp lớn hơn."
Kiểu Ống và Bộ Lọc sử dụng các ống trừu tượng để tách rời các thành phần khỏi nhau. Ống cho phép một thành phần gửi một thông điệp vào ống để sau này có thể được tiêu thụ bởi một quy trình khác mà thành phần đó không biết đến. Triển khai rõ ràng cho một ống như vậy là Kênh Tin nhắn. Thông thường, Kênh Tin nhắn cung cấp tính độc lập về ngôn ngữ, nền tảng và vị trí giữa các bộ lọc. Điều này cho phép chúng ta có tính linh hoạt để di chuyển một bước xử lý sang một máy khác vì lý do phụ thuộc, bảo trì hoặc hiệu suất. Tuy nhiên, một Kênh Tin nhắn do một hạ tầng nhắn tin cung cấp có thể nặng nề nếu tất cả các thành phần thực sự có thể nằm trên cùng một máy. Sử dụng một hàng đợi trong bộ nhớ đơn giản để triển khai các ống sẽ hiệu quả hơn nhiều. Do đó, hữu ích khi thiết kế các thành phần sao cho chúng giao tiếp với một giao diện ống trừu tượng. Việc triển khai giao diện đó sau đó có thể được thay thế để sử dụng Kênh Tin nhắn hoặc một triển khai thay thế như một hàng đợi trong bộ nhớ. Cổng Nhắn tin mô tả cách thiết kế các thành phần cho sự linh hoạt này.
Một trong những mặt hạn chế tiềm ẩn của kiến trúc Pipes and Filters là số lượng kênh yêu cầu lớn hơn. Đầu tiên, các kênh có thể không phải là tài nguyên không giới hạn, vì các kênh cung cấp bộ đệm và các chức năng khác tiêu tốn bộ nhớ và chu kỳ CPU. Ngoài ra, việc phát hành một thông điệp đến một kênh liên quan đến một lượng phí tổn nhất định vì dữ liệu phải được chuyển đổi từ định dạng nội bộ của ứng dụng sang định dạng của hạ tầng nhắn tin. Ở đầu nhận, quy trình này phải được đảo ngược. Nếu chúng ta đang sử dụng một chuỗi dài các bộ lọc, chúng ta đang trả giá cho lợi ích về tính linh hoạt với hiệu suất có thể thấp hơn do việc chuyển đổi dữ liệu thông điệp lặp đi lặp lại.
Hình thức thuần túy của Ống và Bộ lọc yêu cầu mỗi bộ lọc chỉ có một cổng đầu vào và một cổng đầu ra. Khi xử lý Tin nhắn, chúng ta có thể hơi nới lỏng thuộc tính này. Một thành phần có thể tiêu thụ tin nhắn từ nhiều kênh và cũng xuất tin nhắn đến nhiều kênh (ví dụ, một Bộ định tuyến Tin nhắn). Tương tự, nhiều thành phần bộ lọc có thể tiêu thụ tin nhắn từ một kênh Tin nhắn duy nhất. Một Kênh Điểm-Đến-Điểm đảm bảo rằng chỉ có một thành phần bộ lọc tiêu thụ mỗi tin nhắn.
Sử dụng Ống và Bộ lọc cũng cải thiện khả năng kiểm thử, một lợi ích thường bị bỏ qua. Chúng ta có thể kiểm thử từng bước xử lý riêng lẻ bằng cách truyền một Tin nhắn Kiểm thử vào thành phần và so sánh tin nhắn kết quả với kết quả mong đợi. Việc kiểm thử và gỡ lỗi từng chức năng cốt lõi một cách độc lập là hiệu quả hơn vì chúng ta có thể điều chỉnh cơ chế kiểm thử cho chức năng cụ thể. Ví dụ, để kiểm thử chức năng mã hóa/giải mã, chúng ta có thể truyền vào một số lượng lớn tin nhắn chứa dữ liệu ngẫu nhiên. Sau khi mã hóa và giải mã từng tin nhắn, chúng ta so sánh với bản gốc. Ngược lại, để kiểm thử xác thực, chúng ta cần cung cấp các tin nhắn với mã xác thực cụ thể tương ứng với người dùng đã biết trong hệ thống.
Kết nối các thành phần với các Kênh Tin nhắn không đồng bộ cho phép mỗi đơn vị trong chuỗi hoạt động trong luồng riêng hoặc quy trình riêng của nó. Khi một đơn vị đã hoàn thành việc xử lý một tin nhắn, nó có thể gửi tin nhắn này đến kênh đầu ra và ngay lập tức bắt đầu xử lý một tin nhắn khác. Nó không cần phải chờ đợi các thành phần tiếp theo đọc và xử lý tin nhắn. Điều này cho phép nhiều tin nhắn được xử lý đồng thời khi chúng đi qua các giai đoạn riêng lẻ. Ví dụ, sau khi tin nhắn đầu tiên đã được giải mã, nó có thể được chuyển đến thành phần xác thực. Đồng thời, tin nhắn tiếp theo có thể đã được giải mã (xem hình). Chúng tôi gọi cấu hình như vậy là một ống xử lý vì các tin nhắn chảy qua các bộ lọc giống như lỏng chảy qua một ống. Khi so sánh với quy trình xử lý tuần tự nghiêm ngặt, một ống xử lý có thể tăng đáng kể thông lượng của hệ thống.
Xử lý đường ống với ống và bộ lọc

Tuy nhiên, năng suất tổng thể của hệ thống bị giới hạn bởi quá trình chậm nhất trong chuỗi. Chúng ta có thể triển khai nhiều phiên bản song song của quá trình đó để cải thiện năng suất. Trong kịch bản này, một Kênh Điểm-đến-Điểm với các Người tiêu dùng Cạnh tranh là cần thiết để đảm bảo rằng mỗi tin nhắn trên kênh được tiêu thụ bởi chính xác một trong N bộ xử lý có sẵn. Điều này cho phép chúng ta tăng tốc quá trình tốn nhiều thời gian nhất và cải thiện năng suất tổng thể. Tuy nhiên, chúng ta cần nhận thức rằng cấu hình này có thể khiến các tin nhắn được xử lý không theo thứ tự. Nếu thứ tự của các tin nhắn là quan trọng, chúng ta chỉ có thể chạy một phiên bản của mỗi thành phần hoặc phải sử dụng một Bộ tái sắp xếp.
Tăng cường thông lượng với xử lý song song

Ví dụ, nếu chúng ta giả định rằng việc giải mã một tin nhắn chậm hơn nhiều so với việc xác thực nó, chúng ta có thể sử dụng cấu hình được hiển thị trong hình, chạy ba phiên bản song song của thành phần giải mã. Việc phân tán các bộ lọc hoạt động tốt nhất nếu mỗi bộ lọc không giữ trạng thái, tức là nó trở lại trạng thái trước đó sau khi một tin nhắn đã được xử lý. Điều này có nghĩa là chúng ta không thể dễ dàng chạy nhiều thành phần loại bỏ trùng lặp song song vì thành phần này duy trì một lịch sử của tất cả các tin nhắn mà nó đã nhận và do đó không phải là không giữ trạng thái.
Kiến trúc Ống và Bộ lọc không phải là một khái niệm mới. Sự tinh tế đơn giản của kiến trúc này kết hợp với tính linh hoạt và khả năng xử lý cao giúp dễ dàng hiểu được sự phổ biến của kiến trúc Ống và Bộ lọc. Ngữ nghĩa đơn giản cũng cho phép sử dụng các phương pháp chính thức để mô tả kiến trúc.
[Kahn] đã mô tả Mạng Quy trình Kahn vào năm 1974 như một tập hợp các quy trình song song được kết nối bởi các kênh FIFO (First-In, First-Out) không giới hạn. [Garlan] có một chương tốt về các kiểu kiến trúc khác nhau, bao gồm Ống và Bộ lọc. [Monroe] cung cấp một cách tiếp cận chi tiết về mối quan hệ giữa các kiểu kiến trúc và các mẫu thiết kế. [PLoPD1] có bài "Kiến trúc Ống và Bộ lọc" của Regine Meunier, tạo thành cơ sở cho mẫu Ống và Bộ lọc được đưa vào [POSA]. Hầu hết các triển khai liên quan đến tích hợp của Ống và Bộ lọc đều tuân theo "Kịch bản IV" được trình bày trong [POSA], sử dụng bộ lọc chủ động kéo, xử lý và đẩy một cách độc lập từ và đến các ống xếp hàng. Mẫu được mô tả bởi [POSA] giả định rằng mỗi phần tử trải qua cùng một bước xử lý khi được truyền từ bộ lọc này sang bộ lọc khác. Điều này thường không đúng trong một kịch bản tích hợp. Trong nhiều trường hợp, các thông điệp được định tuyến một cách động dựa trên nội dung của thông điệp hoặc điều khiển bên ngoài. Trên thực tế, việc định tuyến là một hiện tượng phổ biến đến mức trong tích hợp doanh nghiệp, nó xứng đáng có các mẫu riêng, đó là Bộ định tuyến Thông điệp.
VocabularyKhi thảo luận về kiến trúc Pipes và Filters, chúng ta cần thận trọng với thuật ngữ "filter" (bộ lọc). Chúng tôi sau đó sẽ định nghĩa hai mẫu bổ sung, Bộ Lọc Tin Nhắn và Bộ Lọc Nội Dung. Trong khi cả hai đều là trường hợp đặc biệt của một bộ lọc chung, nhiều mẫu khác trong ngôn ngữ mẫu này cũng vậy. Nói cách khác, một mẫu không nhất thiết phải liên quan đến chức năng lọc (ví dụ: loại bỏ trường hoặc tin nhắn) để trở thành một bộ lọc theo nghĩa của Pipes và Filters. Chúng tôi có thể đã tránh được sự nhầm lẫn này bằng cách đổi tên phong cách kiến trúc Pipes và Filters. Tuy nhiên, chúng tôi cảm thấy rằng Pipes và Filters là một khái niệm quan trọng và được thảo luận rộng rãi đến mức sẽ còn gây nhầm lẫn hơn nếu chúng tôi đặt một cái tên mới cho nó. Chúng tôi đang cố gắng sử dụng từ "filter" một cách cẩn thận trong suốt các mẫu này và cố gắng rõ ràng về việc chúng tôi đang nói đến một bộ lọc chung như trong Pipes và Filters hay một Bộ Lọc Tin Nhắn/Bộ Lọc Nội Dung mà lọc các tin nhắn. Nếu chúng tôi nghĩ rằng vẫn có thể có sự nhầm lẫn, chúng tôi đã gọi bộ lọc chung là một thành phần, một thuật ngữ đủ chung (và thường bị lạm dụng) để không gây rắc rối cho chúng tôi. |
Các ống dẫn và bộ lọc có một số điểm tương đồng với khái niệm Quy trình tuần tự giao tiếp (CSP). Được giới thiệu bởi Hoare vào năm 1978 [CSP], CSP cung cấp một mô hình đơn giản để mô tả các vấn đề đồng bộ xảy ra trong các hệ thống xử lý song song. Cơ chế cơ bản nằm sau CSP là sự đồng bộ hóa của hai quy trình thông qua đầu vào-đầu ra (I/O). I/O xảy ra khi quy trình A chỉ định rằng nó sẵn sàng xuất dữ liệu cho quy trình B, và quy trình B cho biết rằng nó sẵn sàng nhận dữ liệu từ quy trình A. Nếu một trong hai điều này xảy ra mà điều còn lại không đúng, quy trình sẽ được đưa vào hàng đợi chờ cho đến khi quy trình kia sẵn sàng. CSP khác với các giải pháp tích hợp ở chỗ chúng không được liên kết lỏng lẻo như vậy, cũng như các "ống dẫn" không cung cấp bất kỳ cơ chế xếp hàng nào. Tuy nhiên, chúng ta có thể hưởng lợi từ sự tiếp cận sâu rộng của CSP trong giới học thuật.
| Ví dụ: Lọc đơn giản trong C# và MSMQ Mã code dưới đây cho thấy một lớp cơ sở tổng quát cho một bộ lọc với một cổng đầu vào và một cổng đầu ra. Cài đặt cơ bản đơn giản in nội dung của thông điệp nhận được và gửi nó tới cổng đầu ra. Một bộ lọc thú vị hơn sẽ kế thừa lớp Processor và ghi đè phương thức ProcessMessage để thực hiện các hành động bổ sung trên thông điệp, tức là, biến đổi nội dung thông điệp hoặc định tuyến nó tới các kênh đầu ra khác nhau. Bạn nhận thấy rằng Bộ xử lý nhận tham chiếu đến một kênh đầu vào và đầu ra trong quá trình khởi tạo. Do đó, lớp này không bị ràng buộc với bất kỳ kênh cụ thể nào cũng như bất kỳ bộ lọc nào khác. Điều này cho phép chúng ta khởi tạo nhiều bộ lọc và kết nối chúng với nhau theo các cấu hình tùy ý. [View full width] using System; using System.Messaging; namespace PipesAndFilters { public class Processor { protected MessageQueue inputQueue; protected MessageQueue outputQueue; public Processor (MessageQueue inputQueue, MessageQueue Việc triển khai này là một Người tiêu dùng theo sự kiện. Phương thức Process đăng ký nhận các tin nhắn đến và chỉ định hệ thống nhắn tin gọi phương thức OnReceiveCompleted mỗi khi có tin nhắn đến. Phương thức này trích xuất dữ liệu tin nhắn từ đối tượng sự kiện đến và gọi phương thức ảo ProcessMessage. Ví dụ bộ lọc đơn giản này không phải là giao dịch. Nếu xảy ra lỗi trong quá trình xử lý tin nhắn (trước khi nó được gửi tới kênh đầu ra), tin nhắn sẽ bị mất. Điều này thường không được mong muốn trong môi trường sản xuất. Xem Khách hàng Giao dịch để tìm giải pháp cho vấn đề này. |
Nhiều bước xử lý trong chuỗi Ống và Bộ lọc được kết nối bởi các Kênh Tin nhắn.
| Làm thế nào bạn có thể tách rời các bước xử lý riêng lẻ để các thông điệp có thể được chuyển đến các bộ lọc khác nhau tùy thuộc vào một tập hợp các điều kiện? |
Kiến trúc kiểu Ống và Bộ lọc kết nối các bộ lọc trực tiếp với nhau bằng các ống cố định. Điều này có ý nghĩa vì nhiều ứng dụng của mô hình Ống và Bộ lọc (ví dụ, [POSA]) dựa trên một tập hợp lớn các mục dữ liệu, mỗi mục đều trải qua cùng một chuỗi bước xử lý tuần tự. Ví dụ, một trình biên dịch sẽ luôn thực hiện phân tích từ vựng đầu tiên, phân tích cú pháp thứ hai, và phân tích ngữ nghĩa cuối cùng. Ngược lại, các giải pháp tích hợp dựa trên tin nhắn xử lý các tin nhắn cá nhân mà không nhất thiết phải liên kết với một tập dữ liệu lớn hơn duy nhất. Do đó, các tin nhắn cá nhân có khả năng yêu cầu một chuỗi bước xử lý khác nhau hơn.
Một Kênh Tin Nhắn tách biệt người gửi và người nhận của một Tin Nhắn. Điều này cũng có nghĩa là nhiều ứng dụng có thể công bố Tin Nhắn đến một Kênh Tin Nhắn. Kết quả là, một Kênh Tin Nhắn có thể chứa các tin nhắn từ các nguồn khác nhau mà có thể phải được xử lý khác nhau dựa trên loại tin nhắn hoặc các tiêu chí khác. Bạn có thể tạo một Kênh Tin Nhắn riêng cho mỗi loại tin nhắn (một khái niệm sẽ được giải thích chi tiết hơn sau này dưới dạng Kênh Kiểu Dữ Liệu) và kết nối mỗi kênh với các bước xử lý cần thiết cho loại tin nhắn đó. Tuy nhiên, điều này sẽ yêu cầu các nguồn gốc tin nhắn phải nhận thức được các tiêu chí lựa chọn cho các bước xử lý khác nhau để công bố tin nhắn vào kênh thích hợp. Nó cũng có thể dẫn đến sự bùng nổ số lượng Kênh Tin Nhắn. Hơn nữa, quyết định về các bước mà tin nhắn trải qua có thể không chỉ phụ thuộc vào nguồn gốc của tin nhắn. Ví dụ, chúng ta có thể tưởng tượng một tình huống trong đó đích đến của một tin nhắn thay đổi tùy thuộc vào số lượng tin nhắn đã đi qua kênh cho đến nay. Không một nguồn gốc nào có thể biết số này và do đó sẽ không thể gửi tin nhắn đến kênh chính xác.
Các Kênh Tin Nhắn cung cấp một dạng khả năng định tuyến rất cơ bản. Một ứng dụng phát hành một Tin Nhắn đến một Kênh Tin Nhắn và không có kiến thức gì thêm về đích đến của Tin Nhắn đó. Do đó, con đường của Tin Nhắn có thể thay đổi tùy thuộc vào thành phần nào đăng ký nhận Kênh Tin Nhắn. Tuy nhiên, loại "định tuyến" này không tính đến các thuộc tính của các tin nhắn riêng lẻ. Khi một thành phần đăng ký nhận Kênh Tin Nhắn, nó sẽ mặc định tiêu thụ tất cả các tin nhắn từ kênh đó mà không cần quan tâm đến các thuộc tính cụ thể của từng tin nhắn. Hành vi này tương tự như việc sử dụng ký hiệu ống trong UNIX để xử lý các tệp văn bản. Nó cho phép bạn kết hợp các quy trình thành một chuỗi Ống và Bộ lọc, nhưng trong suốt thời gian của chuỗi, tất cả các dòng văn bản đều trải qua cùng một bước xử lý.
Chúng ta có thể làm cho thành phần nhận chịu trách nhiệm xác định xem nó có nên xử lý một tin nhắn đến trên một Kênh Tin nhắn chung hay không. Điều này có vấn đề, vì một khi tin nhắn được tiêu thụ và thành phần quyết định rằng nó không muốn tin nhắn đó, nó không thể chỉ đơn giản đặt lại tin nhắn lên kênh để một thành phần khác kiểm tra. Một số hệ thống nhắn tin cho phép người nhận kiểm tra các thuộc tính của tin nhắn mà không cần loại bỏ tin nhắn khỏi kênh, để từ đó quyết định có tiêu thụ tin nhắn hay không. Tuy nhiên, đây không phải là một giải pháp tổng quát và cũng buộc thành phần tiêu thụ gắn liền với một loại tin nhắn cụ thể vì logic chọn lọc tin nhắn giờ đây được xây dựng ngay trong thành phần. Điều này sẽ giảm thiểu khả năng tái sử dụng của thành phần đó và loại bỏ tính khả thi, điều là sức mạnh chính của mô hình Ống và Bộ lọc.
Nhiều trong số các giải pháp thay thế này giả định rằng chúng ta có thể điều chỉnh các thành phần tham gia để đáp ứng nhu cầu của mình. Tuy nhiên, trong hầu hết các giải pháp tích hợp, các khối xây dựng (thành phần) là các ứng dụng lớn mà trong hầu hết các trường hợp không thể chỉnh sửa, chẳng hạn như vì chúng là các ứng dụng đóng gói hoặc ứng dụng kế thừa. Điều này làm cho việc điều chỉnh các ứng dụng sản xuất hoặc tiêu thụ thông điệp theo nhu cầu của hệ thống nhắn tin hoặc các ứng dụng khác trở nên không kinh tế hoặc thậm chí không thể.
Một lợi thế của Pipes và Filters là tính khả tổ hợp của các thành phần riêng lẻ. Tính chất này cho phép chúng ta chèn các bước bổ sung vào chuỗi lọc mà không cần phải thay đổi các thành phần hiện có. Điều này mở ra lựa chọn tách biệt hai bộ lọc bằng cách chèn vào giữa chúng một bộ lọc khác xác định bước nào sẽ được thực hiện tiếp theo.
| Chèn một bộ lọc đặc biệt, một Bộ định tuyến Tin nhắn, tiêu thụ một Tin nhắn từ một Kênh Tin nhắn và tái xuất bản nó ra một Kênh Tin nhắn khác, phụ thuộc vào một tập hợp các điều kiện.
|
Bộ định tuyến tin nhắn khác với khái niệm cơ bản về Ống và Bộ lọc ở chỗ nó kết nối với nhiều kênh đầu ra (tức là, nó có nhiều cổng đầu ra). Tuy nhiên, nhờ vào kiến trúc Ống và Bộ lọc, các thành phần xung quanh Bộ định tuyến tin nhắn hoàn toàn không biết về sự tồn tại của Bộ định tuyến tin nhắn. Chúng chỉ đơn giản tiêu thụ tin nhắn từ một kênh và công bố chúng ra một kênh khác. Một đặc điểm xác định của Bộ định tuyến tin nhắn là nó không sửa đổi nội dung tin nhắn; nó chỉ quan tâm đến đích đến của tin nhắn.
Lợi ích chính của việc sử dụng Bộ định tuyến Tin nhắn là các tiêu chí quyết định cho đích đến của một tin nhắn được duy trì ở một vị trí duy nhất. Nếu các loại tin nhắn mới được xác định, các thành phần xử lý mới được thêm vào, hoặc các quy tắc định tuyến thay đổi, chúng ta chỉ cần thay đổi logic của Bộ định tuyến Tin nhắn, trong khi tất cả các thành phần khác không bị ảnh hưởng. Ngoài ra, vì tất cả các tin nhắn đều đi qua một Bộ định tuyến Tin nhắn duy nhất, các tin nhắn đến được đảm bảo sẽ được xử lý lần lượt theo đúng thứ tự.
Trong khi mục đích của một Bảng định tuyến Tin nhắn là để tách biệt các bộ lọc khỏi nhau, việc sử dụng Bảng định tuyến Tin nhắn thực sự có thể gây ra hiệu ứng ngược lại. Thành phần Bảng định tuyến Tin nhắn phải có kiến thức về tất cả các kênh đích có thể để gửi tin nhắn đến kênh đúng. Nếu danh sách các điểm đến có thể thay đổi thường xuyên, Bảng định tuyến Tin nhắn có thể trở thành một nút thắt về bảo trì. Trong những trường hợp đó, tốt hơn hết là để các người nhận cá nhân quyết định tin nhắn nào họ quan tâm. Bạn có thể đạt được điều này bằng cách sử dụng Kênh Công bố-Đăng ký và một mảng các Bộ lọc Tin nhắn. Chúng tôi so sánh hai lựa chọn này bằng cách gọi chúng là định tuyến dự đoán và lọc phản ứng (để so sánh chi tiết hơn, xem Bộ lọc Tin nhắn trong Chương 7, "Định tuyến Tin nhắn").
Bởi vì một Bộ Định Tuyến Thông Điệp yêu cầu chèn thêm một bước xử lý, nó có thể làm giảm hiệu suất. Nhiều hệ thống dựa trên thông điệp phải giải mã thông điệp từ một kênh trước khi nó có thể được đặt lên một kênh khác, điều này gây ra gánh nặng tính toán nếu thông điệp thực tế không thay đổi. Gánh nặng này có thể biến Bộ Định Tuyến Thông Điệp thành một điểm nghẽn hiệu suất. Bằng cách sử dụng nhiều bộ định tuyến song song hoặc thêm phần cứng bổ sung, hiệu ứng này có thể được tối thiểu hóa. Kết quả là, thông lượng thông điệp (số lượng thông điệp được xử lý mỗi đơn vị thời gian) có thể không bị ảnh hưởng, nhưng độ trễ (thời gian để một thông điệp di chuyển qua hệ thống) chắc chắn sẽ tăng lên.
Như hầu hết các công cụ tốt, Bộ định tuyến Tin nhắn cũng có thể bị lạm dụng. Việc sử dụng có chủ đích Bộ định tuyến Tin nhắn có thể biến lợi thế của việc liên kết lỏng lẻo thành bất lợi. Các hệ thống liên kết lỏng lẻo có thể làm khó khăn cho việc hiểu "bức tranh tổng thể" của giải pháp – dòng chảy tổng thể của tin nhắn trong hệ thống. Đây là một vấn đề thường gặp với các giải pháp nhắn tin, và việc sử dụng bộ định tuyến có thể làm trầm trọng thêm vấn đề. Nếu mọi thứ đều liên kết lỏng lẻo với mọi thứ khác, sẽ trở nên không thể hiểu được tin nhắn thực sự chảy theo hướng nào. Điều này có thể làm phức tạp việc kiểm tra, gỡ lỗi và bảo trì. Một số công cụ có thể giúp giảm bớt vấn đề này. Đầu tiên, chúng ta có thể sử dụng Lịch sử Tin nhắn để kiểm tra các tin nhắn trong thời gian chạy và xem các thành phần nào mà chúng đã đi qua. Ngoài ra, chúng ta có thể biên soạn danh sách tất cả các kênh mà mỗi thành phần trong hệ thống đăng ký hoặc công bố. Với hiểu biết này, chúng ta có thể vẽ đồ thị của tất cả các luồng tin nhắn có thể xảy ra giữa các thành phần. Nhiều gói EAI duy trì thông tin đăng ký kênh trong một kho lưu trữ trung tâm, giúp cho việc phân tích tĩnh loại này trở nên dễ dàng hơn.
Một Bộ Định Tuyến Tin Nhắn có thể sử dụng bất kỳ số lượng tiêu chí nào để xác định kênh đầu ra cho một tin nhắn đến. Trường hợp đơn giản nhất là một bộ định tuyến cố định. Trong trường hợp này, chỉ định nghĩa một kênh đầu vào duy nhất và một kênh đầu ra duy nhất. Bộ định tuyến cố định tiêu thụ một tin nhắn từ kênh đầu vào và phát hành nó ra kênh đầu ra. Tại sao chúng ta lại sử dụng một bộ định tuyến đơn giản như vậy? Bộ định tuyến cố định có thể hữu ích để cố ý tách biệt các hệ thống con cho phép chúng ta có thể chèn một bộ định tuyến thông minh hơn sau này. Hoặc, chúng ta có thể đang chuyển tiếp các tin nhắn giữa nhiều giải pháp tích hợp khác nhau. Trong hầu hết các trường hợp, bộ định tuyến cố định sẽ được kết hợp với một Bộ Dịch Tin Nhắn hoặc một Bộ Chuyển Đổi Kênh để biến đổi nội dung tin nhắn hoặc gửi tin nhắn qua một loại kênh khác.
Nhiều Bộ định tuyến Tin nhắn quyết định điểm đến của tin nhắn chỉ dựa trên thuộc tính của chính tin nhắn đó, ví dụ như loại tin nhắn hoặc giá trị của các trường tin nhắn cụ thể. Chúng tôi gọi loại bộ định tuyến này là Bộ định tuyến Dựa trên Nội dung. Loại bộ định tuyến này phổ biến đến mức mẫu Bộ định tuyến Dựa trên Nội dung mô tả nó chi tiết hơn.
Các bộ định tuyến tin nhắn khác quyết định đích đến của tin nhắn dựa trên các điều kiện môi trường. Chúng tôi gọi những bộ định tuyến này là bộ định tuyến dựa trên ngữ cảnh. Các bộ định tuyến như vậy thường được sử dụng để thực hiện chức năng cân bằng tải, kiểm tra hoặc chuyển tiếp. Ví dụ, nếu một thành phần xử lý gặp sự cố, bộ định tuyến dựa trên ngữ cảnh có thể chuyển hướng tin nhắn đến một thành phần xử lý khác và do đó cung cấp khả năng chuyển tiếp. Các bộ định tuyến khác phân tách luồng tin nhắn đều đặn qua nhiều kênh để đạt được xử lý song song tương tự như một bộ cân bằng tải. Một số Kênh Tin Nhắn đã cung cấp khả năng cân bằng tải cơ bản mà không cần sử dụng Bộ Định Tuyến Tin Nhắn vì nhiều Người Tiêu Thụ Cạnh Tranh có thể mỗi người tiêu thụ tin nhắn từ cùng một kênh nhanh như họ có thể. Tuy nhiên, một Bộ Định Tuyến Tin Nhắn có thể có sự thông minh tích hợp bổ sung để định hướng tin nhắn thay vì một triển khai đơn giản theo kiểu vòng đàm phán được thực hiện bởi kênh.
Nhiều Bộ định tuyến Tin nhắn là không trạng thái, nghĩa là chúng chỉ xem xét một tin nhắn tại một thời điểm để đưa ra quyết định định tuyến. Các bộ định tuyến khác xem xét nội dung của các tin nhắn trước đó khi đưa ra quyết định định tuyến. Ví dụ, ví dụ về Ống và Lọc đã sử dụng một bộ định tuyến loại bỏ các tin nhắn trùng lặp bằng cách giữ một danh sách tất cả các tin nhắn mà nó đã nhận. Những bộ định tuyến này là có trạng thái.
Hầu hết các Bộ định tuyến Tin nhắn chứa logic cố định cho quyết định định tuyến. Tuy nhiên, một số biến thể kết nối với một Bus Điều khiển để giải pháp trung gian có thể thay đổi tiêu chí quyết định mà không cần phải thực hiện bất kỳ thay đổi mã nào hoặc làm gián đoạn luồng tin nhắn. Ví dụ, Bus Điều khiển có thể truyền giá trị của một biến toàn cục đến tất cả các Bộ định tuyến Tin nhắn trong hệ thống. Điều này có thể rất hữu ích cho việc thử nghiệm để cho phép hệ thống nhắn tin chuyển từ chế độ thử nghiệm sang chế độ sản xuất. Bộ định tuyến Động cấu hình bản thân một cách động dựa trên các tin nhắn điều khiển từ mỗi người nhận tiềm năng.
Chương 7, "Lộ trình Tin nhắn," giới thiệu nhiều biến thể của Bộ định tuyến Tin nhắn.
| Ví dụ: Công cụ EAI thương mại Khái niệm về Routers Tin nhắn là trung tâm trong khái niệm của một Nhà môi giới Tin nhắn, được triển khai trong hầu hết các công cụ EAI thương mại. Những công cụ này chấp nhận các tin nhắn đến, xác thực chúng, chuyển đổi chúng, và định tuyến chúng đến đích đúng. Kiến trúc này giảm bớt gánh nặng cho các ứng dụng tham gia trong việc phải nhận thức về các ứng dụng khác vì Nhà môi giới Tin nhắn điều phối giữa các ứng dụng. Đây là một chức năng then chốt trong tích hợp doanh nghiệp vì hầu hết các ứng dụng cần kết nối là các ứng dụng đóng gói hoặc ứng dụng kế thừa và việc tích hợp phải diễn ra một cách không xâm phạm, tức là, mà không thay đổi mã nguồn của ứng dụng. Do đó, phần mềm trung gian phải tích hợp tất cả logic định tuyến để các ứng dụng không phải làm điều đó. Nhà môi giới Tin nhắn là tương đương tích hợp của một Người hòa giải được trình bày trong [GoF]. |
| Ví dụ: Bộ định tuyến đơn giản với C# và MSMQ Mẫu mã này minh họa một bộ định tuyến rất đơn giản, nó chuyển tiếp một tin nhắn đến một trong hai kênh xuất có thể có dựa trên một điều kiện đơn giản. [View full width] class SimpleRouter { protected MessageQueue inQueue; protected MessageQueue outQueue1; protected MessageQueue outQueue2; public SimpleRouter(MessageQueue inQueue, MessageQueue Mã nguồn khá đơn giản. Giống như bộ lọc đơn giản được trình bày trong Pipes and Filters, lớp SimpleRouter triển khai một Người tiêu dùng Dựa trên Sự kiện cho các thông điệp bằng cách sử dụng các ủy quyền C#. Constructor đăng ký phương thức OnMessage làm trình xử lý cho các thông điệp đến từ inQueue. Điều này khiến .NET Framework gọi phương thức OnMessage cho mỗi thông điệp đến inQueue. OnMessage xác định nơi để chuyển tiếp thông điệp bằng cách gọi phương thức IsConditionFulfilled. Trong ví dụ đơn giản này, IsConditionFulfilled chỉ đơn giản là chuyển đổi giữa hai kênh, chia đều chuỗi các thông điệp giữa outQueue1 và outQueue2. Để giữ cho mã nguồn ở mức tối thiểu, bộ định tuyến đơn giản này không có tính chất giao dịch, tức là, nếu bộ định tuyến gặp sự cố sau khi tiêu thụ một thông điệp từ kênh đầu vào và trước khi phát hành nó đến kênh đầu ra, thông điệp đó sẽ bị mất. Client Giao dịch giải thích cách để làm cho các điểm cuối có tính chất giao dịch. |
Các mẫu trước đây cho thấy cách xây dựng tin nhắn và cách định tuyến chúng đến đích chính xác. Trong nhiều trường hợp, các giải pháp tích hợp doanh nghiệp định tuyến tin nhắn giữa các ứng dụng hiện có như hệ thống kế thừa, ứng dụng đóng gói, ứng dụng tùy chỉnh tự phát triển, hoặc các ứng dụng được vận hành bởi các đối tác bên ngoài. Mỗi ứng dụng này thường được xây dựng xung quanh một mô hình dữ liệu độc quyền. Mỗi ứng dụng có thể có một khái niệm hơi khác về thực thể Khách hàng, các thuộc tính xác định một Khách hàng, và các thực thể khác mà Khách hàng có liên quan. Ví dụ, hệ thống kế toán có thể quan tâm nhiều hơn đến số nhận dạng người nộp thuế của khách hàng, trong khi hệ thống quản lý quan hệ khách hàng (CRM) lưu trữ số điện thoại và địa chỉ. Mô hình dữ liệu cơ sở của ứng dụng thường dẫn dắt thiết kế của sơ đồ cơ sở dữ liệu vật lý, định dạng tệp giao diện, hoặc giao diện lập trình ứng dụng (API) mà các thực thể mà giải pháp tích hợp phải giao tiếp. Kết quả là, mỗi ứng dụng thường kỳ vọng nhận được các tin nhắn mô phỏng định dạng dữ liệu nội bộ của ứng dụng.
Ngoài các mô hình dữ liệu và định dạng dữ liệu độc quyền được tích hợp trong các ứng dụng khác nhau, các giải pháp tích hợp thường tương tác với các đối tác kinh doanh bên ngoài thông qua các định dạng dữ liệu tiêu chuẩn không phụ thuộc vào các ứng dụng cụ thể. Nhiều tổ chức liên minh và cơ quan tiêu chuẩn định nghĩa các giao thức này; ví dụ, RosettaNet, ebXML, OAGIS và nhiều tổ chức liên minh cụ thể theo ngành khác. Trong nhiều trường hợp, giải pháp tích hợp cần có khả năng giao tiếp với các bên bên ngoài sử dụng các định dạng dữ liệu "chính thức", ngay cả khi các hệ thống nội bộ dựa trên các định dạng độc quyền.
| Các hệ thống sử dụng các định dạng dữ liệu khác nhau có thể giao tiếp với nhau như thế nào thông qua việc nhắn tin? |
Chúng ta có thể tránh việc phải chuyển đổi thông điệp nếu chúng ta có thể sửa đổi tất cả các ứng dụng để sử dụng một định dạng dữ liệu chung. Điều này hóa ra là khó khăn vì một số lý do (xem Cơ sở Dữ liệu Chia sẻ). Đầu tiên, việc thay đổi định dạng dữ liệu của một ứng dụng là rủi ro, khó khăn và đòi hỏi nhiều thay đổi đối với các chức năng kinh doanh vốn có. Đối với hầu hết các ứng dụng kế thừa, việc thay đổi định dạng dữ liệu đơn giản là không khả thi về mặt kinh tế. Chúng ta có thể nhớ lại nỗ lực liên quan đến việc nâng cấp Y2K, nơi phạm vi của sự thay đổi chỉ giới hạn trong kích thước của một trường đơn!
Ngoài ra, trong khi chúng ta có thể nhận được nhiều ứng dụng sử dụng cùng tên trường dữ liệu và có thể thậm chí là cùng kiểu dữ liệu, thì đại diện vật lý vẫn có thể khác nhau khá nhiều. Một ứng dụng có thể sử dụng tài liệu XML, trong khi ứng dụng khác sử dụng sách sao COBOL.
Hơn nữa, nếu chúng ta điều chỉnh định dạng dữ liệu của một ứng dụng để phù hợp với định dạng của một ứng dụng khác, chúng ta đang gắn chặt hai ứng dụng với nhau hơn. Một trong những nguyên tắc kiến trúc chính trong tích hợp doanh nghiệp là liên kết lỏng giữa các ứng dụng (xem Mô hình dữ liệu tiêu chuẩn). Việc chỉnh sửa một ứng dụng để phù hợp với định dạng dữ liệu của một ứng dụng khác sẽ vi phạm nguyên tắc này vì nó khiến hai ứng dụng phụ thuộc trực tiếp vào cách thể hiện nội bộ của nhau. Điều này loại bỏ khả năng thay thế hoặc thay đổi một ứng dụng mà không ảnh hưởng đến ứng dụng khác, một kịch bản khá phổ biến trong tích hợp doanh nghiệp.
Chúng tôi có thể tích hợp việc chuyển đổi định dạng dữ liệu trực tiếp vào Điểm cuối Tin nhắn. Bằng cách này, tất cả các ứng dụng sẽ công bố và tiêu thụ tin nhắn trong một định dạng chung thay vì trong định dạng dữ liệu nội bộ của ứng dụng. Tuy nhiên, phương pháp này yêu cầu truy cập vào mã của điểm cuối, điều này thường không khả thi đối với các ứng dụng đã được đóng gói. Ngoài ra, việc mã cứng hóa chuyển đổi định dạng vào điểm cuối sẽ giảm cơ hội tái sử dụng mã.
| Sử dụng một bộ lọc đặc biệt, một Trình Dịch Tin Nhắn, giữa các bộ lọc khác hoặc ứng dụng để chuyển đổi định dạng dữ liệu này sang định dạng khác.
|
Trình dịch tin nhắn là tương đương trong việc nhắn tin với mẫu Adapter được mô tả trong [GoF]. Một adapter chuyển đổi giao diện của một thành phần thành một giao diện khác để nó có thể được sử dụng trong một bối cảnh khác.
Việc dịch tin nhắn có thể cần diễn ra ở nhiều cấp độ khác nhau. Ví dụ, các yếu tố dữ liệu có thể chia sẻ cùng tên và kiểu dữ liệu nhưng có thể được sử dụng trong các biểu diễn khác nhau (ví dụ, tệp XML so với giá trị phân cách bằng dấu phẩy so với các trường có độ dài cố định). Hoặc, tất cả các yếu tố dữ liệu có thể được biểu diễn theo định dạng XML nhưng sử dụng các tên thẻ khác nhau. Tóm tắt các loại dịch khác nhau, chúng ta có thể chia nó thành nhiều lớp (mượn ý tưởng một cách lỏng lẻo từ Mô hình Tham chiếu OSI).
Lớp | Giải quyết với | Nhu cầu chuyển đổi (Ví dụ) | Công cụ/Kỹ thuật |
|---|---|---|---|
Cấu trúc Dữ liệu (Lớp Ứng dụng) | Thực thể, hiệp hội, bậc phần tử | Tóm gọn mối quan hệ nhiều-nhiều thành tổng hợp. | Mô hình lập bản đồ cấu trúc, mã tùy chỉnh |
Loại dữ liệu | Tên trường, kiểu dữ liệu, miền giá trị, ràng buộc, giá trị mã | Chuyển đổi mã ZIP từ dạng số sang dạng chuỗi. Nối trường Tên và Họ thành một trường Tên duy nhất. Thay thế tên tiểu bang của Hoa Kỳ bằng mã hai ký tự. | Công cụ chỉnh sửa chuyển đổi hình ảnh EAI, XSL, tra cứu cơ sở dữ liệu, mã tùy chỉnh |
Biểu diễn dữ liệu | Định dạng dữ liệu (XML, cặp tên-giá trị, trường dữ liệu có độ dài cố định, định dạng nhà cung cấp EAI, v.v.) Bảng ký tự (ASCII, Unicode, EBCDIC) Mã hóa/giải nén | Phân tích đại diện dữ liệu và hiển thị dưới định dạng khác. Giải mã/mã hóa khi cần thiết. | Công cụ phân tích XML, công cụ phân tích/render EAI, API tùy chỉnh |
Vận chuyển | Giao thức truyền thông: socket TCP/IP, HTTP, SOAP, JMS, TIBCO RendezVous | Di chuyển dữ liệu qua các giao thức mà không ảnh hưởng đến nội dung tin nhắn. | Bộ điều hợp kênh, bộ điều hợp EAI |
Lớp Giao vận ở dưới cùng của "ngăn xếp" cung cấp việc truyền dữ liệu giữa các hệ thống khác nhau. Nó chịu trách nhiệm cho việc truyền dữ liệu hoàn chỉnh và đáng tin cậy qua các đoạn mạng khác nhau và xử lý các gói dữ liệu bị mất cũng như các lỗi mạng khác. Một số nhà cung cấp EAI cung cấp các giao thức vận chuyển riêng của họ (ví dụ: TIBCO RendezVous), trong khi các công nghệ tích hợp khác sử dụng các giao thức TCP/IP (ví dụ: SOAP). Việc chuyển đổi giữa các lớp giao vận khác nhau có thể được thực hiện thông qua mẫu Kênh Bộ chuyển đổi.
Lớp Biểu diễn Dữ liệu cũng được gọi là lớp cú pháp. Lớp này xác định cách biểu diễn dữ liệu được vận chuyển. Việc chuyển đổi này là cần thiết vì lớp vận chuyển thường chỉ vận chuyển các dòng ký tự hoặc byte. Điều này có nghĩa là các cấu trúc dữ liệu phức tạp phải được chuyển đổi thành một chuỗi ký tự. Các định dạng phổ biến cho việc chuyển đổi này bao gồm XML, các trường có độ dài cố định (ví dụ: bản ghi EDI) và các định dạng độc quyền. Trong nhiều trường hợp, dữ liệu cũng được nén hoặc mã hóa và mang theo các số kiểm tra hoặc chứng chỉ số. Để kết nối các hệ thống với các biểu diễn dữ liệu khác nhau, dữ liệu có thể phải được giải mã, giải nén và phân tích, sau đó định dạng dữ liệu mới phải được chuyển đổi và có thể cũng cần được nén và mã hóa.
Lớp Các Loại Dữ Liệu xác định các loại dữ liệu ứng dụng mà mô hình miền ứng dụng dựa vào. Tại đây, chúng ta xem xét các quyết định như liệu các trường ngày tháng có được đại diện dưới dạng chuỗi hay cấu trúc ngày tháng nguyên thủy, liệu các ngày có mang thành phần thời gian trong ngày hay không, và múi giờ nào mà chúng dựa vào, và nhiều vấn đề khác. Chúng ta cũng có thể xem xét liệu trường Mã Bưu Điện chỉ đề cập đến mã ZIP của Mỹ hay có thể chứa các mã bưu điện của Canada. Trong trường hợp mã ZIP của Mỹ, liệu chúng ta có bao gồm ZIP+4 không? Có bắt buộc không? Nó được lưu trữ trong một trường hay hai trường? Nhiều câu hỏi này thường được giải quyết trong các Từ Điển Dữ Liệu. Các vấn đề liên quan đến loại dữ liệu không chỉ dừng lại ở việc một trường là kiểu chuỗi hay số nguyên. Hãy xem xét dữ liệu bán hàng được tổ chức theo vùng miền. Ứng dụng được sử dụng bởi một bộ phận có thể chia đất nước thành bốn vùng: Tây, Trung, Nam và Đông, được xác định bằng các chữ cái W, C, S và E. Một bộ phận khác có thể phân biệt vùng Thái Bình Dương với vùng núi và phân biệt vùng Đông Bắc với vùng Đông Nam. Mỗi vùng được xác định bằng một số hai chữ số. Chữ cái E tương ứng với số nào?
Lớp cấu trúc dữ liệu mô tả dữ liệu ở mức mô hình miền ứng dụng. Do đó, nó cũng được gọi là lớp ứng dụng. Lớp này định nghĩa các thực thể logic mà ứng dụng liên quan đến, chẳng hạn như khách hàng, địa chỉ hoặc tài khoản. Nó cũng định nghĩa các mối quan hệ giữa các thực thể này: Một khách hàng có thể có nhiều tài khoản không? Một khách hàng có thể có nhiều địa chỉ không? Các khách hàng có thể chia sẻ một địa chỉ không? Nhiều khách hàng có thể chia sẻ một tài khoản không? Địa chỉ là một phần của tài khoản hay của khách hàng? Đây là lĩnh vực của các sơ đồ thực thể - quan hệ và sơ đồ lớp.
Nhiều sự đánh đổi trong thiết kế tích hợp được thúc đẩy bởi nhu cầu tách rời các thành phần hoặc ứng dụng. Tách rời là một công cụ thiết yếu để quản lý sự thay đổi. Tích hợp thường kết nối các ứng dụng hiện có và cần phải điều chỉnh các thay đổi cho những ứng dụng này. Kênh Tin nhắn tách rời các ứng dụng khỏi việc phải biết vị trí của nhau. Bộ định tuyến Tin nhắn thậm chí có thể tách rời các ứng dụng khỏi việc phải đồng ý về một Kênh Tin nhắn chung. Tuy nhiên, hình thức tách rời này chỉ đạt được sự độc lập hạn chế giữa các ứng dụng nếu chúng vẫn phụ thuộc vào định dạng dữ liệu của nhau. Bộ dịch Tin nhắn có thể loại bỏ cấp độ phụ thuộc bổ sung này.
Nhiều kịch bản kinh doanh yêu cầu chuyển đổi ở hơn một lớp. Ví dụ, hãy giả sử một bản ghi EDI 850 Đơn đặt hàng được biểu thị dưới dạng tệp định dạng cố định cần được dịch sang một tài liệu XML được gửi qua HTTP tới hệ thống quản lý đơn hàng, mà sử dụng định nghĩa khác về đối tượng Đơn hàng. Chuyển đổi cần thiết bao gồm tất cả bốn cấp độ: Vận chuyển thay đổi từ chuyển tệp sang HTTP, định dạng dữ liệu thay đổi từ định dạng trường cố định sang XML, và cả kiểu dữ liệu và định dạng dữ liệu cần được chuyển đổi để phù hợp với đối tượng Đơn hàng được định nghĩa bởi hệ thống quản lý đơn hàng. Sự tuyệt vời của một mô hình theo lớp là bạn có thể xử lý một lớp mà không cần lo lắng về các lớp dưới, do đó có thể tập trung vào một mức độ trừu tượng tại một thời điểm.
Lập bản đồ qua nhiều lớp

Việc nối chuỗi nhiều đơn vị Dịch Tin nhắn bằng Pipes và Bộ lọc dẫn đến kiến trúc sau (xem hình ở trang tiếp theo). Tạo một Dịch Tin nhắn cho mỗi lớp cho phép chúng ta tái sử dụng những thành phần này trong các kịch bản khác nhau. Chẳng hạn, Bộ chuyển đổi Kênh và Dịch Tin nhắn EDI-to-XML có thể được triển khai theo cách chung để chúng có thể được sử dụng lại cho bất kỳ tài liệu EDI nào đến.
Chuỗi nhiều bộ biên dịch tin nhắn

Việc liên kết nhiều Bộ dịch Tin nhắn cũng cho phép bạn thay đổi các phép biến đổi được sử dụng ở mỗi lớp mà không ảnh hưởng đến bất kỳ lớp nào khác. Bạn có thể sử dụng cùng một cơ chế biến đổi cấu trúc, nhưng thay vì chuyển đổi đại diện dữ liệu thành một định dạng cố định, bạn có thể chuyển đổi nó thành một tệp phân cách bằng dấu phẩy bằng cách thay thế phép biến đổi đại diện dữ liệu.
Có nhiều chuyên môn và biến thể của mẫu Trình Dịch Tin Nhắn. Một Bao Bì Đóng Gói bọc dữ liệu tin nhắn bên trong một bao bì để nó có thể được vận chuyển qua một hệ thống nhắn tin. Một Người Làm Giàu Nội Dung tăng cường thông tin bên trong một tin nhắn, trong khi Bộ Lọc Nội Dung loại bỏ thông tin. Chứng Nhận Lưu trữ thông tin nhưng lưu trữ nó để truy xuất sau. Bộ Chuẩn Hóa có thể chuyển đổi nhiều định dạng tin nhắn khác nhau thành một định dạng đồng nhất. Cuối cùng, Mô Hình Dữ Liệu Luật Lệ cho thấy cách tận dụng nhiều Trình Dịch Tin Nhắn để đạt được sự tách biệt định dạng dữ liệu. Bên trong mỗi mẫu đó, có thể xảy ra các chuyển đổi cấu trúc phức tạp (ví dụ: ánh xạ quan hệ nhiều-nhiều thành quan hệ một-một).
| Ví dụ: Biến đổi cấu trúc với XSL Biến đổi là một nhu cầu phổ biến đến nỗi W3C đã định nghĩa một ngôn ngữ tiêu chuẩn cho việc chuyển đổi các tài liệu XML: Ngôn ngữ Tuyên bố Mở Rộng (XSL). Một phần của XSL là ngôn ngữ Chuyển đổi XSL (XSLT), một ngôn ngữ dựa trên quy tắc để dịch một tài liệu XML sang định dạng khác. Bởi vì đây là một cuốn sách về tích hợp chứ không phải về XSLT, chúng tôi chỉ trình bày một ví dụ đơn giản (để biết tất cả các chi tiết phức tạp, hãy xem tài liệu [XSLT 1.0], hoặc để học bằng cách xem xét các ví dụ mã, hãy xem [Tennison]). Để giữ cho mọi thứ đơn giản, chúng tôi giải thích quá trình chuyển đổi cần thiết bằng cách trình bày các tài liệu XML ví dụ thay vì các lược đồ XML. Ví dụ, giả sử chúng ta có một tài liệu XML đến và cần truyền nó đến hệ thống kế toán. Nếu cả hai hệ thống đều sử dụng XML, lớp Đại diện Dữ liệu là giống nhau, và chúng ta cần phải xử lý bất kỳ sự khác biệt nào về tên trường, loại dữ liệu và cấu trúc. Giả sử tài liệu đến trông như thế này. <data> <customer> <firstname>Joe</firstname> <lastname>Doe</lastname> <address type="primary"> <ref id="55355"/> </address> <address type="secondary"> <ref id="77889"/> </address> </customer> <address id="55355"> <street>123 Main</street> <city>San Francisco</city> <state>CA</state> <postalcode>94123</postalcode> <country>USA</country> <phone type="cell"> <area>415</area> <prefix>555</prefix> <number>1234</number> </phone> <phone type="home"> <area>415</area> <prefix>555</prefix> <number>5678</number> </phone> </address> <address id="77889"> <company>ThoughtWorks</company> <street>410 Townsend</street> <city>San Francisco</city> <state>CA</state> <postalcode>94107</postalcode> <country>USA</country> </address> </data> Tài liệu XML này chứa dữ liệu khách hàng. Mỗi khách hàng có thể liên kết với nhiều địa chỉ, mỗi địa chỉ có thể chứa nhiều số điện thoại. XML đại diện cho các địa chỉ như những thực thể độc lập để nhiều khách hàng có thể chia sẻ một địa chỉ. Giả sử hệ thống kế toán cần đại diện như sau. (Nếu bạn nghĩ rằng các tên thẻ tiếng Đức có vẻ xa vời, hãy nhớ rằng một trong những phần mềm doanh nghiệp phổ biến nhất (SAP) nổi tiếng với các tên trường bằng tiếng Đức!) <Kunde> <Name>Joe Doe</Name> <Adresse> <Strasse>123 Main</Strasse> <Ort>San Francisco</Ort> <Telefon>415-555-1234</Telefon> </Adresse> </Kunde> Tài liệu kết quả có cấu trúc đơn giản hơn nhiều. Tên thẻ khác nhau, và một số trường đã được gộp lại thành một trường duy nhất. Vì chỉ có chỗ cho một địa chỉ và số điện thoại, chúng ta cần chọn một từ tài liệu gốc dựa trên các quy tắc kinh doanh. Chương trình XSLT sau đây chuyển đổi tài liệu gốc thành định dạng mong muốn. Nó thực hiện điều này bằng cách khớp các phần tử của tài liệu đến và dịch chúng thành định dạng tài liệu mong muốn. [View full width] <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999 XSL dựa trên việc khớp mẫu và có thể hơi khó đọc nếu bạn quen với lập trình theo quy trình như hầu hết chúng ta. Nói một cách đơn giản, các lệnh bên trong phần tử <xsl:template> sẽ được gọi mỗi khi một phần tử trong tài liệu XML đến khớp với biểu thức được chỉ định trong thuộc tính match. <xsl:template match="customer"> gây ra các dòng tiếp theo được thực thi cho mỗi phần tử <khách hàng> trong tài liệu nguồn. Các câu lệnh tiếp theo nối kết họ và tên và xuất ra bên trong phần tử <Tên>. Việc lấy địa chỉ thì khó hơn một chút. Mã XSL tra cứu trường hợp đúng của phần tử <địa chỉ> và gọi thủ tục con getaddr. getaddr trích xuất địa chỉ và số điện thoại từ phần tử <địa chỉ> gốc. Nó sử dụng số điện thoại di động nếu có, hoặc số điện thoại cố định trong trường hợp ngược lại. |
| Ví dụ: Công cụ Chuyển đổi Hình ảnh Nếu bạn thấy lập trình XSL có phần khó hiểu, bạn không phải là người duy nhất. Do đó, hầu hết các nhà cung cấp tích hợp đều cung cấp một trình biên tập chuyển đổi trực quan hiển thị cấu trúc của hai định dạng tài liệu ở phía bên trái và bên phải của màn hình tương ứng. Người dùng sau đó có thể liên kết các phần tử giữa các định dạng bằng cách vẽ các đường nối giữa chúng. Điều này có thể đơn giản hơn nhiều so với việc mã hóa XSL. Một số nhà cung cấp, chẳng hạn như Contivo, chuyên hoàn toàn vào các công cụ chuyển đổi. Hình dưới đây cho thấy trình chỉnh sửa Microsoft BizTalk Mapper được tích hợp vào Visual Studio. Sơ đồ thể hiện sự ánh xạ giữa các phần tử riêng lẻ rõ ràng hơn so với mã XSL. Mặt khác, một số chi tiết (chẳng hạn như cách chọn địa chỉ) được ẩn dưới các biểu tượng gọi là functoid. Tạo Biến Đổi: Phong Cách Kéo-Thả
Việc có thể kéo và thả các biến đổi giúp rút ngắn đáng kể thời gian học tập để phát triển một Trình Dịch Thông Điệp. Tuy nhiên, như thường lệ, các công cụ trực quan cũng có thể trở thành gánh nặng khi cần gỡ lỗi hoặc khi bạn cần tạo ra các giải pháp phức tạp. Do đó, nhiều công cụ cho phép bạn chuyển đổi qua lại giữa XSL và biểu diễn trực quan. |
Các ứng dụng đang giao tiếp với nhau bằng cách gửi tin nhắn qua các kênh tin nhắn.
| Một ứng dụng kết nối với kênh nhắn tin như thế nào để gửi và nhận tin nhắn? |
Ứng dụng và hệ thống nhắn tin là hai tập hợp phần mềm khác nhau. Ứng dụng cung cấp chức năng cho một số loại người dùng, trong khi hệ thống nhắn tin quản lý các kênh nhắn tin để truyền tải thông điệp nhằm giao tiếp. Ngay cả khi hệ thống nhắn tin được tích hợp như một phần cơ bản của ứng dụng, nó vẫn là một nhà cung cấp chức năng chuyên biệt tách biệt, tương tự như hệ thống quản lý cơ sở dữ liệu hoặc máy chủ Web. Bởi vì ứng dụng và hệ thống nhắn tin là tách biệt, chúng cần có cách để kết nối và làm việc cùng nhau.
Các ứng dụng không còn kết nối với kênh tin nhắn

Một hệ thống nhắn tin là một loại máy chủ, có khả năng tiếp nhận các yêu cầu và phản hồi lại chúng. Giống như một cơ sở dữ liệu chấp nhận và truy xuất dữ liệu, một máy chủ nhắn tin tiếp nhận và chuyển phát tin nhắn. Một hệ thống nhắn tin là một máy chủ nhắn tin.
Một máy chủ cần có các khách hàng, và một ứng dụng sử dụng nhắn tin là một khách hàng của máy chủ nhắn tin. Nhưng các ứng dụng không nhất thiết phải biết cách trở thành khách hàng nhắn tin giống như chúng không biết cách trở thành khách hàng cơ sở dữ liệu. Máy chủ nhắn tin, giống như máy chủ cơ sở dữ liệu, có một API khách hàng mà ứng dụng có thể sử dụng để tương tác với máy chủ. API không cụ thể cho ứng dụng mà là đặc thù cho miền, nơi miền là nhắn tin. Ứng dụng phải chứa một tập hợp mã kết nối và hợp nhất miền nhắn tin với ứng dụng để cho phép ứng dụng thực hiện chức năng nhắn tin.
| Kết nối một ứng dụng với một kênh nhắn tin bằng cách sử dụng Điểm kết nối Tin nhắn, một khách hàng của hệ thống nhắn tin mà ứng dụng có thể sử dụng để gửi hoặc nhận Tin nhắn.
|
Mã endpoint thông điệp là tùy chỉnh cho cả ứng dụng và API khách hàng của hệ thống nhắn tin. Phần còn lại của ứng dụng biết rất ít về định dạng thông điệp, các kênh nhắn tin hoặc bất kỳ chi tiết nào khác của việc giao tiếp với các ứng dụng khác thông qua nhắn tin. Nó chỉ biết rằng nó có một yêu cầu hoặc một mảnh dữ liệu để gửi đến một ứng dụng khác, hoặc đang mong đợi những điều đó từ một ứng dụng khác. Đó là mã endpoint nhắn tin sẽ nhận lệnh hoặc dữ liệu đó, biến nó thành một thông điệp, và gửi nó đi qua một kênh nhắn tin cụ thể. Nó là endpoint sẽ nhận thông điệp, trích xuất nội dung, và cung cấp chúng cho ứng dụng một cách có ý nghĩa.
Điểm cuối tin nhắn bao gồm hệ thống nhắn tin từ phần còn lại của ứng dụng và tùy chỉnh một API nhắn tin chung cho một ứng dụng và nhiệm vụ cụ thể. Nếu một ứng dụng sử dụng một API nhắn tin cụ thể chuyển sang một API khác, các lập trình viên sẽ phải viết lại mã điểm cuối tin nhắn, nhưng phần còn lại của ứng dụng nên giữ nguyên. Nếu một phiên bản mới của hệ thống nhắn tin thay đổi API nhắn tin, điều này chỉ nên ảnh hưởng đến mã điểm cuối tin nhắn. Nếu ứng dụng quyết định giao tiếp với những ứng dụng khác qua một phương thức nào đó ngoài nhắn tin, các lập trình viên lý tưởng nên có khả năng viết lại mã điểm cuối tin nhắn nhưng để phần còn lại của ứng dụng không thay đổi.
Một Điểm Kết Nối Tin Nhắn có thể được sử dụng để gửi tin nhắn hoặc nhận chúng, nhưng một thể hiện không thực hiện cả hai. Một điểm kết nối là cụ thể cho kênh, vì vậy một ứng dụng đơn lẻ sẽ sử dụng nhiều điểm kết nối để giao tiếp với nhiều kênh. Một ứng dụng có thể sử dụng nhiều thể hiện điểm kết nối để giao tiếp với một kênh đơn lẻ, thường để hỗ trợ nhiều luồng đồng thời.
Một Điểm Kết Nối (Message Endpoint) là một Bô phận Kênh (Channel Adapter) chuyên biệt, được phát triển tùy chỉnh và tích hợp vào ứng dụng của nó.
Một Điểm Kết Nối nên được thiết kế như một Cổng Giao Tiếp để bao gồm mã giao tiếp và ẩn hệ thống nhắn tin khỏi phần còn lại của ứng dụng. Nó có thể sử dụng một Bộ Đồ Họa Nhắn Tin để chuyển dữ liệu giữa các đối tượng miền và thông điệp. Nó có thể được cấu trúc như một Bộ Kích Hoạt Dịch Vụ để cung cấp quyền truy cập nhắn tin không đồng bộ vào một dịch vụ hoặc cuộc gọi hàm đồng bộ. Một điểm kết nối có thể kiểm soát rõ ràng các giao dịch với hệ thống nhắn tin như một Khách Hàng Giao Dịch.
Gửi tin nhắn khá dễ dàng, vì vậy nhiều mẫu điểm cuối liên quan đến các phương pháp khác nhau để nhận tin nhắn. Một người nhận tin nhắn có thể là Một Người Tiêu Thụ Theo Kiểu Xét Nghiệm hoặc Một Người Tiêu Thụ Dựa Trên Sự Kiện. Nhiều người tiêu thụ có thể nhận tin nhắn từ cùng một kênh, hoặc là Những Người Tiêu Thụ Đối Kháng hoặc qua Một Trình Phân Phối Tin Nhắn. Một người nhận có thể quyết định tin nhắn nào để tiêu thụ hoặc bỏ qua bằng cách sử dụng Một Người Tiêu Thụ Chọn Lọc. Nó có thể sử dụng Một Người Đăng Ký Bền Bỉ để đảm bảo rằng một người đăng ký không bỏ lỡ tin nhắn được xuất bản trong khi điểm cuối bị ngắt kết nối. Và người tiêu thụ có thể là Một Người Nhận Đảm Bảo Đúng Mức Có Thể Xác Định Và Xử Lý Tin Nhắn Bị Nhân Đôi.
| Ví dụ: Nhà sản xuất và Người tiêu dùng JMS Trong JMS, hai loại điểm cuối chính là Nhà sản xuất Tin nhắn (MessageProducer), dùng để gửi tin nhắn, và Người tiêu thụ Tin nhắn (MessageConsumer), dùng để nhận tin nhắn. Một Điểm cuối Tin nhắn sử dụng một phiên bản của một trong hai loại này để gửi tin nhắn đến hoặc nhận tin nhắn từ một kênh cụ thể. |
| Ví dụ: .NET MessageQueue Trong .NET, lớp điểm cuối chính giống như lớp kênh tin nhắn chính, MessageQueue. Một Điểm Cuối Tin Nhắn sử dụng một thể hiện của MessageQueue để gửi tin nhắn đến hoặc nhận tin nhắn từ một kênh cụ thể. |
Giới thiệu
Kênh Điểm-Đến-Điểm
Kênh Xuất Bản-Đăng Ký
Kênh kiểu dữ liệu
Kênh tin nhắn không hợp lệ
Kênh thư chết
Giao hàng đảm bảo
Bộ điều hợp kênh
Cầu nhắn tin
Xe buýt Tin nhắn
Trong Chương 3, "Hệ thống Gửi tin nhắn", chúng ta đã thảo luận về Các Kênh Tin nhắn. Khi hai ứng dụng muốn trao đổi dữ liệu, chúng thực hiện bằng cách gửi dữ liệu qua một kênh kết nối giữa chúng. Ứng dụng gửi dữ liệu có thể không biết ứng dụng nào sẽ nhận dữ liệu. Tuy nhiên, bằng cách chọn một kênh cụ thể để gửi dữ liệu, người gửi biết rằng người nhận sẽ là một người đang tìm kiếm loại dữ liệu đó bằng cách tìm kiếm trên kênh đó. Bằng cách này, các ứng dụng sản xuất dữ liệu chia sẻ có cách để giao tiếp với những người muốn tiêu thụ nó.
Quyết định sử dụng kênh Tin nhắn là phần đơn giản; nếu một ứng dụng có dữ liệu cần truyền hoặc dữ liệu mà nó muốn nhận, nó sẽ phải sử dụng một kênh. Thách thức là biết ứng dụng của bạn cần những kênh nào và sử dụng chúng cho mục đích gì.
Tập hợp kênh cố định Một chủ đề được thảo luận trong chương này là tập hợp các Kênh Tin nhắn có sẵn cho một ứng dụng có xu hướng là tĩnh. Khi thiết kế một ứng dụng, nhà phát triển phải biết nơi đặt các loại dữ liệu nào để chia sẻ dữ liệu đó với các ứng dụng khác và cũng tương tự nơi tìm kiếm các loại dữ liệu cụ thể từ các ứng dụng khác. Những con đường giao tiếp này không thể được tạo và phát hiện động tại thời gian chạy; chúng cần được thống nhất lúc thiết kế để ứng dụng biết dữ liệu của nó đến từ đâu và đi đâu. (Dù đúng là hầu hết các kênh phải được định nghĩa tĩnh, vẫn có những ngoại lệ, các trường hợp mà kênh động là thiết thực và hữu ích. Một ngoại lệ là kênh trả lời trong Yêu cầu-Trả lời. Người yêu cầu có thể tạo hoặc lấy một kênh mới mà người trả lời không biết gì về và chỉ định nó là Địa chỉ Trả lại của một tin nhắn yêu cầu. Người trả lời sau đó có thể sử dụng nó. Một ngoại lệ khác là các triển khai hệ thống nhắn tin hỗ trợ các kênh phân cấp. Một người nhận có thể đăng ký với một cha trong phân cấp, và sau đó một người gửi có thể công bố lên một kênh con mới mà người nhận không biết gì về. Người đăng ký vẫn sẽ nhận được tin nhắn. Mặc dù những trường hợp tương đối không phổ biến này, các kênh thường được định nghĩa trước khi triển khai, và các ứng dụng được thiết kế xung quanh một tập hợp kênh đã biết.)
Xác định tập hợp các kênh Một vấn đề liên quan là, Ai quyết định các Kênh Tin nhắn nào có sẵn - hệ thống nhắn tin hay các ứng dụng? Nói cách khác, liệu hệ thống nhắn tin có xác định một số kênh nhất định và yêu cầu các ứng dụng phải làm quen với chúng không? Hay các ứng dụng tự xác định các kênh mà chúng cần và yêu cầu hệ thống nhắn tin cung cấp chúng? Không có câu trả lời đơn giản nào; thiết kế tập hợp các kênh cần thiết là một quá trình lặp đi lặp lại. Đầu tiên, các ứng dụng xác định các kênh mà hệ thống nhắn tin cần phải cung cấp. Các ứng dụng tiếp theo sẽ cố gắng thiết kế giao tiếp của chúng xung quanh các kênh có sẵn, nhưng khi điều này không thực tiễn, chúng sẽ yêu cầu thêm các kênh mới. Khi một tập hợp các ứng dụng đã sử dụng một tập hợp kênh nhất định, và các ứng dụng mới muốn tham gia, chúng cũng sẽ sử dụng tập hợp kênh hiện có. Khi các ứng dụng hiện có thêm chức năng mới, chúng có thể yêu cầu các kênh mới.
Kênh một chiều Một nguồn gây nhầm lẫn phổ biến khác là liệu một Kênh Tin nhắn có phải là một chiều hay hai chiều. Về mặt kỹ thuật, nó không phải là cả hai; một kênh giống như một cái xô mà một số ứng dụng thêm dữ liệu vào và các ứng dụng khác lấy dữ liệu ra (mặc dù đó là một cái xô được phân phối qua nhiều máy tính theo cách có sự phối hợp). Nhưng vì dữ liệu nằm trong các tin nhắn di chuyển từ ứng dụng này sang ứng dụng khác, điều đó tạo ra hướng cho kênh, khiến nó trở thành một chiều. Nếu một kênh là hai chiều, điều đó có nghĩa là một ứng dụng sẽ vừa gửi tin nhắn đến vừa nhận tin nhắn từ cùng một kênh, mà mặc dù về mặt kỹ thuật là có thể, nhưng điều đó không hợp lý vì ứng dụng sẽ có xu hướng tiếp tục tiêu thụ chính các tin nhắn của nó: các tin nhắn mà nó đã gửi đến các ứng dụng khác. Vì vậy, về mặt thực tế, các kênh là một chiều. Do đó, để hai ứng dụng có một cuộc trò chuyện hai chiều, họ cần hai kênh, một trong mỗi hướng (xem Yêu cầu-Phản hồi trong chương tiếp theo).
Bây giờ chúng ta đã hiểu các Kênh Tin nhắn là gì, hãy xem xét các quyết định liên quan đến việc sử dụng chúng.
Một-một hoặc một-nhiều Khi ứng dụng của bạn chia sẻ một mảnh dữ liệu, bạn có muốn chia sẻ nó với chỉ một ứng dụng khác hay với bất kỳ ứng dụng nào khác đang quan tâm? Để gửi dữ liệu đến một ứng dụng duy nhất, hãy sử dụng Kênh Điểm-đến-Điểm. Điều này không đảm bảo rằng mỗi mảnh dữ liệu được gửi trên kênh đó sẽ nhất thiết phải đến cùng một người nhận, vì kênh có thể có nhiều người nhận. Tuy nhiên, nó đảm bảo rằng bất kỳ mảnh dữ liệu nào sẽ chỉ được nhận bởi một trong những ứng dụng. Nếu bạn muốn tất cả các ứng dụng nhận có thể nhận dữ liệu, hãy sử dụng Kênh Xuất-Bản-Đăng-Ký. Khi bạn gửi một mảnh dữ liệu theo cách này, kênh sẽ hiệu quả sao chép dữ liệu cho mỗi người nhận.
Dữ liệu loại nào Bất kỳ dữ liệu nào trong bộ nhớ máy tính đều phải tuân theo một loại nào đó: một định dạng đã biết hoặc cấu trúc dự kiến với ý nghĩa đã được thống nhất. Nếu không, tất cả dữ liệu sẽ chỉ là một đống byte và không có cách nào để hiểu được điều đó. Các hệ thống nhắn tin hoạt động tương tự; nội dung tin nhắn phải tuân theo một loại nào đó để người nhận hiểu được cấu trúc dữ liệu. Kênh kiểu dữ liệu là ý tưởng rằng tất cả dữ liệu trên một kênh phải thuộc cùng loại. Đây là lý do chính khiến các hệ thống nhắn tin cần nhiều kênh. Nếu dữ liệu có thể thuộc bất kỳ loại nào, hệ thống nhắn tin chỉ cần một kênh (trong mỗi hướng) giữa hai ứng dụng bất kỳ.
Tin nhắn không hợp lệ và chết Hệ thống tin nhắn có thể đảm bảo rằng một tin nhắn được gửi đi một cách chính xác, nhưng nó không thể đảm bảo rằng người nhận sẽ biết phải làm gì với nó. Người nhận có những kỳ vọng về loại và ý nghĩa của dữ liệu. Khi nhận được một tin nhắn không đáp ứng những kỳ vọng này, không có nhiều điều nó có thể làm. Tuy nhiên, điều nó có thể làm là đặt tin nhắn lạ vào một Kênh Tin Nhắn Không Hợp Lệ được chỉ định đặc biệt với hy vọng rằng một công cụ giám sát kênh này sẽ tiếp nhận tin nhắn và tìm ra cách xử lý. Nhiều hệ thống nhắn tin có một tính năng tương tự được tích hợp sẵn, Kênh Thư Chết, cho các tin nhắn đã được gửi thành công nhưng cuối cùng không thể được gửi đi thành công. Một lần nữa, một tiện ích quản lý hệ thống nên giám sát Kênh Thư Chết và quyết định cách xử lý các tin nhắn không thể gửi đi.
Chống va chạm Nếu hệ thống nhắn tin gặp sự cố hoặc tạm ngừng để bảo trì, điều gì sẽ xảy ra với các tin nhắn của nó? Khi hệ thống hoạt động trở lại, các tin nhắn của nó có còn trong các kênh không? Mặc định, không; các kênh lưu trữ tin nhắn của chúng trong bộ nhớ. Tuy nhiên, Chuyển phát Đảm bảo làm cho các kênh trở nên bền vững để các tin nhắn của chúng được lưu trữ trên đĩa. Điều này làm giảm hiệu suất nhưng làm cho việc nhắn tin đáng tin cậy hơn, ngay cả khi hệ thống nhắn tin không hoạt động.
Khách hàng không phải là tin nhắn Điều gì sẽ xảy ra nếu một ứng dụng không thể kết nối với hệ thống nhắn tin nhưng vẫn muốn tham gia vào nhắn tin? Thường thì ứng dụng sẽ gặp khó khăn, nhưng nếu hệ thống nhắn tin có thể kết nối với ứng dụng bằng cách nào đó - thông qua giao diện người dùng của nó, API dịch vụ kinh doanh, cơ sở dữ liệu của nó, hoặc một kết nối mạng như TCP/IP hoặc HTTP - thì một Bộ chuyển đổi Kênh trên hệ thống nhắn tin có thể được sử dụng. Điều này cho phép bạn kết nối một kênh (hoặc một tập hợp các kênh) với ứng dụng mà không cần phải sửa đổi ứng dụng và có lẽ không cần một khách hàng nhắn tin chạy trên cùng một máy với ứng dụng. Đôi khi, "khách hàng không phải là tin nhắn" thực sự là một khách hàng nhắn tin, nhưng chỉ cho một hệ thống nhắn tin khác. Trong trường hợp đó, một ứng dụng là khách hàng trên cả hai hệ thống nhắn tin có thể xây dựng một Cầu Nhắn Tin giữa hai hệ thống, kết nối chúng thành một hệ thống nhắn tin tổng hợp.
Xương sống của hệ thống truyền thông Khi ngày càng nhiều ứng dụng của một doanh nghiệp kết nối với hệ thống nhắn tin và làm cho chức năng của chúng có sẵn qua nhắn tin, hệ thống nhắn tin trở thành một điểm tập trung cung cấp chức năng chia sẻ trong doanh nghiệp. Một ứng dụng mới chỉ cần biết các kênh nào để sử dụng để yêu cầu chức năng và các kênh nào khác để lắng nghe kết quả. Hệ thống nhắn tin về cơ bản trở thành một Bus Tin Nhắn, một xương sống cung cấp quyền truy cập vào tất cả các ứng dụng và chức năng khác nhau, luôn thay đổi của doanh nghiệp. Bạn có thể đạt được trạng thái tích hợp này nhanh chóng và dễ dàng hơn bằng cách thiết kế cụ thể cho nó từ đầu.
Như bạn có thể thấy, việc thiết lập ứng dụng cho Nhắn tin không chỉ đơn giản là kết nối chúng với hệ thống nhắn tin để gửi tin nhắn. Các tin nhắn phải có Kênh Tin Nhắn để truyền tải. Chỉ việc thêm vào một số kênh không đủ để hoàn thành công việc. Chúng phải được thiết kế với một mục đích, dựa trên kiểu dữ liệu được chia sẻ, loại ứng dụng cung cấp dữ liệu và loại ứng dụng nhận dữ liệu. Chương này giải thích những quyết định liên quan đến việc thiết kế các kênh này.
Để minh họa các mô hình, mỗi mô hình có một ví dụ từ lĩnh vực giao dịch cổ phiếu hư cấu, đơn giản hóa. Mặc dù không một ví dụ nào trong số này nên được sử dụng làm cơ sở để triển khai một hệ thống giao dịch thực, nhưng chúng thực sự là những ví dụ ngắn gọn và cụ thể về cách các mô hình có thể được sử dụng.
Một ứng dụng đang sử dụng Tin nhắn để thực hiện các cuộc gọi quy trình từ xa (RPCs) hoặc chuyển giao tài liệu.
| Người gọi có thể làm thế nào để chắc chắn rằng chỉ có một người nhận duy nhất sẽ nhận tài liệu hoặc thực hiện cuộc gọi? |
Một lợi thế của RPC là nó được gọi trên một quy trình từ xa duy nhất, vì vậy hoặc là người nhận thực hiện thủ tục hoặc không (và một ngoại lệ xảy ra). Và vì người nhận chỉ được gọi một lần, nên họ chỉ thực hiện thủ tục một lần. Nhưng với messaging, một khi một cuộc gọi được đóng gói thành một Thông điệp và đặt trên một Kênh Thông điệp, có thể nhiều người nhận thấy nó trên kênh và quyết định thực hiện thủ tục.
Hệ thống nhắn tin có thể ngăn chặn hơn một người nhận theo dõi một kênh duy nhất, nhưng điều này sẽ giới hạn không cần thiết đối với những người gọi muốn truyền dữ liệu đến nhiều người nhận. Tất cả các người nhận trên một kênh có thể phối hợp để đảm bảo rằng chỉ một trong số họ thực hiện quy trình, nhưng điều đó sẽ phức tạp, tạo ra nhiều chi phí giao tiếp và thường làm tăng sự kết nối giữa các người nhận vốn độc lập với nhau. Nhiều người nhận trên một kênh duy nhất có thể được mong muốn để nhiều tin nhắn có thể được tiêu thụ đồng thời, nhưng bất kỳ một người nhận nào cũng nên tiêu thụ bất kỳ tin nhắn nào.
| Gửi tin nhắn trên kênh Điểm đến Điểm, đảm bảo rằng chỉ có một người nhận sẽ nhận được một tin nhắn cụ thể.
|
Kênh Điểm đến Điểm đảm bảo rằng chỉ một người nhận tiêu thụ bất kỳ thông điệp nào. Kênh có thể có nhiều người nhận có thể tiêu thụ nhiều thông điệp đồng thời, nhưng chỉ có một trong số họ có thể thành công trong việc tiêu thụ một thông điệp cụ thể. Nếu nhiều người nhận cố gắng tiêu thụ một thông điệp duy nhất, kênh đảm bảo rằng chỉ một trong số họ thành công, vì vậy các người nhận không cần phải phối hợp với nhau.
Khi một kênh Point-to-Point chỉ có một người tiêu thụ, việc một tin nhắn chỉ được tiêu thụ một lần không có gì ngạc nhiên. Khi kênh có nhiều người tiêu thụ, thì họ trở thành Các Người Tiêu Thụ Cạnh Tranh, và kênh đảm bảo rằng chỉ một trong những người tiêu thụ nhận mỗi tin nhắn. Thiết kế này làm cho việc tiêu thụ và xử lý tin nhắn trở nên rất linh hoạt vì công việc đó có thể được phân bổ tải trọng qua nhiều người tiêu thụ đang chạy trên nhiều ứng dụng trên nhiều máy tính.
Trong khi bạn sử dụng Kênh Điểm-đến-Điểm để gửi tin nhắn đến chỉ một trong những người nhận có sẵn, để gửi tin nhắn đến tất cả những người nhận có sẵn, hãy sử dụng Kênh Xuất-bản-Đăng-ký. Để thực hiện các RPC sử dụng thông điệp, hãy sử dụng Yêu cầu-Trả lời với một cặp Kênh Điểm-đến-Điểm. Lời gọi là một Tin nhắn Lệnh, và phản hồi là một Tin nhắn Tài liệu.
| Ví dụ: Giao dịch chứng khoán Trong một hệ thống giao dịch chứng khoán, yêu cầu thực hiện một giao dịch cụ thể là một thông điệp cần được tiêu thụ và thực hiện bởi đúng một người nhận, vì vậy thông điệp đó nên được đặt trên một Kênh Điểm-đến-Điểm. |
| Ví dụ: JMS Queue Trong JMS, một kênh điểm-điểm triển khai giao diện Queue. Người gửi sử dụng QueueSender để gửi tin nhắn; mỗi người nhận sử dụng QueueReceiver riêng của mình để nhận tin nhắn [JMS 1.1], [Hapner]. Một ứng dụng sử dụng QueueSender để gửi một tin nhắn như thế này: [View full width] Queue queue = // obtain the queue via JNDI QueueConnectionFactory factory = // obtain the connection factory Một ứng dụng sử dụng QueueReceiver để nhận một tin nhắn như thế này: [View full width] Queue queue = // obtain the queue via JNDI QueueConnectionFactory factory = // obtain the connection factory LƯU Ý: JMS 1.1 thống nhất các API của khách hàng cho các miền điểm-đến-điểm và công bố-theo-dõi, vì vậy mã được hiển thị ở đây có thể được đơn giản hóa để sử dụng Đungh, NhàmáyKếtnối, Kếtnối, Phiên, Nhà sản xuất thông điệp và Người tiêu dùng thông điệp thay vì các đối tác cụ thể của Hàng đợi. |
| Ví dụ: .NET MessageQueue Trong .NET, lớp MessageQueue thực hiện một kênh điểm-đến-điểm [SysMsg]. MSMQ, thực hiện nhắn tin .NET, chỉ hỗ trợ nhắn tin điểm-đến-điểm trước phiên bản 3.0, vì vậy điểm-đến-điểm là những gì .NET hỗ trợ. Trong khi JMS tách biệt trách nhiệm của factory kết nối, kết nối, phiên, người gửi và hàng đợi, một MessageQueue thì làm tất cả. Gửi một tin nhắn trên MessageQueue như thế này: MessageQueue queue = new MessageQueue("MyQueue"); queue.Send("The contents of the message."); Nhận một tin nhắn trên hàng đợi tin nhắn như thế này: MessageQueue queue = new MessageQueue("MyQueue"); Message message = queue.Receive(); String contents = (String) message.Body(); |
Một ứng dụng đang sử dụng Nhắn tin để thông báo sự kiện.
| Người gửi có thể phát đi một sự kiện đến tất cả những người nhận quan tâm như thế nào? |
Rất may mắn, có những mẫu thiết kế đã được thiết lập tốt để thực hiện việc phát sóng. Mẫu Observer [GoF] mô tả sự cần thiết phải tách rời các quan sát viên khỏi đối tượng của chúng (tức là, nguồn gốc của sự kiện) để đối tượng có thể dễ dàng cung cấp thông báo sự kiện cho tất cả các quan sát viên quan tâm, bất kể có bao nhiêu quan sát viên (thậm chí không có ai). Mẫu Xuất bản-Đăng ký [POSA] mở rộng thêm về Observer bằng cách thêm khái niệm kênh sự kiện để giao tiếp thông báo sự kiện.
Đó là lý thuyết, nhưng nó hoạt động như thế nào với việc nhắn tin? Sự kiện có thể được đóng gói dưới dạng Tin nhắn để việc nhắn tin có thể truyền đạt đáng tin cậy sự kiện đến các người theo dõi (người đăng ký). Sau đó, kênh sự kiện là một Kênh Tin nhắn. Nhưng làm thế nào một kênh nhắn tin có thể truyền đạt đúng cách sự kiện đến tất cả các người đăng ký?
Mỗi người đăng ký cần được thông báo về một sự kiện cụ thể một lần nhưng không nên được thông báo lặp lại về cùng một sự kiện. Sự kiện không thể được coi là đã tiêu thụ cho đến khi tất cả các người đăng ký đã được thông báo, nhưng một khi họ đã nhận được thông báo, sự kiện có thể được coi là đã tiêu thụ và nên biến mất khỏi kênh. Tuy nhiên, việc để các người đăng ký phối hợp để xác định khi nào một tin nhắn đã được tiêu thụ sẽ vi phạm nguyên tắc tách rời của mẫu Observer. Các người tiêu thụ đồng thời không nên cạnh tranh mà nên có thể chia sẻ tin nhắn sự kiện.
| Gửi sự kiện trên kênh Xuất-Biên, kênh này sẽ cung cấp một bản sao của một sự kiện cụ thể đến mỗi người nhận.
|
Kênh Công Báo-Có Chọn hoạt động như sau: Nó có một kênh đầu vào chia thành nhiều kênh đầu ra, một cho mỗi người đăng ký. Khi một sự kiện được công bố vào kênh, Kênh Công Báo-Có Chọn sẽ gửi một bản sao của tin nhắn đến từng kênh đầu ra. Mỗi đầu ra của kênh chỉ có một người đăng ký, người này chỉ được phép tiêu thụ một bản tin nhắn một lần. Bằng cách này, mỗi người đăng ký nhận được tin nhắn chỉ một lần, và các bản sao đã được tiêu thụ sẽ biến mất khỏi các kênh của họ.
Kênh Publish-Subscribe có thể là một công cụ gỡ lỗi hữu ích. Mặc dù một thông điệp chỉ định đến một người nhận duy nhất, việc sử dụng Kênh Publish-Subscribe cho phép bạn nghe lén trên kênh thông điệp mà không làm gián đoạn luồng thông điệp hiện có. Giám sát toàn bộ lưu lượng trên một kênh có thể cực kỳ hữu ích khi gỡ lỗi các ứng dụng nhắn tin. Nó cũng có thể giúp bạn tránh phải chèn rất nhiều câu lệnh in vào mỗi ứng dụng tham gia vào giải pháp nhắn tin. Tạo một chương trình lắng nghe thông điệp trên tất cả các kênh hoạt động và ghi lại chúng vào tệp có thể cung cấp nhiều lợi ích tương tự như một Cửa hàng Thông điệp mang lại.
Tuy nhiên, khả năng nghe lén trên Kênh Xuất Bản - Đăng Ký cũng có thể trở thành một bất lợi. Nếu giải pháp nhắn tin của bạn truyền tải dữ liệu bảng lương giữa hệ thống bảng lương và hệ thống kế toán, bạn có thể không muốn cho phép bất kỳ ai viết một chương trình đơn giản để lắng nghe lưu lượng tin nhắn. Các Kênh Điểm-Đến-Điểm giải quyết vấn đề này phần nào: Bởi vì kẻ nghe lén sẽ tiêu thụ các tin nhắn từ kênh và tin nhắn sẽ đột nhiên biến mất, tình huống có thể được phát hiện rất nhanh chóng. Tuy nhiên, nhiều triển khai hàng đợi tin nhắn cung cấp chức năng xem cho phép người tiêu dùng nhìn vào các tin nhắn bên trong một hàng đợi mà không tiêu thụ bất kỳ tin nhắn nào. Kết quả là, việc đăng ký vào một Kênh Tin Nhắn là một hoạt động cần được hạn chế bởi các chính sách bảo mật. Nhiều (nhưng không phải tất cả) triển khai nhắn tin thương mại thực hiện những hạn chế như vậy. Ngoài ra, việc tạo ra một công cụ giám sát ghi lại các người đăng ký hoạt động vào các Kênh Tin Nhắn có thể là một công cụ quản lý hệ thống hữu ích.
Wildcard SubscribersNhiều hệ thống nhắn tin cho phép người đăng ký sử dụng các Kênh Xuất Bản - Đăng Ký để chỉ định các ký tự đại diện đặc biệt. Đây là một kỹ thuật mạnh mẽ cho phép người đăng ký đăng ký nhiều kênh cùng một lúc. Ví dụ, nếu một ứng dụng phát hành các tin nhắn tới các kênh MyCorp/Prod/OrderProcessing/NewOrders và MyCorp/Prod/OrderProcessing/CanceledOrders, một ứng dụng có thể đăng ký với MyCorp/Prod/OrderProcessing/* và nhận tất cả các tin nhắn liên quan đến quy trình đặt hàng. Một ứng dụng khác có thể đăng ký với MyCorp/Dev/** để nhận tất cả các tin nhắn được gửi bởi tất cả các ứng dụng trong môi trường phát triển. Chỉ có người đăng ký được phép sử dụng ký tự đại diện; người phát hành luôn phải phát hành một tin nhắn đến một kênh cụ thể. Các khả năng và cú pháp cụ thể cho người đăng ký ký tự đại diện khác nhau giữa các nhà cung cấp nhắn tin khác nhau. |
Một Thông điệp Sự kiện thường được gửi trên một Kênh Xuất bản-Đăng ký vì thường có nhiều phụ thuộc quan tâm đến một sự kiện. Một người đăng ký có thể là bền vững hoặc không bền vững - xem Người đăng ký bền vững trong Chương 10, "Điểm cuối Giao tiếp". Nếu các thông báo cần được xác nhận bởi các người đăng ký, hãy sử dụng Yêu cầu-Trả lời, trong đó thông báo là yêu cầu và xác nhận là phản hồi. Việc lưu trữ mỗi thông điệp trên một Kênh Xuất bản-Đăng ký cho đến khi tất cả các người đăng ký tiếp nhận thông điệp có thể yêu cầu một lượng lớn dung lượng lưu trữ thông điệp. Để giúp giảm bớt vấn đề này, các thông điệp gửi đến một Kênh Xuất bản-Đăng ký có thể sử dụng Thời gian Hết hiệu lực Thông điệp.
| Ví dụ: Giao dịch chứng khoán Trong một hệ thống giao dịch chứng khoán, nhiều hệ thống có thể cần được thông báo về sự hoàn tất của một giao dịch, vì vậy hãy làm cho tất cả chúng trở thành người đăng ký của một Kênh Xuất Bản - Đăng Ký để công bố các giao dịch đã hoàn tất. Tương tự, nhiều người tiêu dùng quan tâm đến việc hiển thị hoặc xử lý dữ liệu báo giá cổ phiếu hiện tại. Do đó, báo giá cổ phiếu nên được phát sóng qua một Kênh Xuất Bản-Đăng Ký. |
| Ví dụ: Chủ đề JMS Trong JMS, một Kênh Xuất-Bao gồm triển khai giao diện Chủ đề. Người gửi sử dụng TopicPublisher để gửi tin nhắn; mỗi người nhận sử dụng TopicSubscriber riêng của mình để nhận tin nhắn [JMS 1.1], [Hapner]. Một ứng dụng sử dụng TopicPublisher để gửi một tin nhắn giống như thế này: [View full width] Topic topic = // obtain the topic via JNDI TopicConnectionFactory factory = // obtain the connection factory Một ứng dụng sử dụng một TopicSubscriber để nhận một tin nhắn như thế này: [View full width] Topic topic = // obtain the topic via JNDI TopicConnectionFactory factory = // obtain the connection factory Lưu ý: JMS 1.1 hợp nhất các API client cho các miền point-to-point và publish-subscribe, vì vậy mã được hiển thị ở đây có thể được đơn giản hóa để sử dụng Destination, ConnectionFactory, Connection, Session, MessageProducer và MessageConsumer thay vì các đối tác cụ thể cho Topic. |
| Ví dụ: Nhắn tin One-to-Many qua MSMQ Một tính năng mới trong MSMQ 3.0 [MSMQ] là mô hình nhắn tin một-nhiều, có hai cách tiếp cận khác nhau.
.NET Common Language Runtime (CLR) không cung cấp hỗ trợ trực tiếp cho việc sử dụng mô hình thông điệp một-nhiều. Tuy nhiên, chức năng này có thể được truy cập thông qua giao diện COM [MDMSG], có thể được nhúng vào mã .NET. |
| Ví dụ: Nhắn tin đơn giản Ví dụ về JMS Publish-Subscribe trong Chương 6, "Chương giữa: Giao tiếp đơn giản," cho thấy một ví dụ về cách triển khai Observer trên nhiều tiến trình sử dụng nhắn tin. |
Một ứng dụng đang sử dụng Gửi tin nhắn để chuyển đổi các loại dữ liệu khác nhau, chẳng hạn như các loại tài liệu khác nhau.
| Làm thế nào để ứng dụng gửi một mục dữ liệu sao cho người nhận sẽ biết cách xử lý nó? |
Tất cả các thông điệp chỉ là những trường hợp của cùng một loại thông điệp, như được định nghĩa bởi hệ thống nhắn tin, và nội dung của bất kỳ thông điệp nào cuối cùng chỉ là một mảng byte. Mặc dù cấu trúc đơn giản này - một tập hợp các byte - đủ cụ thể để hệ thống nhắn tin có thể truyền tải một thông điệp, nhưng không đủ cụ thể để người nhận có thể xử lý nội dung của thông điệp.
Một bộ nhận phải biết cấu trúc dữ liệu và định dạng dữ liệu của nội dung thông điệp. Cấu trúc có thể là mảng ký tự, mảng byte, đối tượng đã tuần tự hóa, tài liệu XML, và những thứ khác. Định dạng có thể là cấu trúc bản ghi của các byte hoặc ký tự, lớp của đối tượng đã tuần tự hóa, định nghĩa lược đồ của tài liệu XML, và những thứ khác. Tất cả những kiến thức này thường được gọi là loại của thông điệp, ám chỉ cả cấu trúc và định dạng của nội dung thông điệp.
Người nhận phải biết loại tin nhắn nào đang nhận, nếu không họ sẽ không biết cách xử lý chúng. Ví dụ, một người gửi có thể muốn gửi các đối tượng khác nhau như đơn đặt hàng, báo giá và truy vấn. Tuy nhiên, người nhận có thể sẽ thực hiện các bước khác nhau để xử lý từng loại, vì vậy họ cần biết cái nào là cái nào. Nếu người gửi chỉ đơn giản gửi tất cả những điều này đến người nhận qua một kênh tin nhắn duy nhất, người nhận sẽ không biết cách xử lý từng cái.
Dữ liệu hỗn hợp

Người gửi biết loại tin nhắn nào mà mình đang gửi, vậy làm thế nào điều này có thể được truyền đạt đến người nhận? Người gửi có thể đặt một cờ trong tiêu đề của tin nhắn (xem Bộ chỉ báo định dạng), nhưng sau đó người nhận sẽ cần một câu lệnh điều kiện. Người gửi có thể bọc dữ liệu trong một Tin nhắn Lệnh với một lệnh khác nhau cho mỗi loại dữ liệu, nhưng điều này giả định việc cho người nhận biết phải làm gì với dữ liệu khi mà tất cả những gì mà tin nhắn đang cố gắng làm là truyền tải dữ liệu đến người nhận.
Một vấn đề tương tự, tách biệt với việc nhắn tin, xảy ra khi xử lý một bộ sưu tập các mục. Bộ sưu tập phải đồng nhất, nghĩa là tất cả các mục đều phải cùng loại, để bộ xử lý biết loại của mục đó và do đó biết cách thao tác với nó. Nhiều triển khai bộ sưu tập không bắt buộc tất cả các mục phải thuộc một loại nhất định, vì vậy các lập trình viên phải thiết kế mã của họ để đảm bảo rằng tất cả các mục trong bộ sưu tập đều cùng loại. Nếu không, các mục khác loại có thể được thêm vào bộ sưu tập, nhưng mã xử lý những mục đó sẽ không biết cách thao tác với từng mục vì nó không biết loại của một mục cụ thể nào đó.
Nguyên tắc tương tự cũng áp dụng cho việc nhắn tin, vì các tin nhắn trên một kênh cũng phải cùng loại. Giải pháp đơn giản nhất là tất cả các tin nhắn phải có cùng một định dạng. Nếu các định dạng phải khác nhau, chúng phải có một chỉ báo định dạng đáng tin cậy. Mặc dù kênh không buộc tất cả các tin nhắn phải cùng loại, nhưng người nhận cần chúng phải như vậy để biết cách xử lý chúng.
| Sử dụng một Kênh Kiểu Dữ liệu riêng biệt cho mỗi loại dữ liệu để tất cả dữ liệu trên một kênh cụ thể đều cùng loại.
|
Bằng cách sử dụng một Kênh Kiểu dữ liệu riêng biệt cho mỗi loại dữ liệu, tất cả các thông điệp trên một kênh nhất định sẽ chứa cùng một loại dữ liệu. Người gửi, biết loại dữ liệu là gì, sẽ cần chọn kênh phù hợp để gửi nó đi. Người nhận, biết kênh mà dữ liệu được nhận, sẽ biết nó là loại nào.
Như được trình bày trong các hình, vì người gửi muốn gửi ba loại dữ liệu khác nhau (đơn đặt hàng, báo giá và truy vấn), nên họ cần sử dụng ba kênh khác nhau. Khi gửi một mục, người gửi phải chọn Kênh Dữ liệu phù hợp cho mục đó. Khi nhận một mục, người nhận biết loại của mục đó nhờ vào kênh dữ liệu mà họ đã nhận mục đó.
Quality-of-Service ChannelMột chiến lược liên quan là Kênh Chất lượng Dịch vụ. Đôi khi, một doanh nghiệp muốn truyền tải một nhóm tin nhắn với một mức độ dịch vụ khác với nhóm tin nhắn còn lại. Ví dụ, các tin nhắn Đơn hàng mới đến có thể là nguồn doanh thu chính cho một doanh nghiệp và nên được truyền tải qua một kênh rất đáng tin cậy (ví dụ: sử dụng Giao hàng Đảm bảo) bất chấp việc có thể gặp phải chi phí hiệu suất. Mặt khác, việc mất một tin nhắn đại diện cho yêu cầu trạng thái đơn hàng không phải là thảm họa, vì vậy chúng ta có thể có xu hướng sử dụng một kênh nhanh hơn nhưng ít đáng tin cậy hơn. Điều này đôi khi có thể đạt được trên một kênh duy nhất, chẳng hạn như bằng cách sử dụng các mức độ ưu tiên của tin nhắn. Tuy nhiên, nói chung, ý tưởng tốt hơn là xác định các tham số chất lượng dịch vụ khi tạo ra kênh, thay vì để quyết định này phụ thuộc vào mã ứng dụng gửi tin nhắn. Do đó, tốt nhất là truyền tải mỗi nhóm tin nhắn trên một kênh riêng biệt để từng kênh có thể được điều chỉnh chất lượng dịch vụ phù hợp với nhu cầu của nhóm tin nhắn đó. |
Như đã thảo luận trong Kênh Tin nhắn, các kênh thì rẻ, nhưng không miễn phí. Một ứng dụng có thể cần truyền tải nhiều loại dữ liệu khác nhau, quá nhiều để tạo một Kênh Loại Dữ liệu riêng cho mỗi loại. Trong trường hợp này, nhiều loại dữ liệu có thể chia sẻ một kênh duy nhất bằng cách sử dụng một Người Tiêu thụ Chọn lọc khác nhau cho từng loại. Điều này làm cho một kênh vật lý đơn lẻ hoạt động giống như nhiều Kênh Loại Dữ liệu logic (một chiến lược gọi là đa tuyến). Trong khi Kênh Loại Dữ liệu giải thích lý do tại sao tất cả các tin nhắn trên một kênh phải có cùng định dạng, Mô hình Dữ liệu Canonical giải thích cách mà tất cả các tin nhắn trên tất cả các kênh trong một doanh nghiệp nên tuân theo một mô hình dữ liệu thống nhất.
Nếu chúng ta muốn sử dụng Kênh Dữ liệu nhưng một nhà phát hành thông điệp hiện có chỉ gửi tất cả thông điệp đến một kênh duy nhất, chúng ta có thể sử dụng Bộ định tuyến Dựa trên Nội dung để phân tách các thông điệp. Bộ định tuyến sẽ chia dòng thông điệp thành nhiều Kênh Dữ liệu, mỗi kênh chỉ mang thông điệp của một loại duy nhất.
Một Trình Gửi Thông Điệp, bên cạnh việc cung cấp khả năng tiêu thụ thông điệp đồng thời, có thể được sử dụng để xử lý một tập hợp các thông điệp chung theo những cách cụ thể theo loại. Mỗi thông điệp phải chỉ định loại của nó (thông thường bằng cách chỉ định định dạng trong phần đầu của thông điệp); trình gửi phát hiện loại của thông điệp và chuyển tiếp nó đến một người thực hiện cụ thể để xử lý. Các thông điệp trên kênh vẫn đều thuộc cùng một loại, nhưng loại đó là loại tổng quát hơn mà trình gửi hỗ trợ, không phải các loại cụ thể hơn mà các người thực hiện khác nhau yêu cầu.
Một chỉ báo định dạng được sử dụng để phân biệt các phiên bản định dạng khác nhau của cùng một dữ liệu, điều này cho phép các định dạng khác nhau này được gửi trên cùng một kênh kiểu dữ liệu.
| Ví dụ: Giao dịch chứng khoán Trong một hệ thống giao dịch chứng khoán, nếu định dạng của yêu cầu báo giá khác với yêu cầu giao dịch, hệ thống nên sử dụng một Kênh Loại Dữ liệu riêng biệt để truyền thông cho mỗi loại yêu cầu. Tương tự, một thông báo thay đổi địa chỉ có thể có định dạng khác với thông báo thay đổi quản lý danh mục đầu tư, vì vậy mỗi loại thông báo nên có Kênh Loại Dữ liệu riêng của nó. |
Một ứng dụng đang sử dụng Messaging để nhận Tin nhắn.
| Người nhận tin nhắn có thể xử lý một cách khéo léo việc nhận một tin nhắn không có ý nghĩa như thế nào? |
Về lý thuyết, mọi thứ trên một Kênh Thông điệp chỉ đơn giản là một thông điệp, và những người nhận thông điệp chỉ xử lý các thông điệp. Tuy nhiên, để xử lý một thông điệp, người nhận phải có khả năng giải thích dữ liệu của nó và hiểu được ý nghĩa của nó. Điều này không phải lúc nào cũng có thể: thân thông điệp có thể gây ra lỗi phân tích, lỗi từ vựng, hoặc lỗi xác thực. Tiêu đề thông điệp có thể thiếu các thuộc tính cần thiết, hoặc các giá trị thuộc tính có thể không hợp lệ. Một người gửi có thể gửi một thông điệp hoàn toàn tốt nhưng không đúng kênh, truyền đạt nó đến người nhận sai. Một người gửi ác ý có thể cố tình gửi một thông điệp không chính xác chỉ để làm rối loạn người nhận. Một người nhận có thể không thể xử lý tất cả các thông điệp mà họ nhận được, vì vậy họ cần một cách khác để xử lý những thông điệp mà họ không coi là hợp lệ.
Kênh Tin nhắn nên là một Kênh Kiểu Dữ liệu, trong đó mỗi tin nhắn trên kênh đó sẽ phải có kiểu dữ liệu phù hợp với kênh đó. Nếu một người gửi đưa một tin nhắn lên kênh mà không phải là kiểu dữ liệu đúng, hệ thống nhắn tin sẽ truyền tải tin nhắn thành công, nhưng người nhận sẽ không nhận ra tin nhắn và sẽ không biết cách xử lý nó.
Một ví dụ về một thông điệp có kiểu dữ liệu hoặc định dạng không đúng là một thông điệp byte trên một kênh được cho là chứa thông điệp văn bản. Một ví dụ khác là một thông điệp có định dạng không chính xác, chẳng hạn như một tài liệu XML không được cấu trúc tốt hoặc không hợp lệ với DTD hoặc lược đồ đã thỏa thuận. Không có gì sai với những thông điệp này về mặt hệ thống nhắn tin, nhưng người nhận sẽ không thể xử lý chúng, vì vậy chúng không hợp lệ.
Các tin nhắn không chứa các giá trị trường tiêu đề mà người nhận mong đợi cũng được coi là không hợp lệ. Nếu một tin nhắn được dự kiến có các thuộc tính tiêu đề như Một Định danh Sự liên hệ, Định danh Chuỗi tin nhắn, Địa chỉ Trả lại, v.v., nhưng tin nhắn lại thiếu các thuộc tính đó, thì hệ thống nhắn tin sẽ chuyển phát tin nhắn một cách đúng đắn, nhưng người nhận sẽ không thể xử lý thành công.
Thông điệp không hợp lệ

Khi bộ nhận phát hiện rằng thông điệp mà nó đang cố xử lý không hợp lệ, nó nên làm gì với thông điệp đó? Nó có thể đưa thông điệp trở lại kênh, nhưng sau đó thông điệp sẽ chỉ bị tiêu thụ lại bởi cùng một bộ nhận hoặc một bộ nhận khác giống như vậy. Trong khi đó, những thông điệp không hợp lệ bị bỏ qua sẽ làm rối loạn kênh và ảnh hưởng đến hiệu suất. Bộ nhận có thể tiêu thụ thông điệp không hợp lệ và vứt bỏ nó, nhưng điều đó sẽ có xu hướng che giấu những vấn đề liên quan đến thông điệp cần được phát hiện. Những gì hệ thống cần là một cách để làm sạch các thông điệp không đúng khỏi các kênh và đưa chúng đến một nơi mà chúng sẽ không gây trở ngại nhưng có thể được phát hiện để chẩn đoán các vấn đề với hệ thống thông điệp.
| Người nhận nên chuyển tin nhắn không hợp lệ vào Kênh Tin Nhắn Không Hợp Lệ, một kênh đặc biệt cho các tin nhắn không thể được xử lý bởi người nhận của chúng.
|
Khi thiết kế một hệ thống nhắn tin cho các ứng dụng sử dụng, người quản trị phải xác định một hoặc nhiều Kênh Tin Nhắn Không Hợp Lệ cho các ứng dụng sử dụng. Kênh Tin Nhắn Không Hợp Lệ sẽ không được sử dụng cho giao tiếp bình thường, thành công, vì vậy nếu nó bị lộn xộn với các tin nhắn không chính xác, điều đó sẽ không thành vấn đề. Một trình xử lý lỗi muốn chẩn đoán các tin nhắn không chính xác có thể sử dụng một bộ nhận trên kênh không hợp lệ để phát hiện tin nhắn khi chúng trở nên có sẵn.
Kênh tin nhắn không hợp lệ giống như một nhật ký lỗi cho việc nhắn tin. Khi có sự cố xảy ra trong một ứng dụng, việc ghi lại lỗi là một ý tưởng hay. Khi có sự cố xảy ra trong quá trình xử lý một tin nhắn, tốt nhất nên gửi tin nhắn vào kênh dành cho các tin nhắn không hợp lệ. Nếu không rõ ràng với bất kỳ ai duyệt kênh lý do tại sao tin nhắn này không hợp lệ, ứng dụng cũng nên ghi lại một lỗi với nhiều chi tiết hơn.
Hãy nhớ rằng một thông điệp không tự nó hợp lệ hay không hợp lệ, mà chính bối cảnh và mong đợi của người nhận mới quyết định điều này. Một thông điệp có thể hợp lệ đối với một người nhận nhưng lại không hợp lệ đối với một người nhận khác; hai người nhận như vậy không nên chia sẻ cùng một kênh. Một thông điệp hợp lệ cho một người nhận trên một kênh nên cũng hợp lệ cho tất cả những người nhận khác trên kênh đó. Tương tự, nếu một người nhận cho rằng một thông điệp là không hợp lệ, thì tất cả những người nhận khác cũng nên nghĩ như vậy. Trách nhiệm của người gửi là đảm bảo rằng một thông điệp mà họ gửi trên một kênh sẽ được coi là hợp lệ bởi những người nhận trên kênh đó. Nếu không, những người nhận sẽ bỏ qua thông điệp của người gửi bằng cách chuyển chúng đến Kênh Thông Điệp Không Hợp Lệ.
Một vấn đề tương tự nhưng riêng biệt xảy ra khi một thông điệp được cấu trúc đúng cách, nhưng nội dung của nó lại sai về mặt ngữ nghĩa. Ví dụ, một Thông điệp Lệnh có thể chỉ dẫn người nhận xóa một bản ghi trong cơ sở dữ liệu không tồn tại. Đây không phải là một lỗi trong thông điệp mà là một lỗi trong ứng dụng. Do đó, mặc dù có thể bị cám dỗ để chuyển thông điệp sang Kênh Thông điệp Không hợp lệ, nhưng không có gì sai với thông điệp này, vì vậy việc coi nó là không hợp lệ là gây hiểu lầm. Thay vào đó, một lỗi như vậy nên được xử lý như một yêu cầu ứng dụng không hợp lệ, chứ không phải là một thông điệp không hợp lệ.
Sự khác biệt giữa lỗi xử lý tin nhắn và lỗi ứng dụng trở nên đơn giản và rõ ràng hơn khi bộ nhận được triển khai dưới dạng Bộ Kích Hoạt Dịch Vụ hoặc Cổng Thông Tin Nhắn. Những mẫu này tách biệt mã xử lý tin nhắn khỏi phần còn lại của ứng dụng. Nếu một lỗi xảy ra trong quá trình xử lý tin nhắn, tin nhắn đó sẽ không hợp lệ và nên được chuyển đến Kênh Tin Nhắn Không Hợp Lệ. Nếu lỗi xảy ra trong khi ứng dụng xử lý dữ liệu từ tin nhắn, đó là lỗi ứng dụng không liên quan gì đến việc nhắn tin.
Một Kênh Tin Nhắn Không Hợp Lệ có nội dung bị bỏ qua vô bổ như một nhật ký lỗi bị phớt lờ. Các thông điệp trên Kênh Tin Nhắn Không Hợp Lệ chỉ ra các vấn đề tích hợp ứng dụng, vì vậy những thông điệp này không nên bị bỏ qua; thay vào đó, chúng nên được phân tích để xác định điều gì đã sai để có thể khắc phục vấn đề. Lý tưởng nhất, đây sẽ là một quy trình tự động tiêu thụ các thông điệp không hợp lệ, xác định nguyên nhân của chúng và khắc phục các vấn đề cơ bản. Tuy nhiên, nguyên nhân thường là lỗi lập trình hoặc cấu hình cần một lập trình viên hoặc nhà phân tích hệ thống đánh giá và sửa chữa. Ít nhất, các ứng dụng sử dụng tin nhắn và Kênh Tin Nhắn Không Hợp Lệ nên có một quy trình giám sát Kênh Tin Nhắn Không Hợp Lệ và thông báo cho các quản trị viên hệ thống bất cứ khi nào kênh chứa các thông điệp.
Một khái niệm tương tự được nhiều hệ thống nhắn tin triển khai là Kênh Thư Chết. Trong khi Kênh Thư Không Hợp Lệ dành cho các tin nhắn có thể được giao và nhận nhưng không thể xử lý, Kênh Thư Chết dành cho các tin nhắn mà hệ thống nhắn tin không thể giao đúng cách.
| Ví dụ: Giao dịch chứng khoán Trong một hệ thống giao dịch chứng khoán, một ứng dụng để thực hiện các yêu cầu giao dịch có thể nhận được yêu cầu về báo giá giá hiện tại, hoặc một yêu cầu giao dịch không xác định chứng khoán nào để mua hoặc không xác định số lượng cổ phiếu, hoặc một yêu cầu giao dịch không xác định ai là người nhận xác nhận giao dịch. Trong bất kỳ trường hợp nào, ứng dụng đã nhận được một thông điệp không hợp lệ - một thông điệp không đáp ứng các yêu cầu tối thiểu cần thiết để ứng dụng có thể xử lý yêu cầu giao dịch. Khi ứng dụng xác định thông điệp là không hợp lệ, nó nên gửi lại thông điệp vào Kênh Thông điệp Không hợp lệ. Các ứng dụng khác nhau gửi yêu cầu giao dịch có thể muốn theo dõi Kênh Thông điệp Không hợp lệ để xác định xem các yêu cầu của họ có bị loại bỏ hay không. |
| Ví dụ: Đặc tả JMS Trong JMS, tài liệu quy định gợi ý rằng nếu một MessageListener nhận được một tin nhắn mà nó không thể xử lý, một listener hoạt động tốt nên chuyển hướng tin nhắn "đến một dạng 'điểm đến tin nhắn không thể xử lý' cụ thể cho ứng dụng nào đó" [JMS 1.1]. Điểm đến tin nhắn không thể xử lý này là một Kênh Tin Nhắn Không Hợp Lệ. |
| Ví dụ: Nhắn tin đơn giản Ví dụ về yêu cầu-phản hồi JMS và ví dụ yêu cầu-phản hồi .NET (cả hai đều trong Chương 6, "Giữa chừng: Nhắn tin đơn giản") cho thấy một ví dụ về cách triển khai các bộ thu nhận chuyển tiếp tin nhắn mà họ không thể xử lý đến Kênh Tin nhắn Không hợp lệ. |
Một doanh nghiệp đang sử dụng Giao tiếp để tích hợp các ứng dụng.
| Hệ thống nhắn tin sẽ làm gì với một tin nhắn mà nó không thể gửi đi? |
Nếu một bộ nhận nhận được một tin nhắn mà nó không thể xử lý, nó nên chuyển tin nhắn không hợp lệ đến Kênh Tin Nhắn Không Hợp Lệ. Nhưng điều gì sẽ xảy ra nếu hệ thống nhắn tin không thể gửi tin nhắn đến bộ nhận ngay từ đầu?
Có một số lý do khiến hệ thống nhắn tin có thể không gửi được một tin nhắn. Hệ thống nhắn tin có thể không cấu hình đúng kênh của tin nhắn. Kênh của tin nhắn có thể đã bị xóa sau khi tin nhắn được gửi nhưng trước khi nó có thể được giao, hoặc trong khi nó đang chờ nhận. Tin nhắn có thể hết hạn trước khi nó có thể được giao (xem Hết hạn tin nhắn). Một tin nhắn không có thời gian hết hạn rõ ràng vẫn có thể hết hạn nếu nó không thể được giao trong một thời gian rất dài. Một tin nhắn có giá trị lựa chọn mà tất cả Người tiêu thụ chọn lọc đều bỏ qua sẽ không bao giờ được đọc và có thể cuối cùng sẽ chết. Một tin nhắn có thể có điều gì đó sai với tiêu đề của nó khiến nó không được giao thành công.
Khi hệ thống nhắn tin xác định rằng không thể gửi một tin nhắn, nó phải thực hiện một số hành động với tin nhắn đó. Nó có thể để lại tin nhắn ở đó, làm rối hệ thống. Nó có thể cố gắng trả lại tin nhắn cho người gửi, nhưng người gửi không phải là người nhận và không thể phát hiện việc giao hàng. Nó có thể chỉ xóa tin nhắn và hy vọng không ai thiếu nó, nhưng điều này có thể gây ra vấn đề cho người gửi đã gửi tin nhắn thành công và mong đợi nó được giao (và nhận và xử lý).
| Khi một hệ thống nhắn tin xác định rằng nó không thể hoặc không nên giao một tin nhắn, nó có thể quyết định chuyển tin nhắn đó đến Kênh Chết.
|
Cách thức cụ thể mà Kênh Thư Chết hoạt động phụ thuộc vào thực hiện của hệ thống nhắn tin cụ thể, nếu nó cung cấp một cái nào đó. Kênh này có thể được gọi là "hàng đợi tin nhắn chết" [Monson-Haefel] hoặc "hàng đợi thư chết" [MQSeries], [Dickman]. Thông thường, mỗi máy mà hệ thống nhắn tin được cài đặt sẽ có Kênh Thư Chết cục bộ của riêng nó, để bất kể máy nào mà tin nhắn chết, nó có thể được chuyển từ hàng đợi cục bộ này sang hàng đợi cục bộ khác mà không có sự không chắc chắn về mạng. Điều này cũng ghi lại máy mà tin nhắn đã chết. Khi hệ thống nhắn tin di chuyển tin nhắn, nó cũng có thể ghi lại kênh ban đầu mà tin nhắn dự kiến được gửi tới.
Sự khác biệt giữa một tin nhắn chết và một tin nhắn không hợp lệ là hệ thống nhắn tin không thể giao thành công cái mà nó coi là tin nhắn chết, trong khi một tin nhắn không hợp lệ được giao đúng cách nhưng không thể được xử lý bởi người nhận. Việc xác định xem một tin nhắn có nên được chuyển đến Kênh Tin Nhắn Chết hay không là một sự đánh giá về tiêu đề của tin nhắn được thực hiện bởi hệ thống nhắn tin. Mặt khác, người nhận chuyển một tin nhắn đến Kênh Tin Nhắn Không Hợp Lệ do phần thân của tin nhắn hoặc các trường tiêu đề cụ thể mà người nhận quan tâm. Đối với người nhận, việc xác định và xử lý các tin nhắn chết có vẻ tự động, trong khi người nhận phải tự xử lý các tin nhắn không hợp lệ. Một nhà phát triển sử dụng hệ thống nhắn tin bị mắc kẹt với bất kỳ việc xử lý tin nhắn chết nào mà hệ thống nhắn tin cung cấp, nhưng cô ấy có thể thiết kế việc xử lý tin nhắn không hợp lệ của riêng mình, bao gồm cả việc xử lý cho các tin nhắn có vẻ như đã chết mà hệ thống nhắn tin không xử lý.
| Ví dụ: Giao dịch chứng khoán Trong một hệ thống giao dịch chứng khoán, một ứng dụng muốn thực hiện giao dịch có thể gửi một yêu cầu giao dịch. Để đảm bảo rằng yêu cầu giao dịch được nhận trong khoảng thời gian hợp lý (có thể là dưới năm phút), người gửi yêu cầu thiết lập Thời gian Hết Hạn của yêu cầu là năm phút. Nếu hệ thống nhắn tin không thể chuyển phát yêu cầu trong khoảng thời gian đó, hoặc nếu ứng dụng giao dịch không nhận được tin nhắn (ví dụ: đọc từ kênh) kịp thời, thì hệ thống nhắn tin sẽ gỡ bỏ tin nhắn khỏi kênh yêu cầu giao dịch và đưa tin nhắn vào Kênh Chết. Hệ thống giao dịch có thể muốn theo dõi các Kênh Chết của hệ thống để xác định xem nó có bỏ lỡ giao dịch nào không. |
Một doanh nghiệp đang sử dụng Tin nhắn để tích hợp các ứng dụng.
| Người gửi làm thế nào để đảm bảo rằng một tin nhắn sẽ được gửi đi ngay cả khi hệ thống nhắn tin gặp sự cố? |
Một trong những lợi thế chính của việc nhắn tin bất đồng bộ so với RPC là người gửi, người nhận và mạng kết nối hai bên không nhất thiết phải hoạt động đồng thời. Nếu mạng không khả dụng, hệ thống nhắn tin sẽ lưu trữ thông điệp cho đến khi mạng trở nên khả dụng. Tương tự, nếu người nhận không khả dụng, hệ thống nhắn tin sẽ lưu trữ thông điệp và thử lại việc giao hàng cho đến khi người nhận trở nên khả dụng. Đây là quy trình lưu trữ và chuyển tiếp mà nhắn tin dựa vào. Vậy, thông điệp nên được lưu trữ ở đâu trước khi được chuyển tiếp?
Theo mặc định, hệ thống nhắn tin lưu trữ tin nhắn trong bộ nhớ cho đến khi nó có thể chuyển tiếp tin nhắn thành công đến điểm lưu trữ tiếp theo. Điều này hoạt động miễn là hệ thống nhắn tin đang chạy ổn định, nhưng nếu hệ thống nhắn tin gặp sự cố (ví dụ, vì một trong những máy tính của nó mất điện hoặc quá trình nhắn tin dừng lại một cách bất ngờ), tất cả các tin nhắn được lưu trữ trong bộ nhớ sẽ bị mất.
Hầu hết các ứng dụng phải đối mặt với những vấn đề tương tự. Tất cả dữ liệu được lưu trữ trong bộ nhớ sẽ bị mất nếu ứng dụng gặp sự cố. Để ngăn chặn điều này, các ứng dụng sử dụng tệp và cơ sở dữ liệu để lưu trữ dữ liệu xuống đĩa để dữ liệu tồn tại sau các sự cố hệ thống. Các hệ thống nhắn tin cũng cần một cách tương tự để lưu trữ các tin nhắn một cách lâu bền hơn để không có tin nhắn nào bị mất ngay cả khi hệ thống gặp sự cố.
| Sử dụng Giao hàng Đảm bảo để làm cho tin nhắn trở nên bền vững, để chúng không bị mất ngay cả khi hệ thống nhắn tin gặp sự cố.
|
Với Chế độ Giao hàng Đảm bảo, hệ thống nhắn tin sử dụng một kho dữ liệu tích hợp để lưu trữ các tin nhắn. Mỗi máy tính mà hệ thống nhắn tin được cài đặt đều có kho dữ liệu riêng để các tin nhắn có thể được lưu trữ cục bộ. Khi người gửi gửi một tin nhắn, thao tác gửi sẽ không hoàn thành thành công cho đến khi tin nhắn được lưu trữ an toàn trong kho dữ liệu của người gửi. Sau đó, tin nhắn sẽ không bị xóa khỏi một kho dữ liệu cho đến khi nó được chuyển tiếp thành công và lưu trữ trong kho dữ liệu tiếp theo. Bằng cách này, một khi người gửi gửi thành công tin nhắn, nó sẽ luôn được lưu trữ trên đĩa trên ít nhất một máy tính cho đến khi nó được giao thành công và được xác nhận bởi người nhận.
Sự kiên trì làm tăng độ tin cậy nhưng đánh đổi bằng hiệu suất. Do đó, nếu việc mất tin nhắn khi hệ thống nhắn tin gặp sự cố hoặc bị tắt là chấp nhận được, hãy tránh sử dụng Giao hàng Đảm bảo để tin nhắn có thể di chuyển qua hệ thống nhắn tin nhanh hơn.
Cũng cần lưu ý rằng việc Đảm bảo Giao hàng có thể tiêu tốn một lượng lớn dung lượng đĩa trong các tình huống có lưu lượng truy cập cao. Nếu một nhà sản xuất tạo ra hàng trăm hoặc hàng nghìn tin nhắn mỗi giây, thì một sự cố mạng kéo dài nhiều giờ có thể chiếm dụng một lượng lớn dung lượng đĩa. Bởi vì mạng không khả dụng, các tin nhắn phải được lưu trữ trên ổ đĩa cục bộ của máy tính sản xuất, mà có thể không được thiết kế để chứa đựng lượng dữ liệu này. Vì những lý do này, một số hệ thống nhắn tin cho phép bạn cấu hình tham số thời gian chờ thử lại, xác định thời gian các tin nhắn được lưu trữ bên trong hệ thống nhắn tin. Trong một số ứng dụng có lưu lượng truy cập cao (ví dụ, phát streaming cot cổ phiếu đến các thiết bị đầu cuối), thời gian chờ này có thể phải được đặt ở một khoảng thời gian ngắn, chẳng hạn như vài phút. May mắn thay, trong nhiều ứng dụng này, các tin nhắn được sử dụng như Tin nhắn Sự kiện và có thể an toàn bị loại bỏ sau khi một khoảng thời gian ngắn trôi qua (xem Hết hạn Tin nhắn).
Nó cũng có thể hữu ích khi tắt Chế độ Giao hàng Đảm bảo trong quá trình thử nghiệm và gỡ lỗi. Điều này giúp dễ dàng xóa tất cả các kênh tin nhắn bằng cách dừng và khởi động lại máy chủ tin nhắn. Các tin nhắn vẫn còn trong hàng đợi có thể làm cho việc gỡ lỗi ngay cả những chương trình tin nhắn đơn giản trở nên rất tẻ nhạt. Ví dụ, bạn có thể có một người gửi và một người nhận kết nối qua Kênh Điểm-đến-Điểm. Nếu một tin nhắn vẫn được lưu trữ trên kênh, người nhận sẽ xử lý tin nhắn đó trước bất kỳ tin nhắn mới nào mà người gửi sản xuất. Đây là một cạm bẫy gỡ lỗi phổ biến trong hệ thống nhắn tin không đồng bộ và được đảm bảo. Nhiều bản triển khai nhắn tin thương mại cũng cho phép bạn xóa hàng đợi một cách riêng lẻ để cho phép khởi động lại một cách mới trong quá trình thử nghiệm (xem Bộ xóa Kênh).
How Guaranteed Is Guaranteed Messaging?Điều quan trọng là cần nhớ rằng độ tin cậy trong các hệ thống máy tính thường được đo bằng "số 9", hay nói cách khác, 99,9%. Điều này cho thấy rằng điều gì đó hiếm khi là 100% tin cậy, với chi phí đã tăng theo cấp số nhân khi di chuyển từ 99,9% lên 99,99%. Các cảnh báo tương tự cũng áp dụng cho Giao hàng Được Đảm bảo. Sẽ luôn có một kịch bản mà tại đó một thông điệp có thể bị mất. Ví dụ, nếu ổ đĩa lưu trữ các thông điệp đã được lưu trữ bị hỏng, các thông điệp có thể bị mất. Bạn có thể làm cho không gian lưu trữ của mình đáng tin cậy hơn bằng cách sử dụng lưu trữ ổ đĩa dư thừa để giảm khả năng hỏng hóc. Điều này có thể thêm một "9" nữa vào đánh giá độ tin cậy nhưng có thể không khiến nó trở thành 100% thật sự. Ngoài ra, nếu mạng không khả dụng trong một thời gian dài, các thông điệp cần phải được lưu trữ có thể lấp đầy ổ đĩa của máy tính, dẫn đến mất thông điệp. Tóm lại, Giao hàng Được Đảm bảo được thiết kế để bảo vệ việc giao hàng thông điệp khỏi những sự cố dự kiến, chẳng hạn như hỏng hóc máy móc hoặc hỏng hóc mạng, nhưng thường không phải là 100% không thể bị phá vỡ. |
Với việc triển khai MSMQ của .NET, để một kênh trở nên bền vững, nó phải được khai báo là giao dịch, có nghĩa là các tác giả thường phải là Khách hàng Giao dịch. Trong JMS, với Kênh Xuất Bản - Đăng Ký, Đảm Bảo Giao Hàng chỉ đảm bảo rằng các tin nhắn sẽ được gửi đến các người đăng ký đang hoạt động. Để đảm bảo rằng một người đăng ký nhận được các tin nhắn ngay cả khi không hoạt động, người đăng ký sẽ cần là một Người Đăng Ký Bền Vững.
| Ví dụ: Giao dịch chứng khoán Trong một hệ thống giao dịch chứng khoán, các yêu cầu giao dịch và xác nhận giao dịch nên được gửi kèm với Dịch vụ Giao hàng Đảm bảo để giúp đảm bảo rằng không có yêu cầu nào bị mất. Thông báo thay đổi địa chỉ cũng nên được gửi với Dịch vụ Giao hàng Đảm bảo, nhưng có lẽ không cần thiết đối với các cập nhật giá vì việc mất một số trong số đó không quan trọng, và tần suất của chúng làm cho chi phí của Dịch vụ Giao hàng Đảm bảo trở nên không khả thi. Trong Đăng ký Bền vững, ví dụ về giao dịch chứng khoán cho biết một số người đăng ký thay đổi giá có thể muốn bền vững. Nếu vậy, có lẽ kênh thay đổi giá nên đảm bảo việc giao hàng. Tuy nhiên, những người đăng ký khác có thể không cần phải bền vững hoặc không muốn phải chịu đựng chi phí cao của Giao hàng Được đảm bảo. Làm thế nào để đáp ứng những nhu cầu khác nhau này? Hệ thống có thể muốn triển khai hai kênh thay đổi giá, một kênh có Giao hàng Được đảm bảo và một kênh không có. Chỉ những người đăng ký cần tất cả các bản cập nhật mới nên đăng ký vào kênh bền vững, và các đăng ký của họ nên là bền vững. Nhà xuất bản có thể muốn công bố các bản cập nhật ít thường xuyên hơn trên kênh bền vững vì chi phí cao hơn của nó. (Xem chiến lược Kênh Chất lượng Dịch vụ được thảo luận trong Kênh Loại dữ liệu.) |
| Ví dụ: Tin nhắn bền vững JMS Trong JMS, khả năng lưu trữ tin nhắn có thể được thiết lập trên cơ sở từng tin nhắn. Nói cách khác, một số tin nhắn trên một kênh cụ thể có thể được lưu trữ, trong khi những tin nhắn khác có thể không được lưu trữ [JMS 1.1], [Hapner]. Khi một người gửi JMS muốn làm cho một thông điệp trở nên bền vững, họ sử dụng MessageProducer của mình để đặt JMSDeliveryMode của thông điệp thành PERMANENT. Người gửi có thể thiết lập tính bền vững cho từng thông điệp như sau: Session session = // obtain the session Destination destination = // obtain the destination Message message = // create the message MessageProducer producer = session.createProducer(destination); producer.send( message, javax.jms.DeliveryMode.PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY, javax.jms.Message.DEFAULT_TIME_TO_LIVE); Nếu ứng dụng muốn làm cho tất cả các tin nhắn trở nên bền vững, nó có thể đặt điều đó là mặc định cho nhà sản xuất tin nhắn. producer.setDeliveryMode(javax.jms.DeliveryMode.PERSISTENT); (Và thực tế, chế độ giao hàng mặc định cho một nhà sản xuất tin nhắn là bền vững.) Bây giờ, các tin nhắn được gửi bởi nhà sản xuất này tự động trở thành bền vững, vì vậy chúng có thể được gửi một cách đơn giản. producer.send(message); Trong khi đó, các tin nhắn được gửi bởi các nhà sản xuất tin nhắn khác trên cùng một kênh có thể được lưu trữ, tùy thuộc vào cách mà các nhà sản xuất đó cấu hình tin nhắn của họ. |
| Ví dụ: IBM WebSphere MQ Trong WebSphere MQ, Giao hàng Đảm bảo có thể được thiết lập theo từng kênh hoặc theo từng tin nhắn. Nếu kênh không duy trì, các tin nhắn không thể được duy trì. Nếu kênh được duy trì, kênh có thể được cấu hình sao cho tất cả các tin nhắn gửi qua kênh đó đều tự động được duy trì hoặc một tin nhắn cá nhân có thể được gửi một cách duy trì hoặc không duy trì. Kênh được cấu hình để trở nên bền vững (hoặc không) khi nó được tạo ra trong hệ thống nhắn tin. Ví dụ, kênh có thể được cấu hình sao cho tất cả các tin nhắn của nó đều bền vững. DEFINE Q(myQueue) PER(PERS) Hoặc kênh có thể được cấu hình sao cho người gửi tin nhắn có thể chỉ định với mỗi tin nhắn liệu tin nhắn đó có bền hay tạm thời. DEFINE Q(myQueue) PER(APP) Nếu kênh được thiết lập để cho phép người gửi xác định tính bền vững, thì một JMS MessageProducer có thể thiết lập thuộc tính chế độ giao hàng như đã mô tả ở trên. Nếu kênh được thiết lập để làm cho tất cả các tin nhắn trở nên bền vững, thì các cài đặt chế độ giao hàng do MessageProducer chỉ định sẽ bị bỏ qua [WSMQ]. |
| Ví dụ: Tin nhắn bền vững .NET Với .NET, các tin nhắn bền vững được tạo ra bằng cách biến một hàng đợi tin nhắn (MessageQueue) thành giao dịch. MessageQueue.Create("MyQueue", true); Tất cả các tin nhắn được gửi trên hàng đợi này sẽ tự động trở nên bền vững [Dickman]. |
Nhiều doanh nghiệp sử dụng Tin nhắn để tích hợp nhiều ứng dụng khác nhau.
| Làm thế nào bạn có thể kết nối một ứng dụng với hệ thống nhắn tin để nó có thể gửi và nhận tin nhắn? |
Hầu hết các ứng dụng không được thiết kế để làm việc với một hạ tầng nhắn tin. Có nhiều lý do cho sự hạn chế này. Nhiều ứng dụng đã được phát triển như những giải pháp độc lập, tự chứa ngay cả khi chúng chứa dữ liệu hoặc chức năng có thể được tận dụng bởi các hệ thống khác. Ví dụ, nhiều ứng dụng trên máy chính được thiết kế như một ứng dụng tất cả trong một mà không bao giờ phải tương tác với các ứng dụng khác. Thật không may, tích hợp di sản hiện nay là một trong những điểm tích hợp phổ biến nhất cho các giải pháp tích hợp doanh nghiệp. Một lý do khác xuất phát từ thực tế rằng nhiều hệ thống phần mềm trung gian dựa trên thông điệp công bố các API độc quyền, vì vậy nhà phát triển ứng dụng sẽ phải mã hóa nhiều giao diện cho hệ thống nhắn tin, một giao diện cho mỗi nhà cung cấp phần mềm trung gian tiềm năng.
Nếu các ứng dụng cần trao đổi dữ liệu với các ứng dụng khác, chúng thường được thiết kế để sử dụng các cơ chế giao diện tổng quát hơn như trao đổi tệp hoặc bảng dữ liệu. Đọc và ghi tệp là một chức năng cơ bản của hệ điều hành và không phụ thuộc vào các API cụ thể của nhà cung cấp. Tương tự, hầu hết các ứng dụng kinh doanh đã lưu trữ dữ liệu vào cơ sở dữ liệu, vì vậy chỉ cần ít nỗ lực bổ sung để lưu trữ dữ liệu dành cho các hệ thống khác trong một bảng cơ sở dữ liệu. Hoặc một ứng dụng có thể cung cấp các chức năng nội bộ qua một API tổng quát có thể được sử dụng bởi bất kỳ chiến lược tích hợp nào khác, bao gồm cả nhắn tin.
Các ứng dụng khác có thể có khả năng giao tiếp thông qua một giao thức đơn giản như HTTP hoặc TCP/IP. Tuy nhiên, những giao thức này không cung cấp mức độ tin cậy giống như Kênh Tin nhắn, và định dạng dữ liệu được sử dụng bởi ứng dụng thường cụ thể cho ứng dụng đó và không tương thích với một giải pháp nhắn tin chung.
Trong trường hợp các ứng dụng tùy chỉnh, chúng tôi có thể thêm mã vào ứng dụng để cho phép nó gửi và nhận tin nhắn. Tuy nhiên, điều này có thể làm gia tăng sự phức tạp cho ứng dụng và chúng tôi cần cẩn thận để không gây ra bất kỳ tác dụng phụ không mong muốn nào khi thực hiện những thay đổi này. Ngoài ra, cách tiếp cận này yêu cầu các nhà phát triển phải thành thạo cả logic ứng dụng và API nhắn tin. Cả hai cách tiếp cận đó cũng giả định rằng chúng tôi có quyền truy cập vào mã nguồn của ứng dụng. Nếu chúng tôi làm việc với một ứng dụng đóng gói mà chúng tôi đã mua từ một nhà cung cấp phần mềm bên thứ ba, chúng tôi có thể không có tùy chọn nào để thay đổi mã ứng dụng.
| Sử dụng một Bộ chuyển đổi Kênh có thể truy cập API hoặc dữ liệu của ứng dụng để xuất bản tin nhắn trên một kênh dựa trên dữ liệu này và cũng có thể nhận tin nhắn và thực thi chức năng bên trong ứng dụng.
|
Bộ chuyển đổi hoạt động như một khách hàng nhắn tin đến hệ thống nhắn tin và gọi các chức năng ứng dụng thông qua một giao diện do ứng dụng cung cấp. Tương tự, Bộ Chuyển Đổi Kênh có thể lắng nghe các sự kiện nội bộ của ứng dụng và gọi đến hệ thống nhắn tin để phản hồi các sự kiện này. Bằng cách này, bất kỳ ứng dụng nào cũng có thể kết nối với hệ thống nhắn tin và được tích hợp với các ứng dụng khác miễn là nó có một Bộ Chuyển Đổi Kênh đúng cách.
Bộ điều hợp kênh có thể kết nối với các lớp khác nhau của kiến trúc ứng dụng, tùy thuộc vào kiến trúc đó và loại dữ liệu mà hệ thống nhắn tin cần truy cập.
Một Bộ Chuyển Đổi Kết Nối với Các Lớp Khác Nhau của Một Ứng Dụng

Bộ điều hợp giao diện người dùng. Đôi khi bị coi thường là "lấy màn hình", những loại bộ điều hợp này có thể rất hiệu quả trong nhiều tình huống. Ví dụ, một ứng dụng có thể được triển khai trên một nền tảng không được hệ thống nhắn tin hỗ trợ. Hoặc chủ sở hữu của ứng dụng có thể không mấy quan tâm đến việc hỗ trợ tích hợp. Điều này loại trừ tùy chọn chạy Bộ điều hợp Kênh trên nền tảng ứng dụng. Tuy nhiên, giao diện người dùng thường có sẵn từ các máy và nền tảng khác (ví dụ: các thiết bị đầu cuối 3270). Ngoài ra, sự bùng nổ của các kiến trúc khách mỏng dựa trên web đã gây ra một sự hồi sinh nhất định cho tích hợp giao diện người dùng. Các giao diện người dùng dựa trên HTML rất dễ dàng để thực hiện yêu cầu HTTP và phân tích kết quả. Một lợi thế khác của tích hợp giao diện người dùng là không cần truy cập trực tiếp vào các thành phần nội bộ của ứng dụng. Trong một số trường hợp, có thể không mong muốn hoặc không thể tiết lộ các chức năng bên trong của một hệ thống cho giải pháp tích hợp. Sử dụng bộ điều hợp giao diện người dùng, các ứng dụng khác có quyền truy cập chính xác giống như một người dùng thông thường vào ứng dụng. Nhược điểm của bộ điều hợp giao diện người dùng là khả năng dễ bị hỏng và tốc độ thấp của giải pháp. Ứng dụng phải phân tích đầu vào "người dùng" và hiển thị màn hình để phản hồi chỉ để Bộ điều hợp Kênh có thể phân tích màn hình trở lại thành dữ liệu thô. Quy trình này liên quan đến nhiều bước không cần thiết và có thể chậm. Hơn nữa, giao diện người dùng có xu hướng thay đổi thường xuyên hơn logic ứng dụng cốt lõi. Mỗi khi giao diện người dùng thay đổi, Bộ điều hợp Kênh có khả năng cũng sẽ phải thay đổi.
Bộ điều hợp logic kinh doanh. Hầu hết các ứng dụng kinh doanh đều cung cấp các chức năng cốt lõi của chúng dưới dạng API. Giao diện này có thể là một tập hợp các thành phần (ví dụ: EJB, đối tượng COM, thành phần CORBA) hoặc một API lập trình trực tiếp (ví dụ: thư viện C++, C# hoặc Java). Vì nhà cung cấp phần mềm (hoặc nhà phát triển) công khai các API này một cách rõ ràng để cho phép truy cập bởi các ứng dụng khác, nên chúng thường ổn định hơn giao diện người dùng. Trong hầu hết các trường hợp, việc truy cập API cũng hiệu quả hơn. Nói chung, nếu ứng dụng cung cấp một API được định nghĩa tốt, thì loại Bộ điều hợp Kênh này có khả năng là phương pháp tốt nhất.
Bộ chuyển đổi cơ sở dữ liệu. Hầu hết các ứng dụng kinh doanh lưu trữ dữ liệu của họ trong một cơ sở dữ liệu quan hệ. Vì thông tin đã có sẵn trong cơ sở dữ liệu, Bộ chuyển đổi Kênh có thể trích xuất thông tin trực tiếp từ cơ sở dữ liệu mà không làm ứng dụng nhận thấy, đây là một cách tích hợp rất không xâm phạm. Bộ chuyển đổi Kênh thậm chí có thể thêm một trigger vào các bảng liên quan và gửi thông báo mỗi khi dữ liệu trong các bảng này thay đổi. Loại Bộ chuyển đổi Kênh này có thể rất hiệu quả và khá phổ biến, được hỗ trợ bởi thực tế rằng chỉ có hai hoặc ba nhà cung cấp cơ sở dữ liệu chiếm ưu thế trên thị trường cơ sở dữ liệu quan hệ. Điều này cho phép chúng tôi kết nối với nhiều ứng dụng khác nhau bằng một bộ chuyển đổi tương đối chung chung. Nhược điểm của bộ chuyển đổi cơ sở dữ liệu là chúng ta đang tìm tòi sâu vào nội bộ của một ứng dụng. Điều này có thể không mạo hiểm nếu chúng ta chỉ đọc dữ liệu, nhưng việc cập nhật trực tiếp vào cơ sở dữ liệu có thể rất nguy hiểm. Ngoài ra, nhiều nhà cung cấp ứng dụng coi sơ đồ cơ sở dữ liệu là "chưa được công bố," có nghĩa là họ giữ quyền thay đổi nó theo ý muốn, điều này có thể làm cho giải pháp bộ chuyển đổi cơ sở dữ liệu trở nên kém bền vững.
Một hạn chế quan trọng của Bộ chuyển đổi Kênh là chúng có thể chuyển đổi tin nhắn thành các chức năng ứng dụng, nhưng chúng yêu cầu định dạng tin nhắn giống như cấu trúc của các thành phần đang được chuyển đổi. Ví dụ, một bộ chuyển đổi cơ sở dữ liệu thường yêu cầu các tên trường của tin nhắn đến phải giống với tên của bảng và trường trong cơ sở dữ liệu ứng dụng. Đây là loại định dạng tin nhắn hoàn toàn được điều khiển bởi cấu trúc nội tại của ứng dụng và không phải là định dạng tin nhắn tốt để sử dụng khi tích hợp với các ứng dụng khác. Vì vậy, hầu hết các Bộ chuyển đổi Kênh phải được kết hợp với một Bộ biên dịch Tin nhắn để chuyển đổi tin nhắn cụ thể ứng dụng thành một định dạng tin nhắn tuân thủ Mô hình Dữ liệu Canonical.
Các bộ chuyển đổi kênh thường có thể chạy trên một máy tính khác với ứng dụng hoặc cơ sở dữ liệu. Bộ chuyển đổi kênh có thể kết nối với logic ứng dụng hoặc cơ sở dữ liệu qua các giao thức như HTTP hoặc ODBC. Mặc dù cấu hình này cho phép chúng ta tránh cài đặt phần mềm bổ sung trên máy chủ ứng dụng hoặc cơ sở dữ liệu, nhưng các giao thức này thường không cung cấp chất lượng dịch vụ giống như một kênh nhắn tin, chẳng hạn như đảm bảo giao hàng. Do đó, chúng ta phải nhận thức rằng kết nối từ xa tới cơ sở dữ liệu có thể đại diện cho một điểm có khả năng thất bại.
Một số Bộ Kết Nối Kênh là một chiều. Ví dụ, nếu một Bộ Kết Nối Kênh kết nối với một ứng dụng qua HTTP, nó có thể chỉ có khả năng tiêu thụ tin nhắn và gọi các hàm trên ứng dụng, nhưng có thể không phát hiện được sự thay đổi trong dữ liệu ứng dụng ngoại trừ thông qua việc kiểm tra lặp đi lặp lại, điều này có thể rất kém hiệu quả.
Một biến thể thú vị của Bộ chuyển đổi Kênh là Bộ chuyển đổi Siêu dữ liệu, đôi khi được gọi là Bộ chuyển đổi Thời gian Thiết kế. Loại bộ chuyển đổi này không gọi các hàm ứng dụng mà trích xuất siêu dữ liệu, dữ liệu mô tả định dạng dữ liệu nội bộ của ứng dụng. Siêu dữ liệu này sau đó có thể được sử dụng để cấu hình các Bộ chuyển đổi Thông điệp hoặc để phát hiện sự thay đổi trong các định dạng dữ liệu ứng dụng (xem phần giới thiệu trong Chương 8, "Chuyển đổi Thông điệp"). Nhiều giao diện ứng dụng hỗ trợ loại trích xuất siêu dữ liệu này. Ví dụ, hầu hết các cơ sở dữ liệu thương mại cung cấp một tập hợp các bảng hệ thống chứa siêu dữ liệu dưới dạng mô tả các bảng ứng dụng. Tương tự, hầu hết các khung thành phần (ví dụ: J2EE, .NET) cung cấp các chức năng "phản chiếu" đặc biệt cho phép một thành phần liệt kê các phương thức do một thành phần khác cung cấp.
Một hình thức đặc biệt của Bộ chuyển đổi Kênh là Cầu nhắn tin. Cầu nhắn tin kết nối hệ thống nhắn tin với một hệ thống nhắn tin khác, thay vì với một ứng dụng cụ thể. Thông thường, một Bộ chuyển đổi Kênh được triển khai như một Khách hàng Giao dịch để đảm bảo rằng mỗi tác vụ mà bộ chuyển đổi thực hiện thành công cả trong hệ thống nhắn tin và hệ thống khác đang được chuyển đổi.
| Ví dụ: Giao dịch cổ phiếu Hệ thống giao dịch cổ phiếu có thể muốn lưu giữ nhật ký tất cả giá cổ phiếu trong một bảng cơ sở dữ liệu. Hệ thống nhắn tin có thể bao gồm một bộ điều hợp cơ sở dữ liệu quan hệ để ghi lại mỗi tin nhắn từ một kênh vào một bảng và lược đồ được chỉ định. Bộ điều hợp kênh đến RDBMS này là một Bộ điều hợp Kênh. Hệ thống cũng có thể nhận các yêu cầu báo giá từ bên ngoài qua Internet (TCP/IP hoặc HTTP) và gửi chúng đến kênh yêu cầu báo giá nội bộ cùng với các yêu cầu báo giá nội bộ. Bộ điều hợp Internet đến kênh này là một Bộ điều hợp Kênh. |
| Ví dụ: Công cụ EAI thương mại Các nhà cung cấp EAI thương mại cung cấp một bộ sưu tập các Bộ chuyển đổi Kênh như một phần trong các sản phẩm của họ. Sự có mặt của các bộ chuyển đổi cho tất cả các gói ứng dụng chính giúp đơn giản hóa rất nhiều việc phát triển một giải pháp tích hợp. Hầu hết các nhà cung cấp cũng cung cấp các bộ chuyển đổi cơ sở dữ liệu tổng quát hơn cũng như các bộ công cụ phát triển phần mềm (SDK) để phát triển các bộ chuyển đổi tùy chỉnh. |
| Ví dụ: Bộ chuyển đổi Nền tảng Di sản Một số nhà cung cấp cung cấp các bộ chuyển đổi từ hệ thống nhắn tin phổ biến sang các hệ thống kế thừa đang chạy trên các nền tảng như UNIX, MVS, OS/2, AS/400, Unisys và VMS. Hầu hết các bộ chuyển đổi này đều cụ thể cho một hệ thống nhắn tin nhất định. Ví dụ, Envoy Technologies' EnvoyMQ là một Bộ Chuyển Đổi Kênh kết nối nhiều nền tảng kế thừa với MSMQ. Nó bao gồm một thành phần khách chạy trên máy tính kế thừa và một thành phần máy chủ chạy trên máy tính Windows với MSMQ. |
| Ví dụ: Bộ chuyển đổi dịch vụ web Nhiều hệ thống nhắn tin cung cấp Bộ chuyển đổi Kênh để di chuyển các thông điệp SOAP giữa một giao thức HTTP và hệ thống nhắn tin. Bằng cách này, các thông điệp SOAP có thể được truyền qua một intranet sử dụng một hệ thống nhắn tin đáng tin cậy, không đồng bộ và qua Internet toàn cầu (cũng như qua các tường lửa) sử dụng HTTP. Một ví dụ về một bộ chuyển đổi như vậy là Cổng Dịch vụ Web cho Máy chủ Ứng dụng WebSphere của IBM. |
Một doanh nghiệp đang sử dụng hệ thống nhắn tin để cho phép các ứng dụng giao tiếp. Tuy nhiên, doanh nghiệp sử dụng hơn một hệ thống nhắn tin, điều này gây ra sự nhầm lẫn về việc ứng dụng nên kết nối với hệ thống nhắn tin nào.
| Làm thế nào để kết nối nhiều hệ thống nhắn tin để các tin nhắn có trên một hệ thống cũng có trên các hệ thống khác? |
Một vấn đề phổ biến là một doanh nghiệp sử dụng hơn một hệ thống nhắn tin. Điều này có thể xảy ra do sáp nhập hoặc mua lại giữa hai công ty khác nhau mà đã chuẩn hóa xung quanh các sản phẩm nhắn tin khác nhau. Đôi khi, một doanh nghiệp duy nhất sử dụng một hệ thống nhắn tin để tích hợp các hệ thống mainframe/cổ điển của mình lại chọn một hệ thống khác cho các máy chủ ứng dụng Web J2EE hoặc .NET của mình và sau đó cần phải tích hợp hai hệ thống nhắn tin này. Một trường hợp phổ biến khác là một ứng dụng tham gia như một phần của nhiều doanh nghiệp, chẳng hạn như một khách hàng B2B muốn tham gia đấu thầu trong nhiều hệ thống đấu giá khác nhau. Nếu các cụm đấu giá khác nhau sử dụng các hệ thống nhắn tin khác nhau, các ứng dụng đấu thầu trong một doanh nghiệp có thể muốn hợp nhất các tin nhắn từ một số hệ thống nhắn tin bên ngoài thành một hệ thống nhắn tin nội bộ duy nhất. Một ví dụ khác là doanh nghiệp cực lớn có số lượng Kênh Tin nhắn và Điểm cuối Tin nhắn rất lớn có thể yêu cầu nhiều hơn một phiên bản của hệ thống nhắn tin, có nghĩa là những phiên bản đó phải được kết nối với nhau bằng cách nào đó.
Nếu các tin nhắn trên một hệ thống không có giá trị đối với các ứng dụng sử dụng hệ thống nhắn tin khác, thì các hệ thống có thể hoàn toàn tách biệt. Nhưng vì các ứng dụng là một phần của cùng một doanh nghiệp, thường thì một số ứng dụng sử dụng một hệ thống nhắn tin sẽ quan tâm đến các tin nhắn được truyền tải trên một hệ thống nhắn tin khác.
Một hiểu lầm phổ biến là một API nhắn tin tiêu chuẩn hóa như JMS giải quyết vấn đề này; điều đó không đúng. JMS làm cho hai hệ thống nhắn tin tuân thủ trông giống nhau đối với một ứng dụng khách, nhưng không làm gì để cho hai hệ thống nhắn tin hoạt động với nhau. Để các hệ thống nhắn tin có thể làm việc cùng nhau, chúng cần có khả năng tương tác, có nghĩa là chúng sử dụng cùng một định dạng tin nhắn và truyền một tin nhắn từ kho tin nhắn này sang kho tin nhắn khác theo cùng một cách. Các hệ thống nhắn tin từ hai nhà cung cấp khác nhau hiếm khi tương tác được với nhau; một kho tin nhắn từ một nhà cung cấp chỉ có thể làm việc với các kho tin nhắn khác từ cùng một nhà cung cấp.
Mỗi ứng dụng trong doanh nghiệp có thể chọn triển khai một client cho mỗi hệ thống nhắn tin trong doanh nghiệp, nhưng điều đó sẽ làm tăng độ phức tạp và sự trùng lặp trong lớp nhắn tin. Sự dư thừa này sẽ trở nên đặc biệt rõ ràng nếu doanh nghiệp thêm một hệ thống nhắn tin khác và tất cả các ứng dụng phải được sửa đổi. Mặt khác, mỗi ứng dụng có thể chọn giao tiếp chỉ với một hệ thống nhắn tin và bỏ qua dữ liệu trên các hệ thống nhắn tin khác. Điều này sẽ làm cho ứng dụng đơn giản hơn nhưng có thể khiến nó bỏ qua một lượng lớn dữ liệu của doanh nghiệp. Cần có một cách để các tin nhắn trên một hệ thống nhắn tin mà có liên quan đến các ứng dụng trên một hệ thống nhắn tin khác được cung cấp trên hệ thống nhắn tin thứ hai.
| Sử dụng Cầu Nhắn Tin, một kết nối giữa các hệ thống nhắn tin giúp sao chép tin nhắn giữa các hệ thống.
|
Thông thường, không có cách thực tiễn nào để kết nối hai hệ thống nhắn tin hoàn chỉnh, vì vậy thay vào đó, chúng ta kết nối các kênh tương ứng riêng lẻ giữa các hệ thống nhắn tin. Cầu nối Nhắn tin là một tập hợp các Bộ chuyển đổi Kênh, trong đó khách hàng không phải nhắn tin thực sự là một hệ thống nhắn tin khác và mỗi cặp bộ chuyển đổi kết nối một cặp kênh tương ứng. Cầu nối hoạt động như một bản đồ từ một tập hợp kênh này sang tập hợp kênh khác và chuyển đổi định dạng tin nhắn từ hệ thống này sang hệ thống kia. Các kênh đã kết nối có thể được sử dụng để truyền tin nhắn giữa các khách hàng truyền thống của hệ thống nhắn tin hoặc chỉ dành cho các tin nhắn nhằm vào các hệ thống nhắn tin khác.
Bạn có thể cần phải triển khai Cầu Nhắn tin cho doanh nghiệp của mình. Cầu là một ứng dụng Điểm cuối Thông điệp chuyên biệt, hoạt động như một khách hàng của cả hai hệ thống nhắn tin. Khi một thông điệp được chuyển đến một kênh quan tâm trong một hệ thống nhắn tin, cầu sẽ tiêu thụ thông điệp đó và gửi một thông điệp khác với nội dung tương tự trên kênh tương ứng trong hệ thống nhắn tin còn lại.
Nhiều nhà cung cấp hệ thống nhắn tin có các mở rộng sản phẩm để kết nối với các hệ thống nhắn tin từ các nhà cung cấp khác. Do đó, bạn có thể mua một giải pháp thay vì tự xây dựng nó.
Nếu "hệ thống truyền tin" khác thực sự là một giao thức đơn giản hơn, chẳng hạn như HTTP, hãy áp dụng mẫu Bộ chuyển đổi Kênh.
Cầu nối tin nhắn là cần thiết vì các hệ thống tin nhắn khác nhau có cách tiếp cận riêng của họ để đại diện cho các tin nhắn và cách chuyển tiếp chúng từ kho này sang kho khác. Các dịch vụ web có thể chuẩn hóa điều này, theo cách mà hai cài đặt hệ thống tin nhắn, ngay cả từ các nhà cung cấp khác nhau, có thể hành động như một bằng cách chuyển giao tin nhắn sử dụng các tiêu chuẩn dịch vụ web. Xem thảo luận về WS-Reliability và WS-ReliableMessaging trong Chương 14, "Những nhận xét kết thúc."
| Ví dụ: Giao dịch cổ phiếu Một công ty môi giới có thể có một hệ thống nhắn tin mà các ứng dụng tại các văn phòng khác nhau của nó sử dụng để giao tiếp. Một ngân hàng có thể có một hệ thống nhắn tin khác mà các ứng dụng tại các chi nhánh khác nhau của nó sử dụng để giao tiếp. Nếu công ty môi giới và ngân hàng quyết định sáp nhập thành một công ty duy nhất cung cấp tài khoản ngân hàng và dịch vụ đầu tư, hệ thống nhắn tin nào nên được công ty kết hợp sử dụng? Thay vì thiết kế lại một nửa ứng dụng của công ty để sử dụng hệ thống nhắn tin mới, công ty có thể sử dụng một Cầu Nối Nhắn Tin để kết nối hai hệ thống nhắn tin. Bằng cách này, ví dụ, một ứng dụng ngân hàng và một ứng dụng môi giới có thể phối hợp để chuyển tiền giữa một tài khoản tiết kiệm và một tài khoản giao dịch chứng khoán. |
| Ví dụ: Cầu MSMQ MSMQ định nghĩa một kiến trúc dựa trên các máy chủ kết nối, cho phép các ứng dụng kết nối gửi và nhận tin nhắn sử dụng các hệ thống nhắn tin khác (không phải MSMQ). Một ứng dụng MSMQ sử dụng máy chủ kết nối có thể thực hiện các thao tác giống như trên các kênh từ các hệ thống nhắn tin khác mà nó có thể thực hiện trên các kênh MSMQ. Sản phẩm Host Integration Server của Microsoft chứa một dịch vụ cầu nối MSMQ-MQSeries cho phép hai hệ thống nhắn tin hoạt động cùng nhau. Nó cho phép các ứng dụng MSMQ gửi tin nhắn qua các kênh MQSeries và ngược lại, khiến cho hai hệ thống nhắn tin hoạt động như một. Envoy Technologies, người cấp phép cho cầu nối MSMQ-MQSeries, cũng có một sản phẩm liên quan gọi là Envoy Connect. Nó kết nối các máy chủ MSMQ và BizTalk với các máy chủ nhắn tin chạy trên các nền tảng không phải Windows, đặc biệt là nền tảng J2EE, điều phối nhắn tin J2EE và .NET trong một doanh nghiệp. |
| Ví dụ: SonicMQ Bridges Sonic Software's SonicMQ có các sản phẩm SonicMQ Bridge hỗ trợ IBM MQSeries, TIBCO TIB/Rendezvous và JMS. Điều này cho phép các tin nhắn trên các kênh Sonic được truyền tải trên các kênh của các hệ thống nhắn tin khác. |
Một doanh nghiệp chứa nhiều hệ thống hiện có mà phải có khả năng chia sẻ dữ liệu và hoạt động theo cách thống nhất để đáp ứng một tập hợp các yêu cầu kinh doanh chung.
| Kiến trúc nào cho phép các ứng dụng riêng lẻ làm việc cùng nhau nhưng theo cách tách rời, để các ứng dụng có thể dễ dàng được thêm vào hoặc loại bỏ mà không ảnh hưởng đến các ứng dụng khác? |
Một doanh nghiệp thường chứa nhiều ứng dụng hoạt động độc lập nhưng phải làm việc cùng nhau một cách thống nhất. Tích hợp Ứng dụng Doanh nghiệp (EAI) định nghĩa một giải pháp cho vấn đề này nhưng không mô tả cách thực hiện nó.
Chẳng hạn, hãy xem xét một công ty bảo hiểm bán các loại sản phẩm bảo hiểm khác nhau (bảo hiểm nhân thọ, bảo hiểm sức khỏe, bảo hiểm xe hơi, bảo hiểm nhà cửa, v.v.). Do sự sáp nhập doanh nghiệp và những thay đổi không ngừng trong sự phát triển công nghệ thông tin, doanh nghiệp bao gồm một số ứng dụng riêng biệt để quản lý các sản phẩm khác nhau của công ty. Một đại lý bảo hiểm đang cố gắng bán cho khách hàng nhiều loại chính sách khác nhau phải đăng nhập vào một hệ thống riêng biệt cho mỗi chính sách, gây lãng phí công sức và tăng khả năng xảy ra sai sót.
Kịch bản EAI của Công ty Bảo hiểm

Đại lý cần một ứng dụng duy nhất và thống nhất để bán cho khách hàng một danh mục các chính sách. Các nhân viên công ty bảo hiểm khác, như nhân viên điều chỉnh khiếu nại và đại diện dịch vụ khách hàng, cần ứng dụng riêng của họ để làm việc với các sản phẩm bảo hiểm, nhưng họ cũng muốn các ứng dụng của họ trình bày một cái nhìn thống nhất. Các ứng dụng sản phẩm riêng lẻ phải có khả năng làm việc cùng nhau, có thể để cung cấp một khoản giảm giá khi mua hơn một chính sách và để xử lý một yêu cầu bồi thường được bảo hiểm bởi hơn một chính sách.
Bộ phận CNTT có thể viết lại các ứng dụng sản phẩm để tất cả sử dụng cùng một công nghệ và làm việc cùng nhau, nhưng lượng thời gian và tiền bạc để thay thế các hệ thống đã hoạt động (mặc dù chúng không làm việc cùng nhau) là rất tốn kém. CNTT có thể tạo ra một ứng dụng thống nhất cho các nhân viên, nhưng ứng dụng này cần kết nối với các hệ thống thực sự quản lý các hợp đồng. Thay vì thống nhất các hệ thống, ứng dụng mới này tạo ra một hệ thống nữa không tích hợp với các hệ thống khác.
Ứng dụng đại lý có thể tích hợp với tất cả những hệ thống khác này, nhưng điều đó sẽ làm cho nó trở nên phức tạp hơn rất nhiều. Sự phức tạp này sẽ được lặp lại trong các ứng dụng cho nhân viên điều chỉnh yêu cầu bồi thường và đại diện dịch vụ khách hàng. Hơn nữa, những ứng dụng người dùng thống nhất này sẽ không giúp các ứng dụng sản phẩm tích hợp với nhau.
Ngay cả khi tất cả các ứng dụng này có thể hoạt động cùng nhau, bất kỳ sự thay đổi nào đối với cấu hình của doanh nghiệp cũng có thể khiến chúng ngừng hoạt động. Không phải tất cả các ứng dụng đều sẽ có sẵn mọi lúc, nhưng những ứng dụng đang chạy phải có khả năng tiếp tục với ảnh hưởng tối thiểu từ những ứng dụng không chạy. Theo thời gian, các ứng dụng sẽ cần được thêm vào và loại bỏ khỏi doanh nghiệp, với ảnh hưởng tối thiểu đến các ứng dụng khác. Điều cần thiết là một kiến trúc tích hợp cho phép các ứng dụng sản phẩm phối hợp theo cách lỏng lẻo và cho các ứng dụng người dùng có thể tích hợp với chúng.
| Cấu trúc phần mềm trung gian kết nối giữa các ứng dụng này như một Bus Tin nhắn cho phép chúng hoạt động cùng nhau thông qua việc truyền tin nhắn.
|
Một Bus Tin Nhắn là sự kết hợp của Mô Hình Dữ Liệu Canonical, một tập hợp lệnh chung và cơ sở hạ tầng nhắn tin để cho phép các hệ thống khác nhau giao tiếp thông qua một tập hợp giao diện chia sẻ. Điều này tương tự như một bus truyền thông trong một hệ thống máy tính, phục vụ như là điểm trung tâm cho việc giao tiếp giữa CPU, bộ nhớ chính và các thiết bị ngoại vi. Cũng như trong phép tương tự phần cứng, có nhiều thành phần kết hợp với nhau để tạo thành bus tin nhắn.
Hệ thống hạ tầng truyền thông chung Giống như các chân và dây vật lý của bus PCI cung cấp một hạ tầng vật lý chung, rõ ràng cho một PC, một hạ tầng chung cũng phải phục vụ cùng một mục đích trong một bus tin nhắn. Thông thường, một hệ thống nhắn tin được chọn để phục vụ như hạ tầng truyền thông vật lý, cung cấp một bộ chuyển đổi phổ quát xuyên nền tảng và đa ngôn ngữ giữa các ứng dụng. Hạ tầng này có thể bao gồm khả năng Bộ định tuyến Tin nhắn để tạo điều kiện cho việc định tuyến chính xác các tin nhắn từ hệ thống này sang hệ thống khác. Một lựa chọn phổ biến khác là sử dụng Kênh Xuất bản-Đăng ký để tạo điều kiện gửi tin nhắn đến tất cả các người nhận.
Bộ chuyển đổi Các hệ thống khác nhau phải tìm cách giao tiếp với Bus Tin nhắn. Một số ứng dụng có thể được xây dựng sẵn để kết nối với bus, nhưng hầu hết sẽ cần bộ chuyển đổi để kết nối với hệ thống nhắn tin. Những bộ chuyển đổi này thường là Adapters Kênh thương mại hoặc tùy chỉnh và Dịch vụ Kích hoạt. Chúng có thể được chuyên biệt để xử lý các tác vụ như gọi các giao dịch CICS với các tham số phù hợp hoặc chuyển đổi cấu trúc dữ liệu chung của bus sang biểu diễn cụ thể mà một ứng dụng sử dụng. Điều này cũng yêu cầu một Mô hình Dữ liệu Chuẩn mà tất cả các hệ thống đều có thể đồng ý.
Cấu trúc lệnh chung Cũng như các kiến trúc PC có một tập hợp các lệnh chung để thể hiện các hoạt động khác nhau có thể thực hiện trên bus vật lý (đọc byte từ một địa chỉ, ghi byte vào một địa chỉ), cần phải có các lệnh chung mà tất cả các bên tham gia trong Bus Tin nhắn có thể hiểu. Tin nhắn Lệnh minh họa cách tính năng này hoạt động. Một triển khai chung khác cho điều này là Kênh Kiểu dữ liệu, nơi một Bộ định tuyến Tin nhắn đưa ra quyết định rõ ràng về cách định tuyến các tin nhắn cụ thể (như đơn đặt hàng) đến các điểm cuối cụ thể. Đến mức đó, thuật ngữ tương tự bị phá vỡ, vì mức độ của các tin nhắn được mang trên bus tinh vi hơn nhiều so với các loại tin nhắn "đọc/ghi" được mang trên bus vật lý.
Trong ví dụ EAI của chúng tôi, một Bus Tin nhắn có thể đóng vai trò là một kết nối phổ quát giữa các hệ thống bảo hiểm khác nhau và là một giao diện phổ quát cho các ứng dụng khách hàng muốn kết nối với các hệ thống bảo hiểm.
Thông điệp của Công ty Bảo hiểm

Ở đây chúng ta có hai GUI chỉ biết về Bus Tin nhắn; chúng hoàn toàn không nhận thức được những phức tạp của các hệ thống bên dưới. Bus chịu trách nhiệm định tuyến các Tin nhắn Lệnh đến các hệ thống bên dưới phù hợp. Trong một số trường hợp, cách tốt nhất để xử lý các tin nhắn lệnh là xây dựng một bộ chuyển đổi cho hệ thống, bộ chuyển đổi này sẽ diễn giải lệnh và sau đó giao tiếp với hệ thống theo cách mà nó hiểu (ví dụ, gọi một giao dịch CICS hoặc một API C++). Trong những trường hợp khác, có thể xây dựng logic xử lý lệnh trực tiếp vào hệ thống hiện tại như một cách bổ sung để kích hoạt logic hiện tại.
Một khi Bus Tin nhắn đã được phát triển cho giao diện người dùng của đại lý, thì việc tái sử dụng cho các giao diện người dùng khác, như của các nhân viên xử lý đơn yêu cầu, đại diện dịch vụ khách hàng và khách hàng sử dụng giao diện Web để duyệt tài khoản của họ, là rất dễ dàng. Các tính năng và kiểm soát bảo mật của các ứng dụng giao diện người dùng này có thể khác nhau, nhưng nhu cầu để làm việc với các ứng dụng phía sau là giống nhau.
Một Bus Tin nhắn tạo thành một kiến trúc hướng dịch vụ đơn giản và hữu ích cho một doanh nghiệp. Mỗi dịch vụ có ít nhất một kênh yêu cầu chấp nhận các yêu cầu theo định dạng đã thỏa thuận và có thể có một kênh phản hồi tương ứng hỗ trợ một định dạng phản hồi cụ thể. Bất kỳ ứng dụng tham gia nào cũng có thể sử dụng các dịch vụ này bằng cách thực hiện yêu cầu và chờ phản hồi. Các kênh yêu cầu, trên thực tế, đóng vai trò như một danh bạ của các dịch vụ có sẵn.
Một Bus Tin nhắn yêu cầu tất cả các ứng dụng sử dụng bus phải sử dụng cùng một Mô hình Dữ liệu Chính. Các ứng dụng thêm tin nhắn vào bus có thể cần phụ thuộc vào Bộ định tuyến Tin nhắn để định tuyến các tin nhắn đến các điểm đến cuối phù hợp. Các ứng dụng không được thiết kế để giao diện với hệ thống nhắn tin có thể yêu cầu Bộ chuyển đổi Kênh và Bộ kích hoạt Dịch vụ.
| Ví dụ: Giao dịch Chứng khoán Một hệ thống giao dịch chứng khoán có thể muốn cung cấp một bộ dịch vụ thống nhất bao gồm giao dịch cổ phiếu, đấu thầu trái phiếu, báo giá, quản lý danh mục đầu tư, và nhiều thứ khác. Điều này có thể yêu cầu một vài hệ thống back-end riêng biệt cần phải phối hợp với nhau. Để thống nhất các dịch vụ cho giao diện người dùng phía trước, hệ thống có thể sử dụng một ứng dụng trung gian cung cấp tất cả các dịch vụ này và phân công việc thực hiện cho các hệ thống back-end. Các hệ thống back-end thậm chí có thể phối hợp thông qua ứng dụng trung gian này. Tuy nhiên, ứng dụng trung gian sẽ có xu hướng trở thành một điểm nghẽn và là điểm thất bại duy nhất. Thay vì một ứng dụng trung gian, một cách tiếp cận tốt hơn có thể là một Bus Tin nhắn với các kênh để yêu cầu các dịch vụ khác nhau và nhận phản hồi. Bus này cũng có thể cho phép các hệ thống backend phối hợp với nhau. Một hệ thống front-end có thể đơn giản kết nối với bus và sử dụng nó để gọi các dịch vụ. Bus có thể được phân phối tương đối dễ dàng trên nhiều máy tính để cung cấp phân phối tải và khả năng chịu lỗi. Khi Bus Tin Nhắn đã được thiết lập, việc kết nối các giao diện người dùng (GUI) phía trước sẽ trở nên dễ dàng; chúng chỉ cần gửi và nhận tin nhắn từ các kênh thích hợp. Một GUI có thể cho phép một nhà môi giới bán lẻ quản lý danh mục đầu tư của khách hàng của mình. Một GUI trên web khác có thể cho phép bất kỳ khách hàng nào có trình duyệt web quản lý danh mục đầu tư của chính họ. Một giao diện không phải GUI khác có thể hỗ trợ các chương trình tài chính cá nhân như Intuit's Quicken và Microsoft’s Money, cho phép khách hàng sử dụng những chương trình đó tải xuống giao dịch và giá hiện tại. Khi Bus Tin Nhắn đã được thiết lập, việc phát triển các ứng dụng người dùng mới sẽ trở nên đơn giản hơn nhiều. Tương tự, hệ thống giao dịch có thể muốn tận dụng các ứng dụng back-end mới, chẳng hạn như việc thay thế một ứng dụng giao dịch này bằng một ứng dụng khác hoặc phân tán các yêu cầu báo giá trên nhiều ứng dụng. Việc thực hiện một thay đổi như vậy đơn giản chỉ là thêm và loại bỏ các ứng dụng khỏi Bus Tin nhắn. Khi các ứng dụng mới được triển khai, không có ứng dụng nào khác cần phải thay đổi; chúng chỉ cần tiếp tục gửi tin nhắn trên các kênh của bus như thường lệ. |
Giới thiệu
Thông điệp lệnh
Thông điệp Tài liệu
Thông báo sự kiện
Yêu cầu-Phản hồi
Địa chỉ hoàn trả
Người xác định mối tương quan
Chuỗi Thông điệp
Thông báo hết hạn
Chỉ báo định dạng
Trong Chương 3, "Hệ thống Nhắn tin," chúng ta đã thảo luận về Tin nhắn. Khi hai ứng dụng muốn trao đổi một phần dữ liệu, họ thực hiện điều đó bằng cách gói nó trong một tin nhắn. Trong khi một Kênh Tin nhắn không thể truyền tải dữ liệu thô per se, nó có thể truyền tải dữ liệu được gói trong một tin nhắn. Việc tạo ra và gửi một Tin nhắn nảy sinh một số vấn đề khác.
Ý định của tin nhắn Tin nhắn cuối cùng chỉ là các tập hợp dữ liệu, nhưng người gửi có thể có những ý định khác nhau về những gì họ mong đợi người nhận sẽ làm với tin nhắn. Người gửi có thể gửi một Tin nhắn Lệnh, chỉ định một hàm hoặc phương thức trên người nhận mà người gửi muốn gọi. Người gửi đang nói với người nhận mã nào cần chạy. Họ có thể gửi một Tin nhắn Tài liệu, cho phép người gửi truyền một trong các cấu trúc dữ liệu của mình đến người nhận. Người gửi đang chuyển dữ liệu cho người nhận nhưng không chỉ rõ những gì người nhận nên làm với nó. Hoặc họ có thể gửi một Tin nhắn Sự kiện, thông báo cho người nhận về một thay đổi ở người gửi. Người gửi không nói với người nhận cách phản ứng, chỉ đơn giản là cung cấp thông báo.
Trả về một phản hồi Khi một ứng dụng gửi một tin nhắn, nó thường mong đợi một phản hồi xác nhận rằng tin nhắn đã được xử lý và cung cấp kết quả. Đây là một kịch bản Yêu cầu - Phản hồi. Yêu cầu thường là một Tin nhắn Lệnh, và phản hồi là một Tin nhắn Tài liệu chứa giá trị kết quả hoặc một ngoại lệ. Người yêu cầu nên chỉ định một Địa chỉ Trả về trong yêu cầu để thông báo cho người phản hồi biết kênh nào nên được sử dụng để truyền tải phản hồi. Người yêu cầu có thể có nhiều yêu cầu đang được xử lý, vì vậy phản hồi nên chứa một Định danh Tương quan xác định yêu cầu nào mà phản hồi này tương ứng.
Có hai kịch bản Request-Reply phổ biến đáng lưu ý; cả hai đều liên quan đến yêu cầu Tin nhắn Lệnh và phản hồi Tin nhắn Tài liệu tương ứng. Trong kịch bản đầu tiên, Messaging RPC, người yêu cầu không chỉ muốn gọi một hàm trên người phản hồi, mà còn muốn giá trị trả về từ hàm đó. Đây là cách các ứng dụng thực hiện gọi thủ tục từ xa (RPC) bằng cách sử dụng Messaging. Trong kịch bản khác, Messaging Query, người yêu cầu thực hiện một truy vấn; người phản hồi thực hiện truy vấn và trả lại kết quả trong phản hồi. Đây là cách các ứng dụng sử dụng messaging để thực hiện truy vấn từ xa.
Lượng dữ liệu khổng lồ Đôi khi, các ứng dụng muốn chuyển một cấu trúc dữ liệu thật lớn, một cấu trúc có thể không vừa vặn trong một thông điệp đơn. Trong trường hợp này, hãy chia dữ liệu thành các phần nhỏ hơn dễ quản lý và gửi chúng dưới dạng Chuỗi Thông Điệp. Các phần này phải được gửi theo thứ tự, không chỉ là một đống thông điệp, để người nhận có thể tái tạo lại cấu trúc dữ liệu ban đầu.
Tin nhắn chậm Một mối quan tâm với việc nhắn tin là người gửi thường không biết mất bao lâu để người nhận nhận được tin nhắn. Tuy nhiên, nội dung tin nhắn có thể nhạy cảm với thời gian, vì vậy nếu tin nhắn không được nhận trước một thời hạn nhất định, nó nên bị bỏ qua và loại bỏ. Trong tình huống này, người gửi có thể sử dụng Thời hạn Tin nhắn để xác định ngày hết hạn. Nếu hệ thống nhắn tin không thể gửi tin nhắn trước thời hạn của nó, nó nên loại bỏ tin nhắn hoặc chuyển nó đến Kênh Tin nhắn Chết. Tương tự, nếu người nhận nhận được tin nhắn sau thời hạn của nó, họ cũng nên loại bỏ tin nhắn.
Tóm lại, chỉ đơn thuần chọn sử dụng một Tin nhắn là không đủ. Khi dữ liệu cần được truyền đi, nó phải được thực hiện thông qua một Tin nhắn. Chương này giải thích những quyết định khác là một phần của việc làm cho các tin nhắn hoạt động.
Một ứng dụng cần gọi chức năng được cung cấp bởi các ứng dụng khác. Thông thường, nó sẽ sử dụng Gọi Thủ tục Từ xa, nhưng nó muốn tận dụng những lợi ích của việc sử dụng Nhắn tin.
| Làm thế nào để việc nhắn tin được sử dụng để gọi một quy trình trong một ứng dụng khác? |
Lợi thế của Việc Gọi Thủ Tục Từ Xa là nó đồng bộ, vì vậy cuộc gọi được thực hiện ngay lập tức trong khi luồng gọi bị chặn. Nhưng đó cũng là một bất lợi. Nếu cuộc gọi không thể được thực hiện ngay lập tức, hoặc vì mạng bị lỗi hoặc vì tiến trình từ xa không đang chạy và lắng nghe, thì cuộc gọi sẽ không hoạt động. Nếu cuộc gọi là không đồng bộ, nó có thể tiếp tục thử cho đến khi thủ tục trong ứng dụng từ xa được gọi thành công.
Một lời gọi cục bộ đáng tin cậy hơn lời gọi từ xa. Nếu người gọi có thể truyền tải lời gọi của quy trình đến người nhận dưới dạng một Tin nhắn, thì người nhận có thể thực hiện lời gọi đó một cách cục bộ. Vậy câu hỏi đặt ra là làm thế nào để biến lời gọi của một quy trình thành một tin nhắn.
Có một mẫu đã được thiết lập tốt để đóng gói một yêu cầu dưới dạng một đối tượng. Mẫu Lệnh [GoF] cho thấy cách biến một yêu cầu thành một đối tượng có thể được lưu trữ và truyền đi. Nếu đối tượng này là một thông điệp, thì nó có thể được lưu trữ và truyền đi qua một Kênh Thông Điệp. Tương tự, trạng thái của lệnh (chẳng hạn như tham số phương thức) có thể được lưu trữ trong trạng thái của thông điệp.
| Sử dụng một Thông điệp Lệnh để gọi một quy trình trong ứng dụng khác một cách đáng tin cậy.
|
Không có loại tin nhắn cụ thể nào dành cho lệnh; một Tin Nhắn Lệnh đơn giản chỉ là một tin nhắn thông thường có chứa một lệnh. Trong JMS, tin nhắn lệnh có thể là bất kỳ loại tin nhắn nào; ví dụ bao gồm một ObjectMessage chứa một đối tượng lệnh có thể tuần tự hóa, một TextMessage chứa lệnh ở dạng XML, và nhiều loại khác. Trong .NET, tin nhắn lệnh là một Tin Nhắn với một lệnh được lưu trữ trong đó. Một yêu cầu Giao thức Truy cập Đối tượng Đơn giản (SOAP) là một tin nhắn lệnh.
Tin nhắn lệnh thường được gửi qua Kênh Điểm-Đến-Điểm để mỗi lệnh chỉ được tiêu thụ và gọi một lần duy nhất.
| Ví dụ: SOAP và WSDL Với giao thức SOAP [SOAP 1.1] và mô tả dịch vụ WSDL [WSDL 1.1], khi sử dụng các thông điệp SOAP kiểu RPC, thông điệp yêu cầu là một ví dụ của mẫu Thông điệp Lệnh này. Với cách sử dụng này, phần thân của thông điệp SOAP (một tài liệu XML) chứa tên của phương thức sẽ được gọi trên máy nhận và các giá trị tham số được truyền vào phương thức. Tên phương thức này phải giống với một trong các tên thông điệp được định nghĩa trong WSDL của máy nhận. Ví dụ này từ đặc tả SOAP gọi phương thức GetLastTradePrice của máy nhận với một tham số duy nhất có tên là symbol. <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:GetLastTradePrice xmlns:m="Some-URI"> <symbol>DIS</symbol> </m:GetLastTradePrice> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Trong một lệnh SOAP, người ta có thể mong đợi tên phương thức là giá trị của một phần tử <method> tiêu chuẩn nào đó; thực tế, tên phương thức là tên của phần tử phương thức, được thêm tiền tố bởi không gian tên m. Việc có một loại phần tử XML riêng biệt cho mỗi phương thức giúp việc xác thực dữ liệu XML chính xác hơn nhiều, vì loại phần tử phương thức có thể xác định tên, loại và thứ tự của các tham số. |
Một ứng dụng muốn chuyển dữ liệu sang một ứng dụng khác. Nó có thể làm điều đó bằng cách sử dụng Chuyển File hoặc Cơ sở Dữ liệu Chia sẻ, nhưng những phương pháp đó có nhược điểm. Việc chuyển giao có thể hoạt động tốt hơn bằng cách sử dụng Tin nhắn.
| Làm thế nào để nhắn tin có thể được sử dụng để truyền dữ liệu giữa các ứng dụng? |
Đây là một vấn đề cổ điển trong xử lý phân tán: Một quy trình có dữ liệu mà quy trình khác cần. Việc chuyển file rất dễ sử dụng, nhưng không phối hợp các ứng dụng một cách tốt. Một file được viết bởi một ứng dụng có thể ở yên không sử dụng trong một thời gian dài trước khi một ứng dụng khác đọc nó. Nếu có nhiều ứng dụng được cho là phải đọc nó, sẽ không rõ ai nên chịu trách nhiệm xóa nó.
Cơ sở dữ liệu chia sẻ yêu cầu thêm lược đồ mới vào cơ sở dữ liệu để phù hợp với dữ liệu hoặc ép buộc dữ liệu vào lược đồ hiện có. Khi dữ liệu đã vào cơ sở dữ liệu, có nguy cơ rằng các ứng dụng khác mà không nên có quyền truy cập vào dữ liệu giờ đây lại có. Kích hoạt người nhận dữ liệu đến và đọc nó có thể gặp khó khăn, và việc phối hợp nhiều người đọc có thể tạo ra sự nhầm lẫn về ai nên xóa dữ liệu.
Gọi thủ tục từ xa có thể được sử dụng để gửi dữ liệu, nhưng lúc đó người gọi cũng đang thông báo cho người nhận qua thủ tục được gọi phải làm gì với dữ liệu. Tương tự, một Tin Nhắn Lệnh sẽ chuyển dữ liệu nhưng sẽ quá cụ thể về việc người nhận nên làm gì với dữ liệu. Hơn nữa, Gọi thủ tục từ xa giả định sự giao tiếp hai chiều, điều này là không cần thiết nếu chúng ta chỉ muốn truyền dữ liệu từ ứng dụng này sang ứng dụng khác.
Tuy nhiên, chúng tôi vẫn muốn sử dụng Nhắn tin để chuyển dữ liệu. Nhắn tin đáng tin cậy hơn một RPC. Một Kênh Điểm-đến-Điểm có thể được sử dụng để đảm bảo rằng chỉ một người nhận nhận được dữ liệu (không có sự trùng lặp), hoặc một Kênh Xuất Bản-Đăng Ký có thể được sử dụng để đảm bảo rằng bất kỳ người nhận nào muốn dữ liệu đều nhận được một bản sao của nó. Vì vậy, việc khó khăn là tận dụng Nhắn tin mà không làm cho Tin nhắn trở nên quá giống với một RPC.
| Sử dụng Tin nhắn Tài liệu để chuyển giao một cấu trúc dữ liệu giữa các ứng dụng một cách đáng tin cậy.
|
Trong khi một Tin Nhắn Lệnh cho biết người nhận phải thực hiện hành vi nào đó, một Tin Nhắn Tài Liệu chỉ truyền dữ liệu và để cho người nhận quyết định xem có nên làm gì với dữ liệu đó hay không. Dữ liệu là một đơn vị dữ liệu đơn lẻ, một đối tượng đơn hoặc cấu trúc dữ liệu có thể phân tách thành các đơn vị nhỏ hơn.
Các Thông điệp Tài liệu có thể trông rất giống như Thông điệp Sự kiện; sự khác biệt chính nằm ở thời gian và nội dung. Phần quan trọng của một Thông điệp Tài liệu là nội dung của nó: tài liệu. Việc chuyển giao tài liệu thành công là điều quan trọng; thời gian gửi và nhận nó không quan trọng bằng. Đảm bảo Giao hàng có thể là một yếu tố cần xem xét; Hết hạn Thông điệp có lẽ không phải. Ngược lại, sự tồn tại và thời gian của một Thông điệp Sự kiện thường quan trọng hơn nội dung của nó.
Một tin nhắn tài liệu có thể là bất kỳ loại tin nhắn nào trong hệ thống nhắn tin. Trong JMS, tin nhắn tài liệu có thể là một ObjectMessage chứa một đối tượng dữ liệu Serializable cho tài liệu, hoặc nó có thể là một TextMessage chứa dữ liệu dưới dạng XML. Trong .NET, một tin nhắn tài liệu là một Message với dữ liệu được lưu trữ trong đó. Một tin nhắn phản hồi Simple Object Access Protocol (SOAP) là một tin nhắn tài liệu.
Tài liệu Tin nhắn thường được gửi bằng cách sử dụng Kênh Điểm-điểm để di chuyển tài liệu từ một quy trình này sang quy trình khác mà không phải sao chép nó. Tin nhắn có thể được sử dụng để triển khai quy trình làm việc đơn giản bằng cách chuyển tài liệu cho một ứng dụng sửa đổi tài liệu đó và sau đó chuyển nó cho một ứng dụng khác. Trong một số trường hợp, một tin nhắn tài liệu có thể được phát sóng qua Kênh Xuất bản-Đăng ký, nhưng điều này tạo ra nhiều bản sao của tài liệu. Các bản sao cần phải chỉ có thể đọc; nếu không, nếu các bên nhận thay đổi các bản sao, sẽ có nhiều bản sao của tài liệu trong hệ thống, mỗi bản chứa dữ liệu khác nhau. Trong Yêu cầu-Phản hồi, phản hồi thường là một Tài liệu Tin nhắn, trong đó giá trị kết quả là tài liệu.
| Ví dụ: Java và XML Ví dụ sau (lấy từ ví dụ về sơ đồ XML trong [Graham]) cho thấy cách một đơn đặt hàng đơn giản có thể được biểu diễn dưới dạng XML và được gửi dưới dạng thông điệp sử dụng JMS. [View full width] Session session = // Obtain the session Destination dest = // Obtain the destination MessageProducer sender = session.createProducer(dest); String purchaseOrder = " <po id=\"48881\" submitted=\"2002-04-23\"> <shipTo> <company>Chocoholics</company> <street>2112 North Street</street> <city>Cary</city> <state>NC</state> <postalCode>27522</postalCode> </shipTo> <order> <item sku=\"22211\" quantity=\"40\"> <description>Bunny, Dark Chocolate, Large< |
| Ví dụ: SOAP và WSDL Với giao thức SOAP [SOAP 1.1] và mô tả dịch vụ WSDL [WSDL 1.1], khi sử dụng tin nhắn SOAP theo kiểu tài liệu, tin nhắn SOAP là một ví dụ về Tin nhắn Tài liệu. Phần thân tin nhắn SOAP là một tài liệu XML (hoặc một kiểu cấu trúc dữ liệu nào đó đã được chuyển đổi thành tài liệu XML), và tin nhắn SOAP truyền tải tài liệu đó từ người gửi (ví dụ: khách hàng) đến người nhận (ví dụ: máy chủ). Khi sử dụng việc nhắn tin SOAP theo kiểu RPC, thông điệp phản hồi là một ví dụ của mẫu này. Với cách sử dụng này, phần thân của thông điệp SOAP (một tài liệu XML) chứa giá trị trả về từ phương thức đã được gọi. Ví dụ này từ đặc tả SOAP trả về câu trả lời từ việc gọi phương thức GetLastTradePrice. [View full width] <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap |
Nhiều ứng dụng muốn sử dụng thông báo sự kiện để phối hợp các hành động của chúng và muốn sử dụng Tin nhắn để truyền đạt những sự kiện đó.
| Làm thế nào để việc nhắn tin có thể được sử dụng để truyền đạt sự kiện từ một ứng dụng này sang ứng dụng khác? |
Đôi khi, một sự kiện xảy ra trong một đối tượng mà một đối tượng khác cần biết. Ví dụ cổ điển là kiến trúc Model-View-Controller [POSA], nơi mà mô hình thay đổi trạng thái của nó và phải thông báo cho các view của nó để chúng có thể vẽ lại. Việc thông báo thay đổi như vậy cũng có thể hữu ích trong các hệ thống phân tán. Ví dụ, trong một hệ thống B2B, một doanh nghiệp có thể cần thông báo cho các doanh nghiệp khác về sự thay đổi giá hoặc một danh mục sản phẩm hoàn toàn mới.
Một quá trình có thể sử dụng Gọi Thủ tục Từ xa để thông báo cho các ứng dụng khác về các sự kiện thay đổi, nhưng điều đó yêu cầu rằng bên nhận phải chấp nhận sự kiện ngay lập tức, ngay cả khi họ không muốn nhận sự kiện ngay lúc này. RPC cũng yêu cầu rằng quá trình thông báo phải biết mọi quá trình lắng nghe và thực hiện một RPC trên mỗi quá trình lắng nghe.
Mẫu Observer [GoF] mô tả cách thiết kế một chủ thể thông báo sự kiện và các quan sát viên tiêu thụ sự kiện. Một chủ thể thông báo cho một quan sát viên về một sự kiện bằng cách gọi phương thức Update() của quan sát viên. Update() có thể được triển khai dưới dạng RPC, nhưng nó sẽ mang theo tất cả những thiếu sót của RPC.
Sẽ tốt hơn nếu gửi thông báo sự kiện không đồng bộ, dưới dạng một Tin nhắn. Bằng cách này, chủ thể có thể gửi thông báo khi đã sẵn sàng, và mỗi người quan sát có thể nhận thông báo nếu và khi họ sẵn sàng.
| Sử dụng Thông điệp Sự kiện để thông báo sự kiện đáng tin cậy, không đồng bộ giữa các ứng dụng.
|
Khi một đối tượng có một sự kiện để thông báo, nó tạo ra một đối tượng sự kiện, bọc nó trong một thông điệp và gửi nó qua một kênh như một Thông điệp Sự kiện. Người quan sát nhận Thông điệp Sự kiện, lấy sự kiện và xử lý nó. Việc gửi thông điệp không thay đổi sự kiện được thông báo, mà chỉ đảm bảo rằng thông báo đến được người quan sát.
Một Thông điệp Sự kiện có thể là bất kỳ loại thông điệp nào trong hệ thống nhắn tin. Trong Java, một sự kiện có thể là một đối tượng hoặc dữ liệu, chẳng hạn như một tài liệu XML. Do đó, nó có thể được truyền qua JMS dưới dạng ObjectMessage, TextMessage, và vân vân. Trong .NET, một thông điệp sự kiện là một Thông điệp với sự kiện được lưu trữ trong đó.
Sự khác biệt giữa Thông điệp Sự kiện và Thông điệp Tài liệu là vấn đề thời gian và nội dung. Nội dung của một sự kiện thường ít quan trọng hơn. Nhiều sự kiện thậm chí có thân tin nhắn trống; sự kiện xảy ra của chúng chỉ đơn giản cho người quan sát biết để phản ứng. Thời gian của một sự kiện rất quan trọng; chủ thể nên phát đi một sự kiện ngay khi có sự thay đổi, và người quan sát nên xử lý nó nhanh chóng khi nó vẫn còn liên quan. Đảm bảo Giao hàng thường không hữu ích với các sự kiện, vì chúng xảy ra thường xuyên và cần được giao nhanh chóng. Hết hạn Tin nhắn có thể rất hữu ích để đảm bảo rằng một sự kiện được xử lý nhanh chóng hoặc không được xử lý hoàn toàn.
Hệ thống B2B phải thông báo cho các doanh nghiệp khác về sự thay đổi giá cả hoặc sản phẩm, ví dụ, có thể sử dụng Thông điệp Sự kiện, Thông điệp Tài liệu, hoặc một sự kết hợp của cả hai. Nếu một thông điệp cho biết rằng giá của ổ đĩa máy tính đã thay đổi, đó là một sự kiện. Nếu thông điệp cung cấp thông tin về ổ đĩa, bao gồm cả giá mới, đó là một tài liệu được gửi như một sự kiện. Một thông điệp khác thông báo về danh mục mới và URL của nó là một sự kiện, trong khi một thông điệp tương tự chứa danh mục mới thực sự là một sự kiện có chứa một tài liệu.
Cái nào thì tốt hơn? Mô hình Observer mô tả điều này như một sự đánh đổi giữa mô hình đẩy và mô hình kéo. Mô hình đẩy gửi thông tin về sự thay đổi như một phần của cập nhật, trong khi mô hình kéo gửi thông tin tối thiểu, và các đối tượng quan sát muốn biết thêm thông tin sẽ yêu cầu bằng cách gửi GetState() tới chủ đề. Hai mô hình này liên quan đến việc nhắn tin như vậy.
Mô hình đẩy Thông điệp là một thông điệp tài liệu/sự kiện kết hợp; việc giao thông điệp thông báo rằng trạng thái đã xảy ra và nội dung của thông điệp là trạng thái mới. Điều này hiệu quả hơn nếu tất cả các người quan sát đều muốn những chi tiết này, nhưng ngược lại, nó có thể là sự kết hợp tồi tệ nhất của cả hai thế giới: một thông điệp lớn được gửi thường xuyên và thường bị nhiều người quan sát bỏ qua.
Mô hình kéo Có ba thông điệp:
Cập nhật là một thông điệp sự kiện thông báo cho người quan sát về sự kiện.
Yêu cầu trạng thái là một thông điệp lệnh mà một quan sát viên quan tâm sử dụng để yêu cầu thông tin chi tiết từ chủ thể.
Phản hồi của tiểu bang là một thông điệp tài liệu mà chủ thể sử dụng để gửi thông tin chi tiết cho người quan sát.
Ưu điểm của mô hình kéo là các thông điệp cập nhật nhỏ, chỉ những người quan tâm mới yêu cầu chi tiết, và tiềm năng mỗi người quan tâm có thể yêu cầu các chi tiết mà họ cụ thể quan tâm. Nhược điểm là số kênh bổ sung cần thiết và lưu lượng truy cập phát sinh do có nhiều hơn một thông điệp.
Để biết thêm chi tiết về cách triển khai Observer sử dụng messaging, xem phần "Ví dụ về JMS Publish/Subscribe" trong Chương 6, "Giữa: Messaging Đơn Giản."
Thông thường không có lý do gì để giới hạn một thông điệp sự kiện cho một người nhận duy nhất qua Kênh Điểm-đến-Điểm; thông điệp thường được phát sóng qua Kênh Xuất bản-Đăng ký để tất cả các quy trình quan tâm đều nhận được thông báo. Trong khi một Thông điệp Tài liệu cần được tiêu thụ để tránh mất tài liệu, người nhận Thông điệp Sự kiện thường có thể bỏ qua các thông điệp khi họ quá bận rộn để xử lý chúng, vì vậy các người đăng ký thường có thể là không bền (không phải Người Đăng Ký Bền). Thông điệp Sự kiện là một phần quan trọng trong việc triển khai mẫu Người Quan Sát sử dụng tin nhắn.
Khi hai ứng dụng giao tiếp qua Tin nhắn, việc giao tiếp chỉ diễn ra theo một chiều. Các ứng dụng có thể muốn có một cuộc trò chuyện hai chiều.
| Khi một ứng dụng gửi một tin nhắn, làm thế nào nó có thể nhận được phản hồi từ người nhận? |
Nhắn tin cung cấp việc truyền thông một chiều giữa các ứng dụng. Tin nhắn di chuyển trên một Kênh Tin nhắn theo một hướng; chúng đi từ người gửi đến người nhận. Việc truyền tải không đồng bộ này làm cho việc giao hàng trở nên đáng tin cậy hơn và tách biệt người gửi khỏi người nhận.
Vấn đề là giao tiếp giữa các thành phần thường cần phải là hai chiều. Khi một chương trình gọi một hàm, nó nhận được giá trị trả về. Khi nó thực hiện một truy vấn, nó nhận được kết quả truy vấn. Khi một thành phần thông báo cho một thành phần khác về một sự thay đổi, nó có thể muốn nhận một sự xác nhận. Làm thế nào để việc nhắn tin có thể hai chiều?
Có lẽ một người gửi và người nhận có thể chia sẻ một thông điệp đồng thời. Sau đó, mỗi ứng dụng có thể thêm thông tin vào thông điệp để bên kia tiêu thụ. Nhưng đó không phải là cách mà việc nhắn tin hoạt động. Một thông điệp được gửi trước và sau đó được nhận, vì vậy người gửi và người nhận không thể cùng truy cập vào thông điệp cùng một lúc.
Có lẽ người gửi có thể giữ một tham chiếu đến thông điệp. Sau đó, một khi người nhận đặt phản hồi của mình vào thông điệp, người gửi có thể rút lại thông điệp đó. Điều này có thể hoạt động cho các ghi chú kẹp trên dây phơi quần áo, nhưng đó không phải là cách mà Kênh Thông điệp hoạt động. Một kênh truyền tải các thông điệp theo một chiều. Điều cần thiết là một thông điệp hai chiều trên một kênh hai chiều.
| Gửi một cặp tin nhắn Yêu cầu-Phản hồi, mỗi tin nhắn trên một kênh riêng biệt.
|
Yêu cầu-Phản hồi có hai người tham gia:
Người yêu cầu gửi một tin nhắn yêu cầu và chờ đợi một tin nhắn hồi đáp.
Người trả lời nhận tin nhắn yêu cầu và phản hồi bằng một tin nhắn trả lời.
Kênh yêu cầu có thể là Kênh Điểm-đến-Điểm hoặc Kênh Xuất-bản-Theo-dõi. Sự khác biệt nằm ở việc liệu yêu cầu có nên được phát sóng đến tất cả các bên quan tâm hay chỉ nên được xử lý bởi một người tiêu dùng duy nhất. Kênh phản hồi, ngược lại, hầu như luôn là điểm-đến-điểm, vì thường thì không có ý nghĩa gì khi phát sóng các phản hồi; chúng chỉ nên được trả về cho người yêu cầu.
Khi một người gọi thực hiện một Kêu gọi Thủ tục Từ xa, luồng của người gọi phải chặn lại trong khi chờ phản hồi. Với Yêu cầu-Trả lời, người yêu cầu có hai cách tiếp cận để nhận phản hồi.
Khối đồng bộ Một luồng đơn trong caller gửi tin nhắn yêu cầu, chặn (như một Người tiêu thụ Đăng ký) để chờ tin nhắn phản hồi, và sau đó xử lý phản hồi. Điều này dễ dàng để thực hiện, nhưng nếu người yêu cầu bị crash, họ sẽ gặp khó khăn trong việc khôi phục lại luồng đang bị chặn. Luồng yêu cầu đang chờ phản hồi ngụ ý rằng chỉ có một yêu cầu đang chờ hoặc rằng kênh phản hồi cho yêu cầu này là riêng tư cho luồng này.
Gọi không đồng bộ Một luồng trong caller gửi tin nhắn yêu cầu và thiết lập một callback cho phản hồi. Một luồng riêng biệt lắng nghe các tin nhắn phản hồi. Khi một tin nhắn phản hồi đến, luồng phản hồi gọi lại callback thích hợp, điều này khôi phục lại ngữ cảnh của caller và xử lý phản hồi. Cách tiếp cận này cho phép nhiều yêu cầu đang chờ xử lý chia sẻ một kênh phản hồi duy nhất và một luồng phản hồi duy nhất để xử lý phản hồi cho nhiều luồng yêu cầu. Nếu yêu cầu gặp sự cố, nó có thể khôi phục bằng cách đơn giản là khởi động lại luồng phản hồi. Tuy nhiên, một phức tạp bổ sung là cơ chế callback phải khôi phục lại ngữ cảnh của caller.
Hai ứng dụng gửi yêu cầu và phản hồi cho nhau thì không thực sự hữu ích. Điều thú vị là hai tin nhắn đó đại diện cho điều gì.
Gửi tin nhắn RPC Đây là cách để triển khai Gọi Thủ tục Từ xa (RPC) sử dụng tin nhắn. Yêu cầu là một Tin nhắn Lệnh mô tả chức năng mà bên trả lời nên gọi. Phản hồi là một Tin nhắn Tài liệu chứa giá trị trả về của chức năng hoặc ngoại lệ.
Truy vấn Tin nhắn Đây là cách thực hiện một truy vấn từ xa sử dụng tin nhắn. Yêu cầu là một Tin nhắn Lệnh chứa truy vấn, và phản hồi là kết quả của truy vấn, có thể là một Chuỗi Tin nhắn.
Thông báo/Xác nhận Điều này cung cấp thông báo sự kiện với sự xác nhận, sử dụng tin nhắn. Yêu cầu là một Tin Nhắn Sự Kiện cung cấp thông báo, và phản hồi là một Tin Nhắn Tài Liệu xác nhận thông báo. Sự xác nhận có thể tự nó là một yêu cầu khác, yêu cầu thông tin chi tiết về sự kiện.
Yêu cầu giống như một cuộc gọi phương thức. Do đó, phản hồi là một trong ba khả năng:
Void chỉ đơn giản thông báo cho người gọi rằng phương thức đã kết thúc để người gọi có thể tiếp tục.
Giá trị kết quả Một đối tượng duy nhất là giá trị trả về của phương thức.
Ngoại lệ Một đối tượng ngoại lệ duy nhất cho thấy rằng phương thức đã dừng lại trước khi hoàn thành thành công, và chỉ ra lý do tại sao.
Yêu cầu nên bao gồm một Địa chỉ Trả lại để thông báo cho người trả lời nơi gửi phản hồi. Phản hồi nên bao gồm một Định danh Tương quan xác định yêu cầu mà phản hồi này thuộc về.
| Ví dụ: Tin nhắn SOAP 1.1 Các thông điệp SOAP đi theo cặp Yêu cầu-Phản hồi. Một thông điệp yêu cầu SOAP chỉ rõ một dịch vụ mà người gửi muốn gọi trên người nhận, trong khi một thông điệp phản hồi SOAP chứa kết quả của việc gọi dịch vụ. Thông điệp phản hồi này chứa hoặc một giá trị kết quả hoặc một lỗi, tương đương với ngoại lệ trong SOAP [SOAP 1.1]. |
| Ví dụ: Mẫu trao đổi thông điệp phản hồi SOAP 1.2 Trong khi SOAP 1.1 mô tả một cách lỏng lẻo các thông điệp phản hồi, SOAP 1.2 giới thiệu một mẫu Trao đổi Thông điệp Yêu cầu-Phản hồi rõ ràng [SOAP 1.2 Phần 2]. Mẫu này mô tả một phản hồi riêng biệt, có thể bất đồng bộ đối với một yêu cầu SOAP. |
| Ví dụ: Đối tượng Yêu cầu JMS JMS bao gồm một vài tính năng có thể được sử dụng để triển khai Request-Reply. Một Hàng Đợi Tạm Thời là một Hàng Đợi có thể được tạo ra một cách lập trình và chỉ tồn tại lâu như Kết Nối đã được sử dụng để tạo ra nó. Chỉ có Các Người Tiêu Thụ Tin Nhắn được tạo ra bởi cùng một kết nối mới có thể đọc từ hàng đợi, vì vậy nó thực sự là riêng tư đối với kết nối đó [JMS 1.1]. Những nhà sản xuất tin nhắn (Message Producers) biết về hàng đợi riêng được tạo ra này như thế nào? Một người yêu cầu (requestor) tạo một hàng đợi tạm thời và chỉ định nó trong thuộc tính reply-to của tin nhắn yêu cầu (xem Địa chỉ Trả lại). Một người trả lời (replier) cư xử đúng cách sẽ gửi phản hồi trở lại trên hàng đợi đã chỉ định, mà người trả lời thậm chí không biết đến nếu nó không phải là một thuộc tính của tin nhắn yêu cầu. Đây là một cách đơn giản mà người yêu cầu có thể sử dụng để đảm bảo rằng các phản hồi luôn quay trở lại với họ. Nhược điểm của hàng đợi tạm thời là khi kết nối của chúng đóng lại, hàng đợi và bất kỳ thông điệp nào trong đó sẽ bị xóa. Tương tự, hàng đợi tạm thời không thể cung cấp Đảm bảo Giao hàng; nếu hệ thống nhắn tin bị sập, thì kết nối sẽ bị mất, do đó hàng đợi và các thông điệp của nó cũng sẽ bị mất. JMS cũng cung cấp QueueRequestor, một lớp đơn giản để gửi yêu cầu và nhận phản hồi. Một requestor chứa một QueueSender để gửi yêu cầu và một QueueReceiver để nhận phản hồi. Mỗi requestor tạo một hàng đợi tạm thời của riêng mình để nhận phản hồi và chỉ định điều đó trong thuộc tính reply-to của yêu cầu [JMS 1.1]. Một requestor làm cho việc gửi yêu cầu và nhận phản hồi trở nên rất đơn giản. [View full width] QueueConnection connection = // obtain the connection Queue requestQueue = // obtain the queue Message request = // create the request message QueueSession session = connection.createQueueSession(false, Một phương pháp yêu cầu gửi thông điệp yêu cầu và chặn cho đến khi nhận được thông điệp trả lời. Hàng đợi tạm thời, được sử dụng bởi Yêu cầu Hàng đợi, là một Kênh Điểm-đến-Điểm. Các kênh tương đương với Đăng ký - Chia sẻ là Chủ đề Tạm thời và Yêu cầu Chủ đề. |
Ứng dụng của tôi đang sử dụng Tin nhắn để thực hiện Yêu cầu-Trả lời.
| Người trả lời biết gửi phản hồi đến đâu như thế nào? |
Các tin nhắn thường được coi là hoàn toàn độc lập, đến nỗi bất kỳ người gửi nào cũng có thể gửi một tin nhắn trên bất kỳ kênh nào khi họ muốn. Tuy nhiên, các tin nhắn thường có sự liên kết với nhau. Với cặp Yêu cầu-Trả lời, hai tin nhắn có vẻ độc lập, nhưng tin nhắn trả lời có mối tương quan một-một với tin nhắn yêu cầu đã gây ra nó. Do đó, người trả lời xử lý tin nhắn yêu cầu không thể đơn giản gửi tin nhắn trả lời trên bất kỳ kênh nào mà nó muốn; họ phải gửi nó trên kênh mà người yêu cầu mong đợi nhận được phản hồi.
Mỗi người nhận có thể tự động biết kênh nào để gửi phản hồi, nhưng việc mã hóa những giả định như vậy làm cho phần mềm kém linh hoạt và khó bảo trì hơn. Hơn nữa, một người phản hồi đơn lẻ có thể đang xử lý các cuộc gọi từ nhiều người yêu cầu khác nhau, vì vậy kênh phản hồi không giống nhau cho mỗi tin nhắn; nó phụ thuộc vào người yêu cầu nào đã gửi tin nhắn yêu cầu.
Không chắc nên gửi phản hồi đến đâu

Một yêu cầu có thể không muốn nhận phản hồi quay trở lại. Thay vào đó, nó có thể có một bộ xử lý callback liên quan để xử lý các phản hồi, và bộ xử lý callback này có thể theo dõi một kênh khác so với yêu cầu (hoặc yêu cầu có thể không theo dõi bất kỳ kênh nào). Yêu cầu có thể có nhiều bộ xử lý callback, yêu cầu phản hồi cho các yêu cầu khác nhau từ cùng một yêu cầu được gửi đến các bộ xử lý khác nhau.
Kênh phản hồi sẽ không nhất thiết phải truyền lại các phản hồi cho người yêu cầu; nó sẽ truyền chúng đến bất kỳ ai mà người yêu cầu muốn xử lý các phản hồi, vì nó đang lắng nghe kênh mà người yêu cầu đã chỉ định. Vì vậy, việc biết người yêu cầu đã gửi một yêu cầu nào hay kênh nào được sử dụng để gửi không nhất thiết sẽ cho người phản hồi biết kênh nào để gửi phản hồi. Ngay cả khi có, người phản hồi vẫn phải suy luận kênh phản hồi nào để sử dụng cho một người yêu cầu hoặc kênh yêu cầu cụ thể. Thật dễ dàng hơn cho yêu cầu khi chỉ định rõ ràng kênh phản hồi nào được sử dụng. Điều cần thiết là một cách để người yêu cầu thông báo cho người phản hồi nơi và cách để gửi lại một phản hồi.
| Thông điệp yêu cầu nên chứa một Địa chỉ Trả lại cho biết nơi gửi thông điệp phản hồi.
|
Bằng cách này, người trả lời không cần phải biết nơi gửi câu trả lời; họ có thể chỉ cần lấy địa chỉ kênh trả lời từ thông điệp yêu cầu. Nếu các thông điệp khác nhau gửi đến cùng một người trả lời yêu cầu các câu trả lời đến những nơi khác nhau, người trả lời có thể xác định từ mỗi thông điệp yêu cầu nơi gửi câu trả lời cho yêu cầu đó. Điều này tổng hợp kiến thức về các kênh sử dụng cho yêu cầu và câu trả lời bên trong yêu cầu, do đó những quyết định đó không cần phải được lập trình cứng trong người trả lời. Một Địa Chỉ Trả lại được đưa vào tiêu đề của một thông điệp vì nó không phải là một phần của dữ liệu ứng dụng đang được truyền tải.
Địa chỉ trả về của một tin nhắn tương tự như trường trả lời trong một tin nhắn email. Địa chỉ email trả lời thường giống với địa chỉ gửi, nhưng người gửi có thể đặt nó thành một địa chỉ khác để nhận phản hồi tại một tài khoản khác thay vì tài khoản được sử dụng để gửi tin nhắn ban đầu.
Khi phản hồi được gửi lại qua kênh được chỉ định bởi Địa Chỉ Trả Lời, có thể nó cũng cần một Nhận Dạng Tương Quan. Địa Chỉ Trả Lời cho người nhận biết kênh nào để đặt thông điệp phản hồi; Nhận Dạng Tương Quan cho người gửi biết yêu cầu nào mà phản hồi đó dành cho.
| Ví dụ: Thuộc tính Reply-To của JMS Các tin nhắn JMS có một thuộc tính được định nghĩa trước cho Địa chỉ Trả lời, JMSReplyTo. Kiểu của nó là một Đích (một Chủ đề hoặc Hàng đợi) thay vì chỉ là một chuỗi cho tên đích, điều này đảm bảo rằng đích (ví dụ, Kênh Tin nhắn) thực sự tồn tại, ít nhất là khi yêu cầu được gửi đi. Một người gửi muốn chỉ định kênh phản hồi là một Hàng đợi sẽ thực hiện như sau: Queue requestQueue = // Specify the request destination Queue replyQueue = // Specify the reply destination Message requestMessage = // Create the request message requestMessage.setJMSReplyTo(replyQueue); MessageProducer requestSender = session.createProducer(requestQueue); requestSender.send(requestMessage); Sau đó, người nhận sẽ gửi tin nhắn trả lời như sau: [View full width] Queue requestQueue = // Specify the request destination MessageConsumer requestReceiver = session.createConsumer |
| Ví dụ: Thuộc tính Response-Queue của .NET CÁc thông điệp .NET cũng có một thuộc tính được xác định trước cho Địa chỉ Trả lại, ResponseQueue. Kiểu của nó là MessageQueue (ví dụ, Kênh Thông điệp), hàng đợi mà ứng dụng nên gửi thông điệp phản hồi tới [SysMsg], [Dickman]. |
| Ví dụ: Yêu cầu/Phản hồi Dịch vụ Web SOAP 1.2 bao gồm mẫu Trao đổi Tin nhắn Yêu cầu-Phản hồi [SOAP 1.2 Phần 2], nhưng địa chỉ để gửi phản hồi không được chỉ định và do đó là ngụ ý. Mẫu SOAP này sẽ cần hỗ trợ một Địa chỉ Trả lại tùy chọn để thực sự làm cho các tin nhắn SOAP trở nên bất đồng bộ và tách rời người phản hồi khỏi người yêu cầu. Tiêu chuẩn WS-Addressing đang nổi lên giúp giải quyết vấn đề này bằng cách xác định cách nhận diện một điểm cuối dịch vụ Web và những phần tử XML nào cần sử dụng. Địa chỉ như vậy có thể được sử dụng trong một thông điệp SOAP để chỉ định Địa chỉ Trả lại. Xem phần thảo luận về WS-Addressing trong Chương 14, "Những nhận xét kết thúc." |
Ứng dụng của tôi đang sử dụng Tin nhắn để thực hiện một Yêu cầu-Trả lời và đã nhận được thông điệp trả lời.
| Người yêu cầu đã nhận được phản hồi biết phản hồi này là cho yêu cầu nào? |
Khi một quá trình gọi một quá trình khác qua Gọi Thủ Tục Từ Xa, cuộc gọi là đồng bộ, vì vậy không có sự nhầm lẫn về cuộc gọi nào đã tạo ra kết quả cụ thể. Nhưng Gửi Tin Nhắn là không đồng bộ, vì vậy từ quan điểm của người gọi, họ thực hiện cuộc gọi, và rồi một thời gian sau đó, một kết quả xuất hiện. Người gọi có thể thậm chí không nhớ đã thực hiện yêu cầu, hoặc có thể đã thực hiện quá nhiều yêu cầu đến nỗi không còn biết đây là kết quả cho yêu cầu nào. Bây giờ, khi người gọi cuối cùng nhận được kết quả, họ có thể không biết nên làm gì với nó, điều này làm suy yếu mục đích của việc thực hiện cuộc gọi ngay từ đầu.
Không thể ghép phản hồi với yêu cầu

Có một vài cách tiếp cận mà người gọi có thể sử dụng để tránh sự nhầm lẫn này. Họ có thể chỉ thực hiện một cuộc gọi tại một thời điểm và chờ câu trả lời trước khi gửi yêu cầu khác, vì vậy sẽ chỉ có một yêu cầu chưa được xử lý tại bất kỳ thời điểm nào. Tuy nhiên, cách này sẽ làm giảm đáng kể thông lượng xử lý. Người gọi có thể giả định rằng họ sẽ nhận được câu trả lời theo thứ tự mà họ gửi yêu cầu, nhưng hệ thống nhắn tin không đảm bảo thứ tự mà các tin nhắn được gửi đi (xem Resequencer), và tất cả các yêu cầu có thể không mất cùng một khoảng thời gian để xử lý, vì vậy giả định của người gọi sẽ không chính xác. Người gọi có thể thiết kế các yêu cầu của mình sao cho không cần câu trả lời, nhưng ràng buộc này sẽ làm cho nhắn tin trở nên vô dụng cho nhiều mục đích.
Điều mà người gọi cần là tin nhắn phản hồi có một con trỏ hoặc tham chiếu đến tin nhắn yêu cầu, nhưng các tin nhắn không tồn tại trong một không gian bộ nhớ ổn định để có thể được tham chiếu bởi các biến. Tuy nhiên, một tin nhắn có thể có loại khóa nào đó, một định danh duy nhất như khóa cho một hàng trong bảng cơ sở dữ liệu quan hệ. Định danh duy nhất như vậy có thể được sử dụng để nhận diện tin nhắn này so với các tin nhắn khác, các khách hàng sử dụng tin nhắn, và vân vân.
| Mỗi tin nhắn hồi đáp nên chứa một Định danh Tương quan, một định danh duy nhất cho biết tin nhắn yêu cầu nào mà tin nhắn hồi đáp này liên quan đến.
|
Có sáu phần trong Nhận diện Tương quan.
Người yêu cầu Một ứng dụng thực hiện một nhiệm vụ kinh doanh bằng cách gửi một yêu cầu và chờ phản hồi.
Người trả lời Một ứng dụng khác nhận yêu cầu, thực hiện nó và sau đó gửi phản hồi. Nó lấy ID yêu cầu từ yêu cầu và lưu trữ nó như là ID tương ứng trong phản hồi.
Yêu cầu Một tin nhắn gửi từ người yêu cầu đến người trả lời, chứa một ID yêu cầu.
Trả lời Một tin nhắn được gửi từ người trả lời đến người yêu cầu, chứa một mã tương ứng.
ID yêu cầu Một mã trong yêu cầu mà xác định duy nhất yêu cầu đó.
ID tương quan Một mã thông báo trong phản hồi có giá trị giống như ID yêu cầu trong yêu cầu.
Đây là cách mà một Bộ nhận diện Tương quan hoạt động: Khi người yêu cầu tạo một thông điệp yêu cầu, họ gán cho yêu cầu một ID yêu cầu, một định danh khác với tất cả các yêu cầu hiện đang chờ xử lý, tức là các yêu cầu chưa có phản hồi. Khi người phản hồi xử lý yêu cầu, họ lưu trữ ID yêu cầu và thêm ID đó vào phản hồi như một ID tương quan. Khi người yêu cầu xử lý phản hồi, họ sử dụng ID tương quan để biết phản hồi là dành cho yêu cầu nào. Điều này được gọi là Bộ nhận diện Tương quan vì cách mà người gọi sử dụng định danh để tương quan (tức là, khớp; thể hiện mối quan hệ) mỗi phản hồi với yêu cầu đã gây ra nó.
Như thường lệ trong việc nhắn tin, người yêu cầu và người trả lời phải đồng ý về một số chi tiết. Họ phải đồng ý về tên và loại thuộc tính ID yêu cầu, và họ phải đồng ý về tên và loại thuộc tính ID tương quan. Tương tự, định dạng tin nhắn yêu cầu và trả lời phải định nghĩa các thuộc tính đó hoặc cho phép chúng được thêm dưới dạng thuộc tính tùy chỉnh. Ví dụ, nếu người yêu cầu lưu trữ ID yêu cầu trong một phần tử XML cấp đầu tiên có tên là request_id và giá trị là một số nguyên, người trả lời phải biết điều này để có thể tìm thấy giá trị ID yêu cầu và xử lý nó một cách chính xác. Giá trị ID yêu cầu và giá trị ID tương quan thường có cùng loại; nếu không, người yêu cầu phải biết cách mà người trả lời sẽ chuyển đổi ID yêu cầu thành ID trả lời.
Mẫu này là một phiên bản đơn giản hơn, cụ thể cho thông điệp của mẫu Chốt hoàn thành không đồng bộ [POSA2]. Người yêu cầu là Người khởi xướng, người trả lời là Dịch vụ, người tiêu dùng trong yêu cầu xử lý câu trả lời là Bộ xử lý hoàn thành, và Mã định danh tương quan mà người tiêu dùng sử dụng để khớp câu trả lời với yêu cầu là Chốt hoàn thành không đồng bộ.
Một ID tương quan (và cũng là ID yêu cầu) thường được đặt trong tiêu đề của một tin nhắn thay vì trong nội dung. ID không phải là một phần của lệnh hoặc dữ liệu mà người yêu cầu đang cố gắng giao tiếp với người đáp trả. Thực tế, người đáp trả không thực sự sử dụng ID này chút nào; họ chỉ lưu ID từ yêu cầu và thêm nó vào phần trả lời vì lợi ích của người yêu cầu. Vì nội dung tin nhắn là thông tin được truyền tải giữa hai hệ thống, và ID không phải là một phần của điều đó, nên ID được đưa vào tiêu đề.
Nội dung chính của mẫu là tin nhắn phản hồi chứa một mã (ID tương ứng) xác định yêu cầu tương ứng (thông qua ID yêu cầu của nó). Có nhiều phương pháp khác nhau để đạt được điều này.
Cách tiếp cận đơn giản nhất là mỗi yêu cầu chứa một ID duy nhất, chẳng hạn như ID tin nhắn, và ID tương quan của phản hồi là ID duy nhất của yêu cầu. Điều này liên kết phản hồi với yêu cầu tương ứng của nó. Tuy nhiên, khi người yêu cầu cố gắng xử lý phản hồi, việc biết tin nhắn yêu cầu thường không giúp ích nhiều. Điều mà người yêu cầu thực sự muốn là một lời nhắc về công việc kinh doanh nào đã dẫn đến việc gửi yêu cầu ngay từ đầu, để người yêu cầu có thể hoàn thành công việc kinh doanh sử dụng dữ liệu trong phản hồi.
Nhiệm vụ kinh doanh, chẳng hạn như cần thực hiện một giao dịch chứng khoán hoặc gửi đơn hàng mua, có lẽ có mã định danh đối tượng kinh doanh riêng biệt (chẳng hạn như mã đơn hàng), để mã định danh duy nhất của nhiệm vụ kinh doanh có thể được sử dụng làm mã xác định tương quan yêu cầu-phản hồi. Sau đó, khi người yêu cầu nhận được phản hồi và mã xác định tương quan của nó, họ có thể bỏ qua thông điệp yêu cầu và đi thẳng đến đối tượng kinh doanh mà nhiệm vụ của nó đã gây ra yêu cầu ngay từ đầu. Trong trường hợp này, thay vì sử dụng thuộc tính mã thông điệp yêu cầu tích hợp sẵn và thuộc tính mã xác định tương quan phản hồi, người yêu cầu và người phản hồi nên sử dụng một thuộc tính mã đối tượng kinh doanh tùy chỉnh trong cả yêu cầu và phản hồi để xác định đối tượng kinh doanh mà cặp thông điệp yêu cầu-phản hồi này đang thực hiện.
Một cách tiếp cận hòa giải là để người yêu cầu giữ một bản đồ các ID yêu cầu và ID đối tượng kinh doanh. Điều này đặc biệt hữu ích khi người yêu cầu muốn giữ ID đối tượng ở chế độ riêng tư hoặc khi người yêu cầu không kiểm soát được việc thực hiện của người hồi đáp và chỉ có thể phụ thuộc vào việc người hồi đáp sao chép ID tin nhắn yêu cầu vào ID tương quan của phản hồi. Trong trường hợp này, khi người yêu cầu nhận được phản hồi, họ tra cứu ID tương quan trong bản đồ để lấy ID đối tượng kinh doanh và sau đó sử dụng nó để tiếp tục thực hiện nhiệm vụ kinh doanh với dữ liệu phản hồi.
Các thông điệp có thuộc tính ID thông điệp và ID tương quan riêng biệt để các cặp thông điệp yêu cầu-phản hồi có thể được xâu chuỗi với nhau. Điều này xảy ra khi một yêu cầu gây ra một phản hồi, và phản hồi lại trở thành một yêu cầu khác gây ra một phản hồi khác, và cứ như vậy. ID thông điệp của một thông điệp xác định duy nhất yêu cầu mà nó đại diện; nếu thông điệp cũng có một ID tương quan, thì thông điệp đó cũng là một phản hồi cho một thông điệp yêu cầu khác, như được xác định bởi ID tương quan.
Chuỗi Yêu cầu-Trả lời

Chuỗi chỉ hữu ích nếu một ứng dụng muốn truy xuất lại đường đi của các thông điệp từ phản hồi mới nhất trở về yêu cầu ban đầu. Thường thì, tất cả những gì ứng dụng muốn biết chỉ là yêu cầu ban đầu, bất kể có bao nhiêu bước phản hồi xảy ra ở giữa. Trong tình huống này, một khi một thông điệp có ID tương ứng không null, nó là một phản hồi, và tất cả các phản hồi tiếp theo phát sinh từ đó cũng nên sử dụng cùng một ID tương ứng.
Trong khi một Định danh Tương quan được sử dụng để khớp một phản hồi với yêu cầu của nó, yêu cầu cũng có thể có Địa chỉ Trả lại xác định kênh nào để đưa phản hồi vào. Trong khi một định danh tương quan được sử dụng để khớp một tin nhắn phản hồi với yêu cầu của nó, các định danh của Chuỗi Tin nhắn được sử dụng để chỉ định vị trí của một tin nhắn trong một loạt tin nhắn từ cùng một người gửi.
| Ví dụ: Thuộc tính JMS Correlation-ID Các tin nhắn JMS có một thuộc tính được xác định trước cho các định danh tương quan: JMSCorrelationID, thường được sử dụng kết hợp với một thuộc tính được xác định trước khác, JMSMessageID [JMS 1.1], [Monson-Haefel]. ID tương quan của tin nhắn trả lời được thiết lập từ ID tin nhắn của yêu cầu như sau: Message requestMessage = // Get the request message Message replyMessage = // Create the reply message String requestID = requestMessage.getJMSMessageID(); replyMessage.setJMSCorrelationID(requestID); |
| Ví dụ: Thuộc tính .NET CorrelationId Mỗi Thông điệp trong .NET có thuộc tính CorrelationId, là một chuỗi trong một thông điệp công nhận thường được đặt thành ID của thông điệp gốc. MessageQueue cũng có các phương thức đặc biệt để xem trước và nhận, PeekByCorrelationId(string) và ReceiveByCorrelationId(string), để xem và tiêu thụ thông điệp trong hàng đợi (nếu có) với ID tương quan được chỉ định (xem Người tiêu dùng chọn lọc) [SysMsg], [Dickman]. |
| Ví dụ: Yêu cầu-Phản hồi Dịch vụ Web Các tiêu chuẩn dịch vụ web, tính đến SOAP 1.1, không cung cấp hỗ trợ tốt cho việc nhắn tin không đồng bộ, nhưng SOAP 1.2 bắt đầu lập kế hoạch cho nó. SOAP 1.2 bao gồm mẫu Trao đổi Thông điệp Yêu cầu-Phản hồi, một phần cơ bản của nhắn tin SOAP không đồng bộ. Tuy nhiên, mẫu yêu cầu-phản hồi không quy định hỗ trợ cho "nhiều yêu cầu đang diễn ra", vì vậy nó không định nghĩa một trường Nhận dạng Tương ứng tiêu chuẩn, thậm chí không có một trường tùy chọn. Trong thực tế, những người yêu cầu dịch vụ thường yêu cầu nhiều yêu cầu chưa được xử lý. "Kịch bản Sử dụng Kiến trúc Dịch vụ Web" [WSAUS] thảo luận về một số kịch bản dịch vụ web bất đồng bộ khác nhau. Bốn trong số đó - Yêu cầu-Phản hồi, Gọi Thủ tục Từ xa (nơi giao thức truyền tải không hỗ trợ [cái gọi là] yêu cầu-phản hồi trực tiếp), Nhiều Phản hồi Bất đồng bộ và Nhắn tin Bất đồng bộ - sử dụng các trường message-id và response-to trong tiêu đề SOAP để liên kết một phản hồi với yêu cầu của nó. Đây là ví dụ về yêu cầu-phản hồi: SOAP Request Message Containing a Message Identifier[View full width]<?xml version="1.0" ?> <env:Envelope xmlns:env="http://www.w3.org/2002/06/soap-envelope"> <env:Header> <n:MsgHeader xmlns:n="http://example.org/requestresponse"> <n:MessageId>uuid:09233523-345b-4351-b623-5dsf35sgs5d6</n SOAP Response Message Containing Correlation to Original Request[View full width]<?xml version="1.0" ?> <env:Envelope xmlns:env="http://www.w3.org/2002/06/soap-envelope"> <env:Header> <n:MsgHeader xmlns:n="http://example.org/requestresponse"> <n:MessageId>uuid:09233523-567b-2891-b623-9dke28yod7m9</n Giống như các ví dụ JMS và .NET, trong ví dụ SOAP này, thông điệp yêu cầu chứa một định danh thông điệp duy nhất, và thông điệp phản hồi chứa một trường phản hồi (ví dụ: một ID tương ứng) có giá trị là định danh thông điệp của thông điệp yêu cầu. |
Ứng dụng của tôi cần gửi một lượng lớn dữ liệu đến một quá trình khác, nhiều hơn những gì có thể chứa trong một thông điệp duy nhất. Hoặc, ứng dụng của tôi đã thực hiện một yêu cầu mà phản hồi chứa quá nhiều dữ liệu cho một thông điệp duy nhất.
| Làm thế nào mà việc nhắn tin có thể truyền tải một lượng dữ liệu bất kỳ lớn? |
Thật tốt khi nghĩ rằng tin nhắn có thể lớn một cách tùy ý, nhưng có những giới hạn thực tế về lượng dữ liệu mà một tin nhắn duy nhất có thể chứa. Một số triển khai nhắn tin đặt ra giới hạn tuyệt đối về kích thước của một tin nhắn. Các triển khai khác cho phép tin nhắn lớn hơn, nhưng tin nhắn lớn vẫn làm ảnh hưởng đến hiệu suất. Ngay cả khi triển khai nhắn tin cho phép tin nhắn lớn, nhà sản xuất hoặc người tiêu dùng tin nhắn có thể đặt ra giới hạn về lượng dữ liệu mà họ có thể xử lý cùng một lúc. Ví dụ, nhiều hệ thống dựa trên COBOL và mainframe chỉ tiêu thụ hoặc sản xuất dữ liệu ở dạng từng khối 32 Kb.
Vậy, bạn làm thế nào để giải quyết vấn đề này? Một cách tiếp cận là giới hạn ứng dụng của bạn sao cho nó không bao giờ cần chuyển giao nhiều dữ liệu hơn mức mà lớp nhắn tin có thể lưu trữ trong một tin nhắn đơn. Tuy nhiên, đây là một giới hạn tùy ý, có thể ngăn cản ứng dụng của bạn sản xuất chức năng mong muốn. Nếu lượng dữ liệu lớn là kết quả của một yêu cầu, thì người gọi có thể phát hành nhiều yêu cầu, mỗi yêu cầu cho một mảnh kết quả, nhưng điều đó làm tăng lưu lượng mạng và giả định rằng người gọi thậm chí biết có bao nhiêu mảnh kết quả sẽ cần. Người nhận có thể lắng nghe các mảnh dữ liệu cho đến khi không còn mảnh nào (nhưng làm sao để biết không còn mảnh nào nữa?) và sau đó cố gắng tìm ra cách để gộp lại các mảnh thành một phần dữ liệu lớn ban đầu, nhưng điều đó sẽ dễ xảy ra lỗi.
Cảm hứng đến từ cách mà một công ty đặt hàng qua bưu điện đôi khi giao hàng trong nhiều hộp. Nếu có ba hộp, người giao hàng sẽ đánh dấu chúng là "1 trong 3," "2 trong 3," và "3 trong 3," để người nhận biết được những hộp nào mà họ đã nhận và liệu họ đã nhận đủ tất cả hay chưa. Mẹo là áp dụng cùng một kỹ thuật này vào việc nhắn tin.
| Mỗi khi một tập dữ liệu lớn cần được chia thành các đoạn kích thước tin nhắn, hãy gửi dữ liệu dưới dạng Chuỗi Tin nhắn và đánh dấu mỗi tin nhắn bằng các trường định danh chuỗi.
|
Ba trường xác định chuỗi tin nhắn là như sau.
Mã nhận diện chuỗi Phân biệt cụm thông điệp này với các cụm khác.
Nguyên vẹn xác định vị trí Xác định duy nhất và sắp xếp theo thứ tự tuần tự mỗi tin nhắn trong một chuỗi.
Kích thước hoặc chỉ báo kết thúc Xác định số lượng tin nhắn trong cụm hoặc đánh dấu tin nhắn cuối cùng trong cụm (có mã định vị sau đó xác định kích thước của cụm).
Các chuỗi thường được thiết kế để mỗi thông điệp trong một chuỗi chỉ ra kích thước tổng thể của chuỗi, tức là số lượng thông điệp trong chuỗi đó. Như một lựa chọn thay thế, bạn có thể thiết kế các chuỗi sao cho mỗi thông điệp chỉ ra liệu nó có phải là thông điệp cuối cùng trong chuỗi hay không.
Nhãn Thông điệp với Chỉ báo Kết thúc

Giả sử một tập dữ liệu cần được gửi dưới dạng một cụm ba thông điệp. Bộ định danh chuỗi của cụm ba thông điệp sẽ là một ID duy nhất. Bộ định danh vị trí cho mỗi thông điệp sẽ khác nhau: hoặc 1, 2 hoặc 3 (giả sử rằng việc đánh số bắt đầu từ 1, không phải 0). Nếu người gửi biết tổng số thông điệp từ trước, kích thước chuỗi cho mỗi thông điệp sẽ là 3. Nếu người gửi không biết tổng số thông điệp cho đến khi hết dữ liệu để gửi (ví dụ, người gửi đang truyền phát dữ liệu), mỗi thông điệp trừ thông điệp cuối cùng sẽ có cờ "kết thúc chuỗi" là sai. Khi người gửi sẵn sàng gửi thông điệp cuối cùng trong chuỗi, nó sẽ đặt cờ kết thúc chuỗi của thông điệp đó là đúng. Theo cách này, các bộ định danh vị trí và chỉ báo kích thước/kết thúc chuỗi sẽ cung cấp cho người nhận đủ thông tin để tái cấu trúc các phần trở lại thành toàn bộ, ngay cả khi các phần không được nhận theo thứ tự liên tiếp.
Nếu người nhận kỳ vọng vào một Chuỗi Thông điệp, thì mọi thông điệp gửi đến nó nên được gửi như một phần của chuỗi, ngay cả khi chỉ là chuỗi một. Ngược lại, khi một thông điệp đơn lẻ được gửi mà không có các trường nhận diện chuỗi, người nhận có thể trở nên bối rối bởi các trường còn thiếu và có thể kết luận rằng thông điệp này không hợp lệ (xem Kênh Thông điệp Không hợp lệ).
Nếu một bộ nhận nhận được một số thông điệp trong một chuỗi nhưng không nhận được tất cả, nó nên chuyển tiếp những thông điệp mà nó đã nhận được đến Kênh Thông điệp Không hợp lệ.
Một ứng dụng có thể muốn sử dụng Client Giao dịch để gửi và nhận các chuỗi tin nhắn. Người gửi có thể gửi tất cả các tin nhắn trong một chuỗi bằng cách sử dụng một giao dịch duy nhất. Bằng cách này, không tin nhắn nào sẽ được giao cho đến khi tất cả chúng đã được gửi. Tương tự, người nhận có thể muốn sử dụng một giao dịch duy nhất để nhận các tin nhắn để không thực sự tiêu thụ bất kỳ tin nhắn nào cho đến khi nhận được tất cả chúng. Nếu bất kỳ tin nhắn nào trong chuỗi bị thiếu, người nhận có thể chọn hoàn tác giao dịch để các tin nhắn có thể được tiêu thụ sau. Trong nhiều hệ thống nhắn tin, nếu một chuỗi tin nhắn được gửi trong một giao dịch, các tin nhắn sẽ được nhận theo thứ tự mà chúng được gửi, điều này đơn giản hóa công việc của người nhận trong việc ghép dữ liệu lại với nhau.
Khi Chuỗi Thông điệp là thông điệp phản hồi trong một Yêu cầu-Phản hồi, mã định danh chuỗi và Mã Định danh Liên quan thường là cùng một thứ. Chúng sẽ tách biệt nếu ứng dụng gửi yêu cầu mong đợi nhiều phản hồi cho cùng một yêu cầu, và một hoặc nhiều phản hồi có thể ở nhiều phần. Khi chỉ một phản hồi được mong đợi, thì việc xác định duy nhất phản hồi và chuỗi của nó là hợp lệ nhưng thừa.
Chuỗi thông điệp thường không tương thích với Người tiêu dùng cạnh tranh hoặc Bộ phát thông điệp. Nếu những người tiêu dùng/thực hiện khác nhau nhận được các thông điệp khác nhau trong một chuỗi, không ai trong số những người nhận sẽ có khả năng tái cấu trúc dữ liệu gốc mà không trao đổi nội dung thông điệp với nhau. Do đó, một chuỗi thông điệp nên được truyền qua Kênh thông điệp với một người tiêu dùng duy nhất.
Một lựa chọn thay thế cho Chuỗi Tin nhắn là sử dụng Phiếu Nhận. Thay vì truyền một tài liệu lớn giữa hai ứng dụng, nếu cả hai ứng dụng đều có quyền truy cập vào một cơ sở dữ liệu hoặc hệ thống tệp chung, hãy lưu trữ tài liệu và chỉ truyền một khóa đến tài liệu đó trong một tin nhắn duy nhất.
Sử dụng Chuỗi Thông điệp tương tự như việc sử dụng Bộ tách để chia một thông điệp lớn thành một chuỗi các thông điệp và sử dụng Bộ tổng hợp để lắp ráp lại chuỗi thông điệp thành một thông điệp duy nhất. Bộ tách và Bộ tổng hợp cho phép các thông điệp ban đầu và cuối có kích thước rất lớn, trong khi Chuỗi Thông điệp cho phép các Điểm cuối Thông điệp tách dữ liệu trước khi bất kỳ thông điệp nào được gửi và tổng hợp dữ liệu sau khi các thông điệp được nhận.
| Ví dụ: Chuyển giao tài liệu lớn Hãy tưởng tượng rằng một người gửi cần gửi cho một người nhận một tài liệu cực kỳ lớn, lớn đến mức không thể fit trong một tin nhắn duy nhất hoặc không thực tế để gửi tất cả cùng một lúc. Trong trường hợp này, tài liệu nên được chia thành các phần, và mỗi phần có thể được gửi như một tin nhắn. Mỗi tin nhắn cần chỉ rõ vị trí của nó trong chuỗi và có bao nhiêu tin nhắn tổng cộng. Ví dụ, kích thước tối đa của một tin nhắn MSMQ là 4 MB. [Dickman] thảo luận về cách gửi một chuỗi tin nhắn đa phần trong MSMQ. |
| Ví dụ: Truy vấn nhiều mục Xem xét một truy vấn yêu cầu danh sách tất cả các cuốn sách của một tác giả nhất định. Vì điều này có thể là một danh sách rất lớn, thiết kế thông điệp có thể chọn để trả về mỗi kết quả dưới dạng một thông điệp riêng biệt. Sau đó, mỗi thông điệp cần chỉ ra truy vấn mà phản hồi này dành cho, vị trí của thông điệp trong chuỗi, và số lượng thông điệp dự kiến. |
| Ví dụ: Truy vấn phân tán Xem xét một truy vấn được thực hiện theo từng phần bởi nhiều người nhận. Nếu các phần có một thứ tự nhất định, điều này sẽ cần được chỉ ra trong các tin nhắn phản hồi để câu trả lời hoàn chỉnh có thể được lắp ráp đúng cách. Mỗi người nhận sẽ cần biết vị trí của mình trong thứ tự tổng thể và sẽ cần chỉ ra vị trí đó trong chuỗi tin nhắn phản hồi. |
| Ví dụ: JMS và .NET Cả JMS và .NET đều không có thuộc tính tích hợp sẵn để hỗ trợ các chuỗi tin nhắn. Do đó, các ứng dụng nhắn tin phải tự triển khai các trường chuỗi của riêng mình. Trong JMS, một ứng dụng có thể định nghĩa các thuộc tính của riêng nó trong tiêu đề, vì vậy đó là một tùy chọn. .NET không cung cấp các thuộc tính do ứng dụng định nghĩa trong tiêu đề. Các trường cũng có thể được định nghĩa trong thân tin nhắn. Hãy nhớ rằng nếu một người nhận chuỗi cần lọc các tin nhắn dựa trên chuỗi của chúng, việc lọc như vậy sẽ đơn giản hơn nhiều nếu trường được lưu trữ trong tiêu đề hơn là trong thân. |
| Ví dụ: Dịch vụ Web: Nhiều Phản hồi Bất đồng bộ Các tiêu chuẩn dịch vụ web hiện tại không cung cấp hỗ trợ tốt cho việc nhắn tin bất đồng bộ, nhưng W3C đã bắt đầu suy nghĩ về cách thức có thể làm được điều đó. "Kịch bản sử dụng Kiến trúc Dịch vụ Web" [WSAUS] thảo luận về một số kịch bản dịch vụ web bất đồng bộ khác nhau. Một trong số đó là Nhiều Phản hồi Bất đồng bộ sử dụng các trường message-id và response-to trong tiêu đề SOAP để liên kết một phản hồi với yêu cầu, và các trường sequence-number và total-in-sequence trong phần thân để xác định tuần tự các phản hồi. Đây là ví dụ về nhiều phản hồi: SOAP Request Message Containing a Message Identifier[View full width]<?xml version="1.0" ?> <env:Envelope xmlns:env="http://www.w3.org/2002/06/soap-envelope"> <env:Header> <n:MsgHeader xmlns:n="http://example.org/requestresponse"> <n:MessageId>uuid:09233523-345b-4351-b623-5dsf35sgs5d6</n First SOAP Response Message Containing Sequencing and Correlation to Original Request[View full width]<?xml version="1.0" ?> <env:Envelope xmlns:env="http://www.w3.org/2002/06/soap-envelope"> <env:Header> <n:MsgHeader xmlns:n="http://example.org/requestresponse"> <!-- MessageId will be unique for each response message --> <!-- ResponseTo will be constant for each response message Final SOAP Response Message Containing Sequencing and Correlation to Original Request[View full width]<?xml version="1.0" ?> <env:Envelope xmlns:env="http://www.w3.org/2002/06/soap-envelope"> <env:Header> <n:MsgHeader xmlns:n="http://example.org/requestresponse"> <!-- MessageId will be unique for each response message --> <!-- ResponseTo will be constant for each response message ID thông điệp trong tiêu đề được sử dụng làm định danh chuỗi trong các phản hồi. Số thứ tự và tổng số trong chuỗi trong mỗi phản hồi lần lượt là định danh vị trí và chỉ số kích thước. |
Ứng dụng của tôi đang sử dụng Nhắn tin. Nếu dữ liệu hoặc yêu cầu Nhắn tin không được nhận trước một thời điểm nhất định, thì nó trở nên vô ích và nên bị bỏ qua.
| Người gửi có thể chỉ định khi nào một tin nhắn nên được coi là lỗi thời và do đó không nên được xử lý như thế nào? |
Hệ thống nhắn tin gần như đảm bảo rằng tin nhắn sẽ cuối cùng được gửi đến người nhận. Điều mà nó không thể đảm bảo là thời gian giao hàng có thể mất bao lâu. Ví dụ, nếu mạng kết nối giữa người gửi và người nhận bị ngắt trong một tuần, thì có thể mất một tuần để gửi một tin nhắn. Hệ thống nhắn tin rất đáng tin cậy, ngay cả khi các bên tham gia (người gửi, mạng, và người nhận) không đáng tin cậy, nhưng tin nhắn có thể mất rất nhiều thời gian để truyền tải trong các tình huống không đáng tin cậy. (Để biết thêm chi tiết, xem Giao Hàng Đảm Bảo.)
Thường thì nội dung của một thông điệp có giới hạn thực tiễn về thời gian mà nó còn hữu ích. Một người gọi yêu cầu báo giá cổ phiếu có lẽ sẽ mất hứng thú nếu không nhận được câu trả lời trong vòng một phút. Điều đó có nghĩa là yêu cầu không nên mất hơn một phút để truyền tải, nhưng cũng có nghĩa là câu trả lời cần phải được truyền lại rất nhanh. Một câu trả lời báo giá cổ phiếu có độ trễ hơn một hoặc hai phút có lẽ đã quá cũ và do đó sẽ không còn liên quan.
Một khi người gửi gửi một tin nhắn và không nhận được phản hồi, họ không có cách nào để hủy hoặc thu hồi tin nhắn. Tương tự, người nhận có thể kiểm tra thời điểm tin nhắn được gửi và từ chối tin nhắn nếu nó quá cũ, nhưng các người gửi khác nhau trong các hoàn cảnh khác nhau có thể có những quan điểm khác nhau về việc bao lâu là quá lâu, vậy làm thế nào người nhận biết được tin nhắn nào cần phải từ chối? Cần có một cách để người gửi xác định thời gian tồn tại của tin nhắn.
| Đặt Thời gian Hết hạn Tin nhắn để chỉ định giới hạn thời gian cho việc tin nhắn có giá trị.
|
Một khi thời gian mà một tin nhắn có thể tồn tại đã qua, và tin nhắn vẫn chưa được tiêu thụ, thì tin nhắn sẽ hết hạn. Các người tiêu dùng trong hệ thống nhắn tin sẽ bỏ qua một tin nhắn đã hết hạn; họ xem tin nhắn như thể nó chưa bao giờ được gửi từ đầu. Hầu hết các triển khai hệ thống nhắn tin sẽ chuyển hướng các tin nhắn hết hạn đến Kênh Thư Chết, trong khi một số khác đơn giản loại bỏ các tin nhắn hết hạn; điều này có thể được cấu hình.
Thời hạn một tin nhắn giống như ngày hết hạn trên hộp sữa. Sau ngày đó, bạn không nên uống sữa nữa. Tương tự, khi một tin nhắn hết hạn, hệ thống nhắn tin không nên gửi tin đó nữa. Nếu một người nhận vẫn nhận được tin nhắn nhưng không thể xử lý trước khi hết hạn, người nhận nên vứt bỏ tin nhắn đó.
Thời gian hết hạn của tin nhắn là một dấu thời gian (ngày và giờ) chỉ định thời gian tin nhắn sẽ tồn tại hoặc khi nào nó sẽ hết hạn. Cài đặt này có thể được chỉ định bằng cách tương đối hoặc tuyệt đối. Cài đặt tuyệt đối chỉ định một ngày và giờ khi tin nhắn sẽ hết hạn. Cài đặt tương đối chỉ định thời gian tin nhắn nên tồn tại trước khi nó hết hạn; hệ thống nhắn tin sẽ sử dụng thời điểm tin nhắn được gửi để chuyển đổi cài đặt tương đối thành cài đặt tuyệt đối. Hệ thống nhắn tin có trách nhiệm điều chỉnh dấu thời gian cho những người nhận ở các múi giờ khác với người gửi, cho những điều chỉnh về giờ mùa hè, và bất kỳ vấn đề nào khác có thể khiến hai đồng hồ khác nhau không đồng ý về thời gian.
Thuộc tính hết hạn của tin nhắn có một thuộc tính liên quan, thời gian gửi, xác định thời điểm tin nhắn được gửi. Dấu thời gian hết hạn tuyệt đối của một tin nhắn phải lớn hơn thời gian gửi của nó (nếu không, tin nhắn sẽ hết hạn ngay lập tức). Để tránh vấn đề này, những người gửi thường chỉ định thời gian hết hạn theo cách tương đối, trong trường hợp này, hệ thống nhắn tin sẽ tính toán dấu thời gian hết hạn bằng cách thêm thời gian tương đối vào thời gian gửi (thời gian hết hạn = thời gian gửi + thời gian sống).
Khi một tin nhắn hết hạn, hệ thống nhắn tin có thể đơn giản loại bỏ nó hoặc chuyển nó đến Kênh Thư Chết. Một người nhận phát hiện mình đang sở hữu một tin nhắn đã hết hạn nên chuyển nó đến Kênh Tin Nhắn Không Hợp Lệ. Đối với một Kênh Đăng Ký-Đăng Ký, mỗi người đăng ký nhận được bản sao của tin nhắn; một số bản sao của một tin nhắn có thể đến tay người đăng ký thành công, trong khi những bản sao khác của cùng một tin nhắn có thể hết hạn trước khi người đăng ký tiêu thụ chúng. Khi sử dụng Yêu Cầu-Trả Lời, một tin nhắn phản hồi có cài đặt hết hạn có thể không hoạt động tốt; nếu phản hồi hết hạn, người gửi yêu cầu sẽ không bao giờ biết liệu yêu cầu đã được nhận hay chưa. Nếu sử dụng hết hạn cho phản hồi, người gửi yêu cầu cần được thiết kế để xử lý trường hợp các phản hồi dự kiến không bao giờ được nhận.
| Ví dụ: Tham số Thời gian sống JMS Thời gian hết hạn của tin nhắn là điều mà đặc tả JMS gọi là "thời gian sống của tin nhắn" [JMS 1.1], [Hapner]. Các tin nhắn JMS có một thuộc tính đã được xác định trước cho thời gian hết hạn, JMSExpiration, nhưng người gửi không nên thiết lập nó thông qua phương thức Message.setJMSExpiration(long) vì nhà cung cấp JMS sẽ ghi đè thiết lập đó khi tin nhắn được gửi. Thay vào đó, người gửi nên sử dụng MessageProducer (QueueSender hoặc TopicPublisher) của mình để thiết lập thời gian chờ cho tất cả các tin nhắn mà nó gửi; phương thức để thực hiện thiết lập này là MessageProducer.setTimeToLive(long). Người gửi cũng có thể thiết lập thời gian sống cho một tin nhắn cá nhân bằng phương thức MessageProducer.send(Message message, int deliveryMode, int priority, long timeToLive), trong đó tham số thứ tư là thời gian sống tính bằng mili giây. Thời gian sống là một thiết lập tương đối xác định thời gian mà tin nhắn sẽ hết hạn sau khi được gửi đi. |
| Ví dụ: Thuộc tính Thời gian để nhận và Thời gian để đến hàng đợi của .NET Một tin nhắn .NET có hai thuộc tính để xác định thời gian hết hạn: TimeToBeReceived và TimeToReachQueue. Thuộc tính reach-queue xác định thời gian mà tin nhắn phải đến hàng đợi đích, sau đó tin nhắn có thể nằm trong hàng đợi không xác định. Thuộc tính be-received xác định thời gian mà tin nhắn phải được tiêu thụ bởi một người nhận, giới hạn tổng thời gian để truyền tin nhắn đến hàng đợi đích cộng với thời gian mà tin nhắn có thể nằm trong hàng đợi đích. TimeToBeReceived tương đương với thuộc tính JMSExpiration của JMS. Cả hai thuộc tính thời gian đều có giá trị kiểu System.TimeSpan, một khoảng thời gian. |
Một vài ứng dụng, giao tiếp qua Tin nhắn, tuân theo một định dạng dữ liệu đã được thống nhất, có thể là Mô hình Dữ liệu Canonical toàn doanh nghiệp. Tuy nhiên, định dạng đó có thể cần thay đổi theo thời gian.
| Làm thế nào để định dạng dữ liệu của một thông điệp có thể được thiết kế cho phép các thay đổi trong tương lai? |
Ngay cả khi bạn thiết kế một định dạng dữ liệu hoạt động cho tất cả các ứng dụng tham gia, các yêu cầu trong tương lai có thể thay đổi. Các ứng dụng mới có thể được thêm vào với các yêu cầu định dạng mới, dữ liệu mới có thể cần được thêm vào các tin nhắn, hoặc các nhà phát triển có thể tìm ra những cách tốt hơn để cấu trúc cùng một dữ liệu. Dù sao đi nữa, việc thiết kế một mô hình dữ liệu doanh nghiệp đơn lẻ đã đủ khó khăn; việc thiết kế một mô hình mà sẽ không bao giờ cần thay đổi trong tương lai gần như là không thể.
Khi định dạng dữ liệu của một doanh nghiệp thay đổi, sẽ không có vấn đề gì nếu tất cả các ứng dụng thay đổi theo nó. Nếu mọi ứng dụng ngừng sử dụng định dạng cũ và bắt đầu sử dụng định dạng mới, và tất cả đều làm như vậy vào đúng thời điểm, thì việc chuyển đổi sẽ rất đơn giản. Vấn đề là một số ứng dụng sẽ được chuyển đổi trước những ứng dụng khác, trong khi một số ứng dụng ít sử dụng có thể sẽ không bao giờ được chuyển đổi. Ngay cả khi tất cả các ứng dụng có thể được chuyển đổi cùng một lúc, tất cả các tin nhắn sẽ phải được tiêu thụ để tất cả các kênh đều trống rỗng trước khi việc chuyển đổi có thể diễn ra.
Một cách thực tế, các ứng dụng sẽ phải có khả năng hỗ trợ cả định dạng cũ và định dạng mới đồng thời. Để làm được điều này, các ứng dụng phải có khả năng phân biệt các tin nhắn nào theo định dạng cũ và tin nhắn nào theo định dạng mới.
Một giải pháp có thể là sử dụng một tập hợp kênh riêng biệt cho các thông điệp với định dạng mới. Tuy nhiên, điều đó sẽ dẫn đến một số lượng kênh khổng lồ, sự lặp lại trong thiết kế và độ phức tạp cấu hình khi mỗi ứng dụng phải được cấu hình cho một loạt kênh ngày càng mở rộng.
Một giải pháp tốt hơn là các tin nhắn với định dạng mới sử dụng cùng các kênh mà các tin nhắn định dạng cũ đang sử dụng. Điều này có nghĩa là người nhận cần một cách để phân biệt các tin nhắn có định dạng khác nhau đang sử dụng cùng một kênh. Mỗi tin nhắn phải chỉ rõ định dạng mà nó đang sử dụng, và nó cần một cách đơn giản để chỉ định định dạng của nó.
| Thiết kế một định dạng dữ liệu bao gồm một chỉ báo định dạng để thông điệp chỉ rõ định dạng mà nó đang sử dụng. |
Chỉ thị Định dạng cho phép người gửi thông báo cho người nhận định dạng của tin nhắn. Bằng cách này, một người nhận mong đợi nhiều định dạng có thể biết định dạng nào mà một tin nhắn đang sử dụng và do đó cách diễn giải nội dung của tin nhắn.
Có ba lựa chọn chính để triển khai chỉ báo định dạng:
Số phiên bản Một số hoặc chuỗi có thể xác định duy nhất định dạng. Cả người gửi và người nhận phải đồng ý về định dạng nào được chỉ định bởi một chỉ báo cụ thể. Lợi thế của cách tiếp cận này là người gửi và người nhận không cần phải đồng ý về một kho lưu trữ chung cho các mô tả định dạng, nhưng bất lợi là cả hai đều phải biết mô tả nào được chỉ định và nơi truy cập nó.
Khóa ngoại Một ID duy nhất như tên tệp, khóa hàng trong cơ sở dữ liệu, khóa chính tại nhà, hoặc URL trên Internet để xác định tài liệu định dạng. Người gửi và người nhận phải đồng ý về việc ánh xạ các khóa đến tài liệu và định dạng của tài liệu lược đồ. Lợi thế của cách tiếp cận này là khóa ngoại rất gọn gàng và có thể chỉ đến mô tả định dạng dữ liệu chi tiết trong một kho tài nguyên chia sẻ. Nhược điểm chính là mỗi người tham gia gửi tin nhắn phải lấy tài liệu định dạng từ một nguồn tài nguyên có thể nằm xa.
Định dạng Tài liệu Một lược đồ mô tả định dạng dữ liệu. Tài liệu lược đồ không cần phải được truy xuất qua khóa ngoại hoặc suy luận từ số phiên bản; nó được nhúng trong thông điệp. Người gửi và người nhận phải đồng ý về định dạng của lược đồ. Lợi ích của lựa chọn này là các thông điệp là tự chứa. Tuy nhiên, lưu lượng thông điệp tăng lên vì mỗi thông điệp mang theo thông tin định dạng hiếm khi thay đổi.
Một số phiên bản hoặc khóa ngoại có thể được lưu trữ trong một trường tiêu đề mà người gửi và người nhận đồng ý với nhau. Người nhận không quan tâm đến phiên bản định dạng có thể bỏ qua trường này. Tài liệu định dạng có thể quá dài hoặc phức tạp để lưu trữ trong một trường tiêu đề, trong trường hợp đó, thân tin nhắn phải có một định dạng gồm hai phần: sơ đồ và dữ liệu.
| Ví dụ: XML Tài liệu XML có ví dụ cho cả ba phương pháp. Một ví dụ là khai báo XML, như thế này: <?xml version="1.0"?> Ở đây, 1.0 là một số phiên bản cho biết tài liệu tuân thủ phiên bản của đặc tả XML đó. Một ví dụ khác là khai báo loại tài liệu, có thể có hai hình thức. Nó có thể là một ID bên ngoài chứa một định danh hệ thống, như thế này: <!DOCTYPE greeting SYSTEM "hello.dtd"> Bộ nhận dạng hệ thống, hello.dtd, là một khóa ngoại chỉ ra tệp chứa tài liệu DTD mô tả định dạng của tài liệu XML này. Khai báo cũng có thể được bao gồm cục bộ, như sau: <!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)> ]> Khai báo kiểu, [<!ELEMENT greeting (#PCDATA)>], là một tài liệu định dạng, một tài liệu sơ đồ nhúng mô tả định dạng của XML [XML 1.0]. |
Giới thiệu
Ví dụ Yêu cầu-Trả lời JMS
Ví dụ về Yêu cầu-Phản hồi trong .NET
Ví dụ về Publish-Subscribe JMS
Cho đến nay, chúng ta đã giới thiệu nhiều mẫu. Chúng ta đã thấy các thành phần nhắn tin cơ bản, chẳng hạn như Kênh Nhắn Tin, Tin Nhắn và Điểm Kết Nối Tin Nhắn. Chúng ta cũng đã xem xét các mẫu chi tiết cho kênh nhắn tin và cho việc xây dựng tin nhắn. Vậy, tất cả những mẫu này kết hợp với nhau như thế nào? Làm thế nào một lập trình viên có thể tích hợp ứng dụng sử dụng các mẫu này? Mã nguồn trông như thế nào, và nó hoạt động ra sao?
Đây là chương mà chúng ta thực sự được xem mã. Chúng ta có hai ví dụ:
Yêu cầu-Phản hồi Chứng minh (bằng Java và .NET/C#) cách sử dụng nhắn tin để gửi một tin nhắn yêu cầu và phản hồi bằng một tin nhắn trả lời.
Công bố-Đăng ký Khám phá cách sử dụng một Chủ đề JMS để triển khai mẫu Quan sát viên [GoF].
Hai ví dụ đơn giản này sẽ giúp bạn bắt đầu thêm chức năng nhắn tin vào các ứng dụng của riêng bạn.
Đây là một ví dụ đơn giản nhưng mạnh mẽ, truyền một yêu cầu và truyền lại một phản hồi. Nó bao gồm hai lớp chính:
Người yêu cầu Đối tượng gửi tin nhắn yêu cầu và mong đợi nhận được tin nhắn hồi đáp.
Người phản hồi Đối tượng nhận thông điệp yêu cầu và gửi thông điệp phản hồi để đáp lại.
Hai lớp đơn giản này gửi những thông điệp đơn giản minh họa cho một số mẫu.
Kênh Tin nhắn và Kênh Điểm-Đến-Điểm Một kênh để truyền tải các yêu cầu, một kênh khác để truyền tải các phản hồi.
Thông điệp Tài liệu Loại thông điệp mặc định, được sử dụng cả làm yêu cầu và phản hồi.
Yêu cầu-Trả lời Một cặp thông điệp được gửi qua một cặp kênh, cho phép hai ứng dụng có cuộc trò chuyện hai chiều.
Địa chỉ trả lại Kênh để gửi phản hồi.
Mã xác định tương quan Mã của yêu cầu đã gây ra phản hồi này.
Kênh Dữ liệu Tất cả các tin nhắn trên mỗi kênh phải cùng loại.
Kênh Tin Nhắn Không Hợp Lệ Những gì xảy ra với các tin nhắn không đúng loại.
Mã ví dụ cũng minh họa một vài mẫu từ Chương 10, "Điểm cuối nhắn tin":
Tiêu thụ Tin nhắn Phản hồi của Người Yêu Cầu
Người tiêu dùng dựa trên sự kiện Cách người trả lời tiêu thụ tin nhắn yêu cầu.
Mặc dù cuốn sách này trung lập về công nghệ, sản phẩm và ngôn ngữ, nhưng mã thì không thể, vì vậy chúng tôi đã chọn hai nền tảng lập trình tin nhắn để triển khai ví dụ này:
API JMS trong Java J2EE
API MSMQ trong Microsoft .NET sử dụng C#
Ví dụ yêu cầu-phản hồi tương tự được triển khai trên cả hai nền tảng. Chọn nền tảng yêu thích của bạn như một ví dụ về cách hoạt động của nhắn tin. Nếu bạn muốn xem cách nhắn tin hoạt động trên nền tảng khác nhưng không biết cách viết mã cho nền tảng đó, bạn có thể tìm hiểu bằng cách so sánh với mã trong ngôn ngữ mà bạn đã biết.
Ví dụ này khám phá cách triển khai mẫu Observer bằng cách sử dụng Kênh Xuất Bản-Đăng Ký. Nó xem xét các vấn đề phân phối và đa luồng và thảo luận về cách nhắn tin đơn giản hóa rất nhiều những vấn đề này. Ví dụ cho thấy cách triển khai cả mô hình thông báo đẩy và kéo và so sánh hậu quả của từng mô hình. Nó cũng khám phá cách thiết kế một bộ kênh thích hợp cần thiết cho một doanh nghiệp phức tạp với nhiều chủ đề thông báo cho nhiều người quan sát.
Cuộc thảo luận và mã mẫu minh họa một số mẫu:
Kênh Đăng-Ký Phát Hành Kênh cung cấp thông báo đăng-ký phát hành.
Thông điệp sự kiện Loại thông điệp được sử dụng để gửi thông báo.
Yêu cầu-Trả lời Kỹ thuật được sử dụng như một phần của mô hình kéo để một quan sát viên yêu cầu trạng thái từ đối tượng.
Thông điệp lệnh Loại thông điệp được sử dụng bởi một người quan sát để yêu cầu trạng thái từ đối tượng.
Thông điệp Tài liệu Loại thông điệp được sử dụng bởi một chủ thể để gửi trạng thái của nó tới một người quan sát.
Địa chỉ trả hàng Cho biết đối tượng cách gửi trạng thái đến người quan sát.
Kênh Kiểu Dữ Liệu Nguyên tắc chính về việc liệu hai chủ đề không liên quan có thể sử dụng cùng một kênh để cập nhật cùng một nhóm người quan sát hay không.
Mã ví dụ cũng minh họa một vài mẫu từ Chương 10, "Điểm cuối nhắn tin":
Cổng thông điệp Cách mà chủ thể và quan sát bao trùm mã thông điệp để chúng không phụ thuộc vào loại thông điệp.
Người tiêu dùng theo sự kiện Cách mà các trình quan sát tiêu thụ các thông điệp thông báo.
Người đăng ký bền vững Một quan sát viên không muốn bỏ lỡ thông báo, ngay cả khi quan sát viên tạm thời bị ngắt kết nối khi thông báo được gửi.
Ví dụ này được triển khai trong Java sử dụng JMS vì JMS hỗ trợ Kênh Xuất Bản-Đăng Ký như một tính năng rõ ràng của API thông qua giao diện Chủ Đề. .NET không cung cấp mức độ hỗ trợ tương tự cho việc sử dụng nghĩa xuất bản-đăng ký trong MSMQ. Khi điều đó xảy ra, các kỹ thuật trong ví dụ JMS nên có thể áp dụng dễ dàng cho các chương trình .NET.
Đây là một ví dụ đơn giản về cách sử dụng tin nhắn, được triển khai trong JMS [JMS]. Nó cho thấy cách triển khai Request-Reply, trong đó một ứng dụng yêu cầu gửi yêu cầu, một ứng dụng trả lời nhận yêu cầu và trả lại phản hồi, và ứng dụng yêu cầu nhận phản hồi. Nó cũng cho thấy cách một tin nhắn không hợp lệ sẽ được chuyển hướng đến một kênh đặc biệt.
Các thành phần của Ví dụ Yêu cầu-Trả lời

Ví dụ này được phát triển bằng JMS 1.1 và chạy trên triển khai tham chiếu J2EE 1.4.
Ví dụ này bao gồm hai lớp chính:
Người yêu cầu Một Điểm kết nối tin nhắn gửi một tin nhắn yêu cầu và chờ nhận một tin nhắn phản hồi.
Người trả lời Một điểm cuối tin nhắn chờ nhận tin nhắn yêu cầu; khi nó nhận được, nó phản hồi bằng cách gửi tin nhắn trả lời.
Người yêu cầu và người trả lời mỗi người chạy trong một Máy ảo Java (JVM) riêng biệt, điều này làm cho việc giao tiếp trở nên phân tán.
Ví dụ này giả định rằng hệ thống nhắn tin có ba hàng đợi này được định nghĩa:
jms/HàngĐợiYêuCầu Hàng đợi mà người gửi yêu cầu sử dụng để gửi thông điệp yêu cầu đến người trả lời.
hàng đợi jms/ReplyQueue Hàng đợi mà người trả lời sử dụng để gửi tin nhắn phản hồi đến người yêu cầu.
jms/TinNhắnKhôngHợpLệ Hàng đợi mà người yêu cầu và người trả lời chuyển một tin nhắn khi họ nhận được một tin nhắn mà họ không thể diễn giải.
Dưới đây là cách hoạt động của ví dụ. Khi yêu cầu được khởi động trong cửa sổ dòng lệnh, nó sẽ bắt đầu và in ra kết quả như sau:
Sent request Time: 1048261736520 ms Message ID: ID:_XYZ123_1048261766139_6.2.1.1 Correl. ID: null Reply to: com.sun.jms.Queue: jms/ReplyQueue Contents: Hello world.
Điều này cho thấy rằng người yêu cầu đã gửi một tin nhắn yêu cầu. Lưu ý rằng điều này vẫn hoạt động ngay cả khi người trả lời không chạy và do đó không thể nhận được yêu cầu.
Khi trình trả lời được khởi động trong một cửa sổ dòng lệnh khác, nó sẽ khởi động và in ra đầu ra như sau:
Received request Time: 1048261766790 ms Message ID: ID:_XYZ123_1048261766139_6.2.1.1 Correl. ID: null Reply to: com.sun.jms.Queue: jms/ReplyQueue Contents: Hello world. Sent reply Time: 1048261766850 ms Message ID: ID:_XYZ123_1048261758148_5.2.1.1 Correl. ID: ID:_XYZ123_1048261766139_6.2.1.1 Reply to: null Contents: Hello world.
Điều này cho thấy rằng người phản hồi đã nhận được tin nhắn yêu cầu và đã gửi tin nhắn phản hồi.
Có nhiều điểm thú vị trong kết quả này. Đầu tiên, hãy chú ý đến các mốc thời gian gửi và nhận yêu cầu; yêu cầu được nhận sau khi nó được gửi (30270 ms sau). Thứ hai, hãy chú ý rằng ID tin nhắn là giống nhau trong cả hai trường hợp, vì đây là cùng một tin nhắn. Thứ ba, hãy chú ý rằng nội dung, "Hello world", là giống nhau, điều này rất tốt vì đây là dữ liệu được truyền tải và nó phải giống nhau ở cả hai bên. (Yêu cầu trong ví dụ này khá tầm thường. Nó về cơ bản là một Tin nhắn Tài liệu; một yêu cầu thực sự thường sẽ là một Tin nhắn Lệnh.) Thứ tư, hàng đợi có tên jms/ReplyQueue đã được chỉ định trong tin nhắn yêu cầu như là điểm đến cho tin nhắn phản hồi (một ví dụ về Địa chỉ Trả về).
Kế tiếp, hãy so sánh đầu ra từ việc nhận yêu cầu với việc gửi phản hồi. Đầu tiên, hãy lưu ý rằng phản hồi không được gửi cho đến khi yêu cầu được nhận (sau 60 ms). Thứ hai, ID của thông điệp phản hồi khác với ID của yêu cầu; điều này là do các thông điệp yêu cầu và phản hồi là những thông điệp khác nhau, riêng biệt. Thứ ba, nội dung của yêu cầu đã được trích xuất và thêm vào phản hồi (trong ví dụ này, người phản hồi hoạt động như một dịch vụ "tiếng vang" đơn giản). Thứ tư, địa điểm gửi phản hồi không được xác định vì không mong đợi có phản hồi (phản hồi không sử dụng Địa chỉ Trả lại). Thứ năm, ID tương quan của phản hồi là giống như ID của thông điệp yêu cầu (phản hồi có sử dụng Bộ nhận dạng Tương quan).
Cuối cùng, quay lại cửa sổ đầu tiên, người yêu cầu đã nhận được phản hồi sau:
Received reply Time: 1048261797060 ms Message ID: ID:_XYZ123_1048261758148_5.2.1.1 Correl. ID: ID:_XYZ123_1048261766139_6.2.1.1 Reply to: null Contents: Hello world.
Đầu ra này chứa một số mục thú vị. Phản hồi đã được nhận sau khi nó được gửi (30210 ms). ID thông điệp của phản hồi giống như khi nó được nhận cũng như khi nó được gửi, điều này chứng minh rằng đó thực sự là cùng một thông điệp. Nội dung thông điệp nhận được giống như nội dung đã gửi, và ID tương quan cho biết cho người yêu cầu biết phản hồi này là cho yêu cầu nào (Mã nhận dạng tương quan).
Lưu ý rằng yêu cầu được thiết kế chỉ để gửi một yêu cầu, nhận một phản hồi và thoát. Vì vậy, sau khi nhận được phản hồi, yêu cầu sẽ không còn chạy nữa. Mặt khác, người phản hồi không biết khi nào nó sẽ nhận được yêu cầu, vì vậy nó không bao giờ ngừng chạy. Để dừng nó, chúng ta vào cửa sổ lệnh của nó và nhấn phím return, điều này khiến chương trình phản hồi thoát.
Vì vậy, đó là ví dụ về yêu cầu-đáp của JMS. Một yêu cầu đã được chuẩn bị và gửi bởi người yêu cầu. Người trả lời đã nhận được yêu cầu và gửi một phản hồi. Sau đó, người yêu cầu đã nhận được phản hồi cho yêu cầu ban đầu của mình.
Đầu tiên, hãy xem cách yêu cầu được thực hiện:
import javax.jms.Connection; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.NamingException; public class Requestor { private Session session; private Destination replyQueue; private MessageProducer requestProducer; private MessageConsumer replyConsumer; private MessageProducer invalidProducer; protected Requestor() { super(); } public static Requestor newRequestor(Connection connection, String requestQueueName, String replyQueueName, String invalidQueueName) throws JMSException, NamingException { Requestor requestor = new Requestor(); requestor.initialize(connection, requestQueueName, replyQueueName, invalidQueueName); return requestor; } protected void initialize(Connection connection, String requestQueueName, String replyQueueName, String invalidQueueName) throws NamingException, JMSException { session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination requestQueue = JndiUtil.getDestination(requestQueueName); replyQueue = JndiUtil.getDestination(replyQueueName); Destination invalidQueue = JndiUtil.getDestination(invalidQueueName); requestProducer = session.createProducer(requestQueue); replyConsumer = session.createConsumer(replyQueue); invalidProducer = session.createProducer(invalidQueue); } public void send() throws JMSException { TextMessage requestMessage = session.createTextMessage(); requestMessage.setText("Hello world."); requestMessage.setJMSReplyTo(replyQueue); requestProducer.send(requestMessage); System.out.println("Sent request"); System.out.println("\tTime: " + System.currentTimeMillis() + " ms"); System.out.println("\tMessage ID: " + requestMessage.getJMSMessageID()); System.out.println("\tCorrel. ID: " + requestMessage.getJMSCorrelationID()); System.out.println("\tReply to: " + requestMessage.getJMSReplyTo()); System.out.println("\tContents: " + requestMessage.getText()); } public void receiveSync() throws JMSException { Message msg = replyConsumer.receive(); if (msg instanceof TextMessage) { TextMessage replyMessage = (TextMessage) msg; System.out.println("Received reply "); System.out.println("\tTime: " + System.currentTimeMillis() + " ms"); System.out.println("\tMessage ID: " + replyMessage.getJMSMessageID()); System.out.println("\tCorrel. ID: " + replyMessage.getJMSCorrelationID()); System.out.println("\tReply to: " + replyMessage.getJMSReplyTo()); System.out.println("\tContents: " + replyMessage.getText()); } else { System.out.println("Invalid message detected"); System.out.println("\tType: " + msg.getClass().getName()); System.out.println("\tTime: " + System.currentTimeMillis() + " ms"); System.out.println("\tMessage ID: " + msg.getJMSMessageID()); System.out.println("\tCorrel. ID: " + msg.getJMSCorrelationID()); System.out.println("\tReply to: " + msg.getJMSReplyTo()); msg.setJMSCorrelationID(msg.getJMSMessageID()); invalidProducer.send(msg); System.out.println("Sent to invalid message queue"); System.out.println("\tType: " + msg.getClass().getName()); System.out.println("\tTime: " + System.currentTimeMillis() + " ms"); System.out.println("\tMessage ID: " + msg.getJMSMessageID()); System.out.println("\tCorrel. ID: " + msg.getJMSCorrelationID()); System.out.println("\tReply to: " + msg.getJMSReplyTo()); } } } Một ứng dụng muốn gửi yêu cầu và nhận phản hồi có thể sử dụng một đối tượng yêu cầu để thực hiện điều đó. Ứng dụng cung cấp cho đối tượng yêu cầu của nó một kết nối đến hệ thống nhắn tin. Nó cũng chỉ định các tên JNDI của ba hàng đợi: hàng đợi yêu cầu, hàng đợi phản hồi và hàng đợi tin nhắn không hợp lệ. Đây là thông tin mà đối tượng yêu cầu cần để khởi tạo chính nó.
Trong phương thức khởi tạo, người yêu cầu sử dụng tên kết nối và hàng đợi để kết nối với hệ thống truyền thông.
Nó sử dụng kết nối để tạo ra một phiên. Một ứng dụng chỉ cần một kết nối đến hệ thống nhắn tin, nhưng mỗi thành phần trong ứng dụng muốn gửi và nhận tin nhắn một cách độc lập cần có phiên riêng của mình. Hai luồng không thể chia sẻ một phiên duy nhất; chúng nên sử dụng mỗi một phiên khác nhau để các phiên hoạt động đúng cách.
Nó sử dụng tên hàng đợi để tra cứu các hàng đợi, mà là Các Điểm đến. Các tên này là các định danh JNDI; JndiUtil thực hiện các truy vấn JNDI.
Nó tạo ra một MessageProducer để gửi tin nhắn trên hàng đợi yêu cầu, một MessageConsumer để nhận tin nhắn từ hàng đợi phản hồi, và một nhà sản xuất khác để chuyển tin nhắn đến hàng đợi tin nhắn không hợp lệ.
Một điều mà người yêu cầu phải có khả năng thực hiện là gửi tin nhắn yêu cầu. Để làm được điều đó, nó triển khai phương thức send().
Nó tạo một Tin Nhắn và đặt nội dung của nó thành "Xin chào thế giới."
Nó thiết lập thuộc tính reply-to của tin nhắn thành hàng đợi trả lời. Đây là một Địa chỉ Trả về sẽ cho người phản hồi biết cách gửi lại câu trả lời.
Nó sử dụng requestProducer để gửi tin nhắn. Producer được kết nối với hàng đợi yêu cầu, vì vậy đó là hàng đợi mà tin nhắn được gửi đến.
Nó sau đó in ra các chi tiết của tin nhắn mà nó vừa gửi. Điều này được thực hiện sau khi tin nhắn đã được gửi vì ID tin nhắn được thiết lập bởi hệ thống nhắn tin và không được thiết lập cho đến khi tin nhắn thực sự được gửi đi.
Điều khác mà người yêu cầu phải làm là nhận tin nhắn phản hồi. Nó triển khai phương thức receiveSync() cho mục đích này.
Nó sử dụng Consumer phản hồi của mình để nhận phản hồi. Consumer được kết nối với hàng đợi phản hồi, vì vậy nó sẽ nhận tin nhắn từ đó. Nó sử dụng phương thức receive() để lấy tin nhắn, phương thức này chặn đồng bộ cho đến khi một tin nhắn được gửi đến hàng đợi và được đọc từ hàng đợi, do đó yêu cầu là một Consumer Polling. Vì phương thức receive này là đồng bộ, nên phương thức của yêu cầu được gọi là receiveSync().
Thông điệp nên là một Tin Nhắn Văn Bản. Nếu vậy, người yêu cầu nhận được nội dung của thông điệp và in ra chi tiết của thông điệp.
Nếu thông điệp không phải là Tin Nhắn Văn bản, thì thông điệp đó không thể được xử lý. Thay vì chỉ loại bỏ thông điệp, người yêu cầu sẽ gửi lại nó vào hàng đợi thông điệp không hợp lệ. Việc gửi lại thông điệp sẽ thay đổi ID thông điệp của nó, vì vậy trước khi gửi lại, người yêu cầu sẽ lưu trữ ID thông điệp ban đầu của nó trong ID tương quan của mình (xem Bộ nhận diện Tương quan).
Theo cách này, một yêu cầu viên thực hiện mọi điều cần thiết để gửi một yêu cầu, nhận phản hồi và chuyển phản hồi đến một hàng đợi đặc biệt nếu tin nhắn không có ý nghĩa. (Lưu ý: JMS cung cấp một lớp đặc biệt, QueueRequestor, có mục đích triển khai một yêu cầu viên nhận phản hồi giống như chúng tôi đã thực hiện ở đây. Chúng tôi đã tự triển khai mã thay vì sử dụng lớp JMS đã được xây dựng sẵn để có thể chỉ cho bạn cách mà mã hoạt động.)
Tiếp theo, hãy cùng xem cách triển khai của người trả lời.
import javax.jms.Connection; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.NamingException; public class Replier implements MessageListener { private Session session; private MessageProducer invalidProducer; protected Replier() { super(); } public static Replier newReplier(Connection connection, String requestQueueName, String invalidQueueName) throws JMSException, NamingException { Replier replier = new Replier(); replier.initialize(connection, requestQueueName, invalidQueueName); return replier; } protected void initialize(Connection connection, String requestQueueName, String invalidQueueName) throws NamingException, JMSException { session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination requestQueue = JndiUtil.getDestination(requestQueueName); Destination invalidQueue = JndiUtil.getDestination(invalidQueueName); MessageConsumer requestConsumer = session.createConsumer(requestQueue); MessageListener listener = this; requestConsumer.setMessageListener(listener); invalidProducer = session.createProducer(invalidQueue); } public void onMessage(Message message) { try { if ((message instanceof TextMessage) && (message.getJMSReplyTo() != null)) { TextMessage requestMessage = (TextMessage) message; System.out.println("Received request"); System.out.println("\tTime: " + System.currentTimeMillis() + " ms"); System.out.println("\tMessage ID: " + requestMessage.getJMSMessageID()); System.out.println("\tCorrel. ID: " + requestMessage.getJMSCorrelationID()); System.out.println("\tReply to: " + requestMessage.getJMSReplyTo()); System.out.println("\tContents: " + requestMessage.getText()); String contents = requestMessage.getText(); Destination replyDestination = message.getJMSReplyTo(); MessageProducer replyProducer = session.createProducer(replyDestination); TextMessage replyMessage = session.createTextMessage(); replyMessage.setText(contents); replyMessage.setJMSCorrelationID(requestMessage.getJMSMessageID()); replyProducer.send(replyMessage); System.out.println("Sent reply"); System.out.println("\tTime: " + System.currentTimeMillis() + " ms"); System.out.println("\tMessage ID: " + replyMessage.getJMSMessageID()); System.out.println("\tCorrel. ID: " + replyMessage.getJMSCorrelationID()); System.out.println("\tReply to: " + replyMessage.getJMSReplyTo()); System.out.println("\tContents: " + replyMessage.getText()); } else { System.out.println("Invalid message detected"); System.out.println("\tType: " + message.getClass().getName()); System.out.println("\tTime: " + System.currentTimeMillis() + " ms"); System.out.println("\tMessage ID: " + message.getJMSMessageID()); System.out.println("\tCorrel. ID: " + message.getJMSCorrelationID()); System.out.println("\tReply to: " + message.getJMSReplyTo()); message.setJMSCorrelationID(message.getJMSMessageID()); invalidProducer.send(message); System.out.println("Sent to invalid message queue"); System.out.println("\tType: " + message.getClass().getName()); System.out.println("\tTime: " + System.currentTimeMillis() + " ms"); System.out.println("\tMessage ID: " + message.getJMSMessageID()); System.out.println("\tCorrel. ID: " + message.getJMSCorrelationID()); System.out.println("\tReply to: " + message.getJMSReplyTo()); } } catch (JMSException e) { e.printStackTrace(); } } } Một replier là những gì một ứng dụng có thể sử dụng để nhận yêu cầu và gửi phản hồi. Ứng dụng cung cấp cho người yêu cầu một kết nối đến hệ thống nhắn tin, cũng như các tên JNDI của hàng đợi yêu cầu và hàng đợi tin nhắn không hợp lệ. (Nó không cần chỉ định tên của hàng đợi phản hồi vì, như chúng ta sẽ thấy, điều đó sẽ được cung cấp bởi Địa chỉ Trả về của tin nhắn.) Đây là thông tin mà người yêu cầu cần để khởi tạo chính nó.
Mã khởi tạo của người trả lời khá tương tự với người yêu cầu, nhưng có một vài điểm khác biệt.
Người phản hồi không kiểm tra hàng đợi phản hồi và tạo một nhà sản xuất cho nó. Điều này là vì người phản hồi không giả định rằng nó sẽ luôn gửi các phản hồi trên hàng đợi đó; thay vào đó, như chúng ta sẽ thấy sau này, nó sẽ để thông điệp yêu cầu chỉ cho nó biết hàng đợi nào để gửi thông điệp phản hồi.
Người trả lời là một Người tiêu thụ theo sự kiện, vì vậy nó triển khai MessageListener. Khi một tin nhắn được gửi đến hàng đợi yêu cầu, hệ thống nhắn tin sẽ tự động gọi phương thức onMessage của người trả lời.
Khi người phản hồi đã khởi tạo để trở thành một người lắng nghe trên hàng đợi yêu cầu, không còn nhiều việc để làm ngoài việc chờ đợi tin nhắn. Khác với người yêu cầu, người phải kiểm tra rõ ràng hàng đợi phản hồi để tìm tin nhắn, người phản hồi được điều khiển bởi sự kiện và vì vậy không làm gì cho đến khi hệ thống nhắn tin gọi phương thức onMessage của nó với một tin nhắn mới. Tin nhắn sẽ đến từ hàng đợi yêu cầu vì việc khởi tạo đã tạo ra người tiêu thụ trên hàng đợi yêu cầu. Khi onMessage nhận được một tin nhắn mới, nó sẽ xử lý tin nhắn như sau.
Như với việc người yêu cầu xử lý một thông điệp trả lời, thông điệp yêu cầu được cho là một ThôngĐiệpVănBản. Nó cũng phải chỉ định hàng đợi mà trong đó sẽ gửi phản hồi. Nếu thông điệp không đáp ứng những yêu cầu này, người phản hồi sẽ chuyển thông điệp vào hàng đợi thông điệp không hợp lệ (giống như người yêu cầu).
Nếu thông điệp đáp ứng các yêu cầu, người trả lời sẽ thực hiện phần của Địa chỉ Trả về. Hãy nhớ rằng người yêu cầu đã thiết lập thuộc tính reply-to của thông điệp yêu cầu để chỉ định hàng đợi trả lời. Người trả lời bây giờ lấy giá trị của thuộc tính đó và sử dụng nó để tạo một MessageProducer trên hàng đợi thích hợp. Phần quan trọng ở đây là người trả lời không được lập trình cứng để sử dụng một hàng đợi trả lời cụ thể; mà nó sử dụng bất kỳ hàng đợi trả lời nào mà mỗi thông điệp yêu cầu cụ thể chỉ định.
Người phản hồi sau đó tạo ra tin nhắn trả lời. Trong quá trình này, họ thực hiện Định danh Mối tương quan bằng cách thiết lập thuộc tính correlation-id của tin nhắn trả lời có cùng giá trị với thuộc tính message-id của tin nhắn yêu cầu.
Người trả lời sau đó gửi đi tin nhắn phản hồi và hiển thị chi tiết của nó.
Do đó, một người đáp lại thực hiện mọi điều cần thiết để nhận một tin nhắn (có lẽ là một yêu cầu) và gửi một phản hồi.
Trong khi chúng ta đang nói về điều đó, hãy xem xét một ví dụ về Kênh Tin Nhắn Không Hợp Lệ. Hãy nhớ rằng, một trong những hàng đợi chúng ta cần là hàng đợi có tên jms/InvalidMessages. Hàng đợi này tồn tại để nếu một client JMS (một Điểm Cuối Tin Nhắn) nhận được một tin nhắn mà nó không thể xử lý, nó có thể chuyển tin nhắn lạ đó đến một kênh đặc biệt.
Để chứng minh việc xử lý thông điệp không hợp lệ, chúng tôi đã thiết kế một lớp InvalidMessenger. Đối tượng này được thiết kế cụ thể để gửi một thông điệp trên kênh yêu cầu có định dạng không chính xác. Kênh yêu cầu là một Kênh Kiểu Dữ Liệu mà các bộ nhận yêu cầu mong đợi các yêu cầu ở một định dạng nhất định. InvalidMessenger đơn giản chỉ gửi một thông điệp ở định dạng khác; khi bộ trả lời nhận được thông điệp, nó không nhận ra định dạng của thông điệp, vì vậy nó di chuyển thông điệp vào hàng đợi thông điệp không hợp lệ.
Chúng tôi sẽ chạy trình trả lời trong một cửa sổ và trình nhắn tin không hợp lệ trong một cửa sổ khác. Khi trình nhắn tin không hợp lệ gửi thông điệp của nó, nó sẽ hiển thị đầu ra như thế này:
Sent invalid message Type: com.sun.jms.ObjectMessageImpl Time: 1048288516959 ms Message ID: ID:_XYZ123_1048288516639_7.2.1.1 Correl. ID: null Reply to: com.sun.jms.Queue: jms/ReplyQueue
Điều này cho thấy thông điệp là một thể hiện của ObjectMessage (trong khi người phản hồi đang mong đợi một TextMessage). Người phản hồi nhận được thông điệp không hợp lệ và gửi lại nó vào hàng đợi thông điệp không hợp lệ.
Invalid message detected Type: com.sun.jms.ObjectMessageImpl Time: 1048288517049 ms Message ID: ID:_XYZ123_1048288516639_7.2.1.1 Correl. ID: null Reply to: com.sun.jms.Queue: jms/ReplyQueue Sent to invalid message queue Type: com.sun.jms.ObjectMessageImpl Time: 1048288517140 ms Message ID: ID:_XYZ123_1048287020267_6.2.1.2 Correl. ID: ID:_XYZ123_1048288516639_7.2.1.1 Reply to: com.sun.jms.Queue: jms/ReplyQueue
Một điểm đáng chú ý là khi tin nhắn được chuyển đến hàng đợi tin nhắn không hợp lệ, nó thực sự đang được gửi lại, vì vậy nó nhận một ID tin nhắn mới. Vì lý do này, chúng tôi áp dụng Nhận diện Tương quan; một khi người trả lời xác định tin nhắn là không hợp lệ, họ sao chép ID chính của tin nhắn vào ID tương quan của nó để bảo tồn một bản ghi về ID gốc của tin nhắn. Mã xử lý quá trình tin nhắn không hợp lệ này nằm trong lớp Replier, đã được trình bày trước đây, trong phương thức onMessage. Requestor.receiveSync() chứa mã xử lý tin nhắn không hợp lệ tương tự.
Chúng ta đã thấy cách triển khai hai lớp, Requestor và Replier (Điểm cuối Tin nhắn), để trao đổi các Tin nhắn yêu cầu và phản hồi sử dụng phương pháp Yêu cầu-Phản hồi. Tin nhắn yêu cầu sử dụng Địa chỉ Trả để chỉ định hàng đợi nào để gửi phản hồi. Tin nhắn phản hồi sử dụng Định danh Tương quan để chỉ định yêu cầu nào mà đây là phản hồi cho. Requestor triển khai một Người tiêu dùng Quét để nhận các phản hồi, trong khi Replier triển khai một Người tiêu dùng Dựa vào Sự kiện để nhận các yêu cầu. Các hàng đợi yêu cầu và phản hồi là Kênh Kiểu Dữ liệu; khi một người tiêu dùng nhận được một tin nhắn không phải là loại đúng, nó sẽ chuyển hướng tin nhắn tới Kênh Tin nhắn Không hợp lệ.
Đây là một ví dụ đơn giản về cách sử dụng messaging, được triển khai trong .NET [SysMsg] và C#. Nó cho thấy cách thực hiện Request-Reply, trong đó một ứng dụng yêu cầu gửi một yêu cầu, một ứng dụng phản hồi nhận yêu cầu và trả về một phản hồi, và ứng dụng yêu cầu nhận được phản hồi. Nó cũng cho thấy cách mà một thông điệp không hợp lệ sẽ được chuyển hướng đến một kênh đặc biệt.
Các thành phần của ví dụ Yêu cầu-Phản hồi

Ví dụ này được phát triển bằng cách sử dụng SDK của Microsoft .NET Framework và chạy trên máy tính Windows XP có cài đặt MSMQ [MSMQ].
Ví dụ này bao gồm hai lớp chính.
Người yêu cầu Một điểm cuối tin nhắn gửi một tin nhắn yêu cầu và chờ đợi để nhận một tin nhắn phản hồi như là câu trả lời.
Một Điểm Kết Nối Phản Hồi mà chờ nhận tin nhắn yêu cầu; khi nhận được, nó sẽ phản hồi bằng cách gửi tin nhắn trả lời.
Người gửi yêu cầu và người phản hồi sẽ hoạt động như hai chương trình .NET riêng biệt, điều này tạo ra sự phân tán trong giao tiếp.
Ví dụ này giả định rằng hệ thống nhắn tin có ba hàng đợi này được định nghĩa:
.\private$\RequestQueue Hàng đợi tin nhắn mà người yêu cầu sử dụng để gửi thông điệp yêu cầu đến người trả lời.
.\private$\ReplyQueue Hàng đợi tin nhắn mà người trả lời sử dụng để gửi tin nhắn phản hồi đến người yêu cầu.
.\private$\InvalidQueue Hàng đợi tin nhắn mà người yêu cầu và người phản hồi chuyển một tin nhắn khi họ nhận được một tin nhắn mà họ không thể hiểu.
Dưới đây là cách mà ví dụ hoạt động. Khi yêu cầu được khởi động trong cửa sổ dòng lệnh, nó sẽ bắt đầu và in ra kết quả như thế này:
Sent request Time: 09:11:09.165342 Message ID: 8b0fc389-f21f-423b-9eaa-c3a881a34808\149 Correl. ID: Reply to: .\private$\ReplyQueue Contents: Hello world.
Điều này cho thấy rằng người yêu cầu đã gửi một thông điệp yêu cầu. Lưu ý rằng điều này hoạt động ngay cả khi người trả lời thậm chí không đang chạy và do đó không thể nhận được yêu cầu.
Khi trình trả lời được khởi động trong một cửa sổ dòng lệnh khác, nó bắt đầu và in ra đầu ra như thế này:
Received request Time: 09:11:09.375644 Message ID: 8b0fc389-f21f-423b-9eaa-c3a881a34808\149 Correl. ID: <n/a> Reply to: FORMATNAME:DIRECT=OS:XYZ123\private$\ReplyQueue Contents: Hello world. Sent reply Time: 09:11:09.956480 Message ID: 8b0fc389-f21f-423b-9eaa-c3a881a34808\150 Correl. ID: 8b0fc389-f21f-423b-9eaa-c3a881a34808\149 Reply to: <n/a> Contents: Hello world.
Điều này cho thấy rằng người trả lời đã nhận được tin nhắn yêu cầu và đã gửi một tin nhắn phản hồi.
Có nhiều điểm thú vị trong kết quả này. Đầu tiên, hãy chú ý đến thời gian gửi và nhận yêu cầu; yêu cầu được nhận sau khi nó được gửi (210302 ms sau). Thứ hai, hãy lưu ý rằng ID tin nhắn giống nhau trong cả hai trường hợp, bởi vì đó là cùng một tin nhắn. Thứ ba, hãy nhận thấy rằng nội dung, "Xin chào thế giới", là giống nhau, điều này hợp lý vì đó là dữ liệu đã được gửi, và nó phải giống nhau ở cả hai bên. Thứ tư, tin nhắn yêu cầu chỉ định hàng đợi là địa điểm cho tin nhắn phản hồi (một ví dụ về Địa chỉ Trả về).
Tiếp theo, hãy so sánh đầu ra từ việc nhận yêu cầu với việc gửi phản hồi. Đầu tiên, lưu ý rằng phản hồi không được gửi cho đến khi yêu cầu được nhận (sau 580836 ms). Thứ hai, ID của thông điệp phản hồi khác với ID của thông điệp yêu cầu; điều này là do các thông điệp yêu cầu và phản hồi là các thông điệp khác nhau, riêng biệt. Thứ ba, nội dung của yêu cầu đã được trích xuất và thêm vào phản hồi. Thứ tư, điểm đến để phản hồi không được chỉ định vì không mong đợi phản hồi (phản hồi không sử dụng Địa chỉ Trả). Thứ năm, ID tương quan của phản hồi giống với ID của thông điệp yêu cầu (phản hồi có sử dụng Nhận dạng Tương quan).
Cuối cùng, trở lại cửa sổ đầu tiên, người yêu cầu nhận được phản hồi sau:
Received reply Time: 09:11:10.156467 Message ID: 8b0fc389-f21f-423b-9eaa-c3a881a34808\150 Correl. ID: 8b0fc389-f21f-423b-9eaa-c3a881a34808\149 Reply to: <n/a> Contents: Hello world.
Đầu ra này chứa nhiều mục thú vị. Phản hồi được nhận khoảng hai giây sau khi nó được gửi. ID tin nhắn của phản hồi giống như khi nó được nhận và khi nó được gửi, điều này chứng tỏ rằng đó thực sự là cùng một tin nhắn. Nội dung tin nhắn được nhận giống như những gì đã được gửi, và ID tương quan cho biết cho người yêu cầu biết phản hồi này là cho yêu cầu nào (Định danh Tương quan).
Người yêu cầu không chạy lâu; họ gửi một yêu cầu, nhận một phản hồi, và thoát. Tuy nhiên, người phản hồi chạy liên tục, chờ đợi các yêu cầu và gửi phản hồi. Để dừng người phản hồi, chúng ta vào cửa sổ lệnh của nó và nhấn phím return, điều này khiến chương trình phản hồi thoát.
Vậy là ví dụ về yêu cầu - phản hồi trong .NET. Một yêu cầu đã được chuẩn bị và gửi bởi người yêu cầu. Người phản hồi đã nhận yêu cầu và gửi một phản hồi. Sau đó, người yêu cầu đã nhận được phản hồi cho yêu cầu ban đầu của mình.
Trước tiên, hãy cùng xem cách yêu cầu được triển khai.
using System; using System.Messaging; public class Requestor { private MessageQueue requestQueue; private MessageQueue replyQueue; public Requestor(String requestQueueName, String replyQueueName) { requestQueue = new MessageQueue(requestQueueName); replyQueue = new MessageQueue(replyQueueName); replyQueue.MessageReadPropertyFilter.SetAll(); ((XmlMessageFormatter)replyQueue.Formatter).TargetTypeNames = new string[]{"System.String,mscorlib"}; } public void Send() { Message requestMessage = new Message(); requestMessage.Body = "Hello world."; requestMessage.ResponseQueue = replyQueue; requestQueue.Send(requestMessage); Console.WriteLine("Sent request"); Console.WriteLine("\tTime: {0}", DateTime.Now.ToString("HH:mm:ss.ffffff")); Console.WriteLine("\tMessage ID: {0}", requestMessage.Id); Console.WriteLine("\tCorrel. ID: {0}", requestMessage.CorrelationId); Console.WriteLine("\tReply to: {0}", requestMessage.ResponseQueue.Path); Console.WriteLine("\tContents: {0}", requestMessage.Body.ToString()); } public void ReceiveSync() { Message replyMessage = replyQueue.Receive(); Console.WriteLine("Received reply"); Console.WriteLine("\tTime: {0}", DateTime.Now.ToString("HH:mm:ss.ffffff")); Console.WriteLine("\tMessage ID: {0}", replyMessage.Id); Console.WriteLine("\tCorrel. ID: {0}", replyMessage.CorrelationId); Console.WriteLine("\tReply to: {0}", "<n/a>"); Console.WriteLine("\tContents: {0}", replyMessage.Body.ToString()); } } Một ứng dụng muốn gửi yêu cầu và nhận phản hồi có thể sử dụng một trình gửi yêu cầu để thực hiện điều đó. Ứng dụng chỉ định tên đường dẫn của hai hàng đợi: hàng đợi yêu cầu và hàng đợi phản hồi. Đây là thông tin mà trình gửi yêu cầu cần để khởi tạo chính nó.
Trong hàm khởi tạo requestor, requestor sử dụng tên hàng đợi để kết nối với hệ thống nhắn tin.
Nó sử dụng tên hàng đợi để tra cứu các hàng đợi, đó là MessageQueues. Các tên này là đường dẫn đến các tài nguyên MSMQ.
Nó thiết lập bộ lọc thuộc tính của hàng đợi trả lời để khi một tin nhắn được đọc từ hàng đợi, tất cả các thuộc tính của tin nhắn đó cũng sẽ được đọc. Nó cũng thiết lập TargetTypeNames của bộ định dạng để nội dung của tin nhắn sẽ được diễn giải dưới dạng chuỗi.
Một điều mà người yêu cầu phải có khả năng làm là gửi tin nhắn yêu cầu. Để làm được điều đó, nó triển khai phương thức Send().
Nó tạo một thông điệp và đặt nội dung của nó thành "Xin chào thế giới."
Nó thiết lập thuộc tính ResponseQueue của thông điệp thành hàng đợi phản hồi. Đây là một Địa chỉ Trả Lời sẽ cho người trả lời biết cách gửi lại phản hồi.
Nó sau đó gửi tin nhắn đến hàng đợi.
Nó sau đó in ra chi tiết của tin nhắn mà nó vừa gửi. Điều này được thực hiện sau khi tin nhắn được gửi đi vì ID tin nhắn được thiết lập bởi hệ thống nhắn tin và không được thiết lập cho đến khi tin nhắn thực sự được gửi.
Điều khác mà người yêu cầu phải có khả năng làm là nhận các tin nhắn phản hồi. Nó triển khai phương thức ReceiveSync() cho mục đích này.
Nó chạy phương thức Receive() của hàng đợi để nhận thông điệp, điều này đồng bộ chặn cho đến khi một thông điệp được gửi đến hàng đợi và được đọc ra từ hàng đợi, vì vậy người yêu cầu là một Người tiêu dùng Polling. Bởi vì phương thức nhận này là đồng bộ, phương thức của người yêu cầu được gọi là ReceiveSync().
Người yêu cầu nhận nội dung của tin nhắn và in ra các chi tiết của tin nhắn.
Theo cách này, người yêu cầu làm mọi điều cần thiết để gửi một yêu cầu và nhận phản hồi.
Tiếp theo, hãy xem cách mà bộ phận trả lời được triển khai.
using System; using System.Messaging; class Replier { private MessageQueue invalidQueue; public Replier(String requestQueueName, String invalidQueueName) { MessageQueue requestQueue = new MessageQueue(requestQueueName); invalidQueue = new MessageQueue(invalidQueueName); requestQueue.MessageReadPropertyFilter.SetAll(); ((XmlMessageFormatter)requestQueue.Formatter).TargetTypeNames = new string[]{"System.String,mscorlib"}; requestQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(OnReceiveCompleted); requestQueue.BeginReceive(); } public void OnReceiveCompleted(Object source, ReceiveCompletedEventArgs asyncResult) { MessageQueue requestQueue = (MessageQueue)source; Message requestMessage = requestQueue.EndReceive(asyncResult.AsyncResult); try { Console.WriteLine("Received request"); Console.WriteLine("\tTime: {0}", DateTime.Now.ToString("HH:mm:ss.ffffff")); Console.WriteLine("\tMessage ID: {0}", requestMessage.Id); Console.WriteLine("\tCorrel. ID: {0}", "<n/a>"); Console.WriteLine("\tReply to: {0}", requestMessage.ResponseQueue.Path); Console.WriteLine("\tContents: {0}", requestMessage.Body.ToString()); string contents = requestMessage.Body.ToString(); MessageQueue replyQueue = requestMessage.ResponseQueue; Message replyMessage = new Message(); replyMessage.Body = contents; replyMessage.CorrelationId = requestMessage.Id; replyQueue.Send(replyMessage); Console.WriteLine("Sent reply"); Console.WriteLine("\tTime: {0}", DateTime.Now.ToString("HH:mm:ss.ffffff")); Console.WriteLine("\tMessage ID: {0}", replyMessage.Id); Console.WriteLine("\tCorrel. ID: {0}", replyMessage.CorrelationId); Console.WriteLine("\tReply to: {0}", "<n/a>"); Console.WriteLine("\tContents: {0}", replyMessage.Body.ToString()); } catch ( Exception ) { Console.WriteLine("Invalid message detected"); Console.WriteLine("\tType: {0}", requestMessage.BodyType); Console.WriteLine("\tTime: {0}", DateTime.Now.ToString("HH:mm:ss.ffffff")); Console.WriteLine("\tMessage ID: {0}", requestMessage.Id); Console.WriteLine("\tCorrel. ID: {0}", "<n/a>"); Console.WriteLine("\tReply to: {0}", "<n/a>"); requestMessage.CorrelationId = requestMessage.Id; invalidQueue.Send(requestMessage); Console.WriteLine("Sent to invalid message queue"); Console.WriteLine("\tType: {0}", requestMessage.BodyType); Console.WriteLine("\tTime: {0}", DateTime.Now.ToString("HH:mm:ss.ffffff")); Console.WriteLine("\tMessage ID: {0}", requestMessage.Id); Console.WriteLine("\tCorrel. ID: {0}", requestMessage.CorrelationId); Console.WriteLine("\tReply to: {0}", requestMessage.ResponseQueue.Path); } requestQueue.BeginReceive(); } } Khi một ứng dụng cần nhận một yêu cầu và gửi phản hồi, nó sẽ triển khai một cái gì đó giống như bộ phản hồi này. Ứng dụng chỉ định đường dẫn của các hàng đợi tin nhắn yêu cầu và không hợp lệ. (Nó không cần chỉ định tên của hàng đợi phản hồi vì, như chúng ta sẽ thấy sau, điều đó sẽ được cung cấp bởi Địa chỉ Trả về của tin nhắn.) Đây là thông tin mà người yêu cầu cần để khởi tạo chính nó.
Constructor của người trả lời rất giống với của người yêu cầu, nhưng có một vài điểm khác biệt.
Một khác biệt là người trả lời không kiểm tra hàng đợi phản hồi. Điều này là vì người trả lời không giả định rằng nó sẽ luôn gửi phản hồi trên hàng đợi đó; thay vào đó, như chúng ta sẽ thấy, nó sẽ để tin nhắn yêu cầu cho biết hàng đợi nào để gửi tin nhắn phản hồi.
Một sự khác biệt khác là người phản hồi là một Người Tiêu Thụ Dựa Trên Sự Kiện, vì vậy nó thiết lập một Trình Xử Lý Sự Kiện Nhận Hoàn Tất. Khi một tin nhắn được gửi đến hàng đợi yêu cầu, hệ thống nhắn tin sẽ tự động gọi phương thức đã chỉ định, OnReceiveCompleted.
Người trả lời khởi tạo chính nó như một listener trên hàng đợi yêu cầu, và sau đó đơn giản chờ đợi các tin nhắn đến. Khác với người gửi yêu cầu, người trả lời không phải kiểm tra rõ ràng hàng đợi trả lời để tìm tin nhắn, mà hoạt động dựa trên sự kiện và vì vậy không làm gì cho đến khi hệ thống nhắn gọi phương thức OnReceiveCompleted của nó với một tin nhắn mới. Tin nhắn đó sẽ đến từ hàng đợi yêu cầu vì constructor đã tạo ra bộ xử lý sự kiện trên hàng đợi yêu cầu. Một khi OnReceiveCompleted được gọi, đây là những gì nó thực hiện để nhận tin nhắn mới và xử lý nó:
Nguồn là một MessageQueue, hàng đợi yêu cầu.
Thông điệp được lấy bằng cách chạy phương thức EndReceive của hàng đợi. Người phản hồi sau đó in ra các chi tiết về thông điệp.
Người trả lời thực hiện phần của mình trong Địa Chỉ Trả Lời. Hãy nhớ rằng người yêu cầu đã thiết lập thuộc tính hàng đợi phản hồi của thông điệp yêu cầu để chỉ định hàng đợi phản hồi. Người trả lời bây giờ lấy giá trị của thuộc tính đó và sử dụng nó để tham chiếu đến MessageQueue phù hợp. Phần quan trọng ở đây là người trả lời không bị mã hóa cứng để sử dụng một hàng đợi phản hồi cụ thể; nó sử dụng bất kỳ hàng đợi phản hồi nào mà mỗi thông điệp yêu cầu cụ thể chỉ định.
Người trả lời sau đó tạo ra tin nhắn phản hồi. Trong quá trình này, họ thực hiện Nhận diện Tương quan bằng cách thiết lập thuộc tính mã định danh tương quan của tin nhắn phản hồi thành giá trị giống như thuộc tính mã định danh tin nhắn của tin nhắn yêu cầu.
Người trả lời sau đó gửi đi tin nhắn trả lời và hiển thị chi tiết của nó.
Nếu thông điệp có thể được nhận nhưng không thể xử lý thành công và một ngoại lệ được ném ra, bên phản hồi sẽ gửi lại thông điệp đến hàng đợi thông điệp không hợp lệ. Trong quá trình này, nó sẽ thiết lập ID tương quan của thông điệp mới thành ID của thông điệp gốc.
Khi người phản hồi đã hoàn tất việc xử lý tin nhắn, họ sẽ gọi BeginReceive để bắt đầu lắng nghe tin nhắn tiếp theo.
Do đó, một người trả lời thực hiện mọi việc cần thiết để nhận được một tin nhắn (có thể là một yêu cầu) và gửi phản hồi. Nếu không thể trả lời một tin nhắn, nó sẽ chuyển tin nhắn đó vào hàng đợi tin nhắn không hợp lệ.
Hãy cùng xem một ví dụ về Kênh Tin Nhắn Không Hợp Lệ. Nhớ rằng, một trong những hàng đợi mà chúng ta cần là hàng đợi có tên private$\InvalidMessages. Hàng đợi này tồn tại để nếu một ứng dụng khách MSMQ (một Điểm Cuối Tin Nhắn) nhận được một tin nhắn mà nó không thể xử lý, nó có thể chuyển tin nhắn lạ đó đến một kênh đặc biệt.
Để minh họa việc xử lý thông điệp không hợp lệ, chúng tôi đã thiết kế một lớp InvalidMessenger. Đối tượng này được thiết kế đặc biệt để gửi một thông điệp trên kênh yêu cầu có định dạng không đúng. Giống như bất kỳ kênh nào, kênh yêu cầu là một Kênh Loại Dữ Liệu ở chỗ các người nhận yêu cầu mong đợi các yêu cầu có định dạng nhất định. Người gửi không hợp lệ chỉ đơn giản gửi một thông điệp ở định dạng khác; khi người đáp nhận nhận được thông điệp, họ không nhận ra định dạng của thông điệp, vì vậy họ chuyển thông điệp vào hàng đợi thông điệp không hợp lệ.
Chúng tôi sẽ chạy trình trả lời trong một cửa sổ và trình gửi tin nhắn không hợp lệ trong một cửa sổ khác. Khi trình gửi tin nhắn không hợp lệ gửi tin nhắn của nó, nó sẽ hiển thị đầu ra như thế này:
Sent request Type: 768 Time: 09:39:44.223729 Message ID: 8b0fc389-f21f-423b-9eaa-c3a881a34808\168 Correl. ID: 00000000-0000-0000-0000-000000000000\0 Reply to: .\private$\ReplyQueue
Loại 768 có nghĩa là định dạng của nội dung thông điệp là nhị phân (trong khi đó, người trả lời lại mong đợi nội dung dưới dạng văn bản/XML). Người trả lời nhận thông điệp không hợp lệ và gửi lại nó vào hàng đợi thông điệp không hợp lệ.
Invalid message detected Type: 768 Time: 09:39:44.233744 Message ID: 8b0fc389-f21f-423b-9eaa-c3a881a34808\168 Correl. ID: <n/a> Reply to: <n/a> Sent to invalid message queue Type: 768 Time: 09:39:44.233744 Message ID: 8b0fc389-f21f-423b-9eaa-c3a881a34808\169 Correl. ID: 8b0fc389-f21f-423b-9eaa-c3a881a34808\168 Reply to: FORMATNAME:DIRECT=OS:XYZ123\private$\ReplyQueue
Một điều đáng lưu ý là khi tin nhắn bị chuyển đến hàng đợi tin nhắn không hợp lệ, nó thực sự đang được gửi lại, vì vậy nó nhận một ID tin nhắn mới. Vì lý do này, chúng tôi áp dụng Mã định danh Tương quan; khi người phản hồi xác định tin nhắn là không hợp lệ, họ sao chép ID chính của tin nhắn vào Mã định danh Tương quan để bảo tồn một bản ghi về ID gốc của tin nhắn. Mã xử lý quá trình tin nhắn không hợp lệ này nằm trong lớp Replier, như đã trình bày trước đó, trong phương thức OnReceiveCompleted.
Chúng ta đã thấy cách triển khai hai lớp, Yêu cầu và Đáp lại (Điểm cuối Tin nhắn), mà trao đổi yêu cầu và phản hồi Tin nhắn bằng cách sử dụng Yêu cầu-Phản hồi. Tin nhắn yêu cầu sử dụng Địa chỉ Trả về để chỉ định hàng đợi nào sẽ gửi phản hồi. Tin nhắn phản hồi sử dụng Định danh Liên quan để chỉ định yêu cầu này là phản hồi cho yêu cầu nào. Người yêu cầu triển khai một Người tiêu dùng Kiểm tra để nhận phản hồi, trong khi người đáp lại triển khai một Người tiêu dùng Dựa trên Sự kiện để nhận yêu cầu. Các hàng đợi yêu cầu và phản hồi là Kênh Kiểu dữ liệu; khi một người tiêu dùng nhận được một tin nhắn không phải là loại đúng, nó sẽ chuyển hướng tin nhắn đó đến Kênh Tin nhắn Không hợp lệ.
Đây là một ví dụ đơn giản cho thấy sức mạnh của việc nhắn tin theo mô hình xuất bản-đăng ký và khám phá các thiết kế thay thế có sẵn. Nó cho thấy cách mà nhiều ứng dụng đăng ký có thể được thông báo về một sự kiện duy nhất bằng cách xuất bản sự kiện chỉ một lần và xem xét các chiến lược thay thế để truyền đạt chi tiết của sự kiện đó đến các người đăng ký.
Xuất bản-Đăng ký Sử dụng một Chủ đề JMS

Để hiểu cách một Kênh Publish-Subscribe đơn giản thực sự hữu ích như thế nào, trước tiên chúng ta cần xem xét việc triển khai mẫu Observer theo cách phân tán giữa nhiều ứng dụng như thế nào. Trước khi đi vào chi tiết, hãy cùng xem lại những điều cơ bản về Observer.
Mô hình Observer [GoF] tài liệu một thiết kế cho phép một đối tượng thông báo cho các đối tượng phụ thuộc của nó về một sự thay đổi, đồng thời giữ cho đối tượng đó không bị ràng buộc với các phụ thuộc của nó, để đối tượng đó hoạt động tốt dù có bao nhiêu phụ thuộc, thậm chí là không có phụ thuộc nào. Các tham gia của nó bao gồm một Subject - đối tượng thông báo sự thay đổi trong trạng thái của nó và các Observer - các đối tượng quan tâm nhận thông báo về sự thay đổi trong Subject. Khi trạng thái của một subject thay đổi, nó gọi phương thức Notify(), mà trong đó biết danh sách các observer và gọi Update() cho từng observer. Một số observer có thể không quan tâm đến sự thay đổi trạng thái này, nhưng những người quan tâm có thể tìm ra trạng thái mới bằng cách gọi GetState() trên subject. Subject cũng phải thực hiện các phương thức Attach(Observer) và Detach(Observer) mà các observer sử dụng để đăng ký quan tâm.
Nguyên tắc Observer cung cấp hai cách để lấy trạng thái mới từ chủ thể đến người quan sát: mô hình đẩy (push model) và mô hình kéo (pull model). Với mô hình đẩy, cuộc gọi Update đến mỗi người quan sát chứa trạng thái mới như một tham số. Do đó, những người quan sát quan tâm có thể tránh phải gọi GetState(), nhưng công sức sẽ bị lãng phí khi truyền dữ liệu cho những người quan sát không quan tâm. Phương pháp đối lập là mô hình kéo, nơi chủ thể gửi thông báo cơ bản và mỗi người quan sát yêu cầu trạng thái mới từ chủ thể. Do vậy, mỗi người quan sát có thể yêu cầu các chi tiết chính xác mà họ muốn, thậm chí không yêu cầu gì cả, nhưng chủ thể thường phải đáp ứng nhiều yêu cầu cho cùng một dữ liệu. Mô hình đẩy yêu cầu một giao tiếp đơn lẻ, một chiều - chủ thể đẩy dữ liệu đến người quan sát như một phần của cập nhật. Mô hình kéo yêu cầu ba giao tiếp một chiều - chủ thể thông báo cho người quan sát, người quan sát yêu cầu trạng thái hiện tại từ chủ thể, và chủ thể gửi trạng thái hiện tại đến người quan sát. Như chúng ta sẽ thấy, số lượng giao tiếp một chiều ảnh hưởng đến cả độ phức tạp thiết kế và hiệu suất thời gian chạy của thông báo.
Cách dễ nhất để triển khai phương thức Notify() của chủ thể là với một luồng duy nhất, nhưng điều đó có thể có những ảnh hưởng về hiệu suất không mong muốn. Một luồng duy nhất sẽ cập nhật từng người quan sát một cách tuần tự, vì vậy những người ở cuối danh sách dài các người quan sát có thể phải chờ đợi lâu cho các cập nhật. Hơn nữa, một chủ thể dành nhiều thời gian để cập nhật tất cả các người quan sát của nó cũng không hoàn thành bất kỳ điều gì khác. Còn tệ hơn, một người quan sát có thể sẽ sử dụng luồng cập nhật của mình để phản ứng với cập nhật bằng cách truy vấn chủ thể để lấy trạng thái và xử lý dữ liệu mới; công việc của người quan sát trong luồng cập nhật khiến quá trình cập nhật mất nhiều thời gian hơn.
Do đó, cách tinh vi hơn để triển khai phương thức Notify() của một chủ thể là chạy mỗi cuộc gọi Update() trong một luồng riêng. Như vậy, tất cả các bộ quan sát có thể được cập nhật đồng thời, và bất kỳ công việc nào mà mỗi bộ quan sát có thể thực hiện trong luồng cập nhật của nó sẽ không làm chậm lại các bộ quan sát khác hoặc chủ thể. Nhược điểm là việc triển khai đa luồng và xử lý các vấn đề quản lý luồng phức tạp hơn.
Mẫu Observer có xu hướng giả định rằng chủ thể và các trình quan sát đều chạy trong cùng một ứng dụng. Thiết kế của mẫu hỗ trợ phân phối, nơi các trình quan sát chạy trong một không gian bộ nhớ riêng biệt so với chủ thể và có thể là so với nhau, nhưng việc phân phối này đòi hỏi công sức. Các phương thức Update() và GetState(), cũng như các phương thức Attach và Detach, phải được truy cập từ xa (xem Gọi Thủ Tục Từ Xa). Bởi vì chủ thể phải có khả năng gọi đến từng trình quan sát, và ngược lại, mỗi đối tượng phải chạy trong một môi trường nào đó của môi giới yêu cầu đối tượng (ORB) cho phép các đối tượng mà nó chứa được gọi từ xa. Bởi vì các chi tiết cập nhật và dữ liệu trạng thái sẽ được truyền giữa các không gian bộ nhớ, các ứng dụng phải có khả năng tuần tự hóa, tức là, chuẩn bị các đối tượng mà chúng đang truyền đi.
Do đó, việc triển khai Observer trong một môi trường phân tán có thể trở nên khá phức tạp. Không chỉ việc triển khai một Observer có đa luồng hơi khó khăn, mà việc làm cho các phương thức có thể truy cập từ xa và gọi chúng từ xa còn làm tăng thêm độ khó. Chỉ để thông báo cho một số phụ thuộc về những thay đổi trạng thái có thể là một khối lượng công việc lớn.
Một vấn đề khác là Cuộc gọi Thủ tục Từ xa chỉ hoạt động khi nguồn gọi, mục tiêu và mạng kết nối chúng đều hoạt động đúng cách. Nếu một chủ thể thông báo một thay đổi và một trình theo dõi từ xa không sẵn sàng xử lý thông báo hoặc bị ngắt kết nối với mạng, trình theo dõi sẽ mất thông báo đó. Mặc dù trình theo dõi có thể hoạt động tốt mà không có thông báo trong một số trường hợp, nhưng trong những trường hợp khác, việc mất thông báo có thể khiến trình theo dõi không còn đồng bộ với chủ thể - chính vấn đề mà mẫu Observer được thiết kế để ngăn chặn.
Phân phối cũng ủng hộ mô hình đẩy hơn mô hình kéo. Như đã thảo luận trước đó, mô hình đẩy yêu cầu một giao tiếp đơn, một chiều, trong khi mô hình kéo yêu cầu ba giao tiếp. Khi phân phối được thực hiện thông qua RPC (Gọi Thủ tục Từ xa), mô hình đẩy yêu cầu một cuộc gọi (Update()), trong khi mô hình kéo yêu cầu ít nhất hai cuộc gọi (Update() và GetState()). RPC có chi phí tài nguyên cao hơn so với các cuộc gọi phương thức không phân phối, vì vậy những cuộc gọi bổ sung cần thiết cho phương pháp đẩy có thể nhanh chóng ảnh hưởng đến hiệu suất.
Một kênh Xuất-Biên nhận triển khai mẫu Quan sát, giúp cho mẫu này dễ sử dụng hơn giữa các ứng dụng phân tán. Mẫu này được triển khai qua ba bước.
Người quản trị hệ thống nhắn tin tạo một Kênh Đăng phát - Đăng ký. (Điều này sẽ được biểu diễn trong các ứng dụng Java dưới dạng JMS Topic.)
Ứng dụng đóng vai trò chủ đề tạo ra một TopicPublisher (một loại MessageProducer) để gửi tin nhắn trên kênh.
Mỗi ứng dụng hoạt động như một người quan sát (ví dụ, một thực thể phụ thuộc) sẽ tạo ra một TopicSubscriber (một loại MessageConsumer) để nhận thông điệp trên kênh. (Điều này tương tự như việc gọi phương thức Attach(Observer) trong mẫu Thiết kế Observer.)
Điều này thiết lập một kết nối giữa chủ thể và các quan sát viên thông qua kênh. Bây giờ, bất cứ khi nào chủ thể có sự thay đổi để thông báo, nó sẽ gửi một tin nhắn. Kênh sẽ đảm bảo rằng mỗi quan sát viên nhận được một bản sao của tin nhắn này.
Dưới đây là một ví dụ đơn giản về mã cần thiết để thông báo sự thay đổi:
import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.NamingException; public class SubjectGateway { public static final String UPDATE_TOPIC_NAME = "jms/Update"; private Connection connection; private Session session; private MessageProducer updateProducer; protected SubjectGateway() { super(); } public static SubjectGateway newGateway() throws JMSException, NamingException { SubjectGateway gateway = new SubjectGateway(); gateway.initialize(); return gateway; } protected void initialize() throws JMSException, NamingException { ConnectionFactory connectionFactory = JndiUtil.getQueueConnectionFactory(); connection = connectionFactory.createConnection(); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination updateTopic = JndiUtil.getDestination(UPDATE_TOPIC_NAME); updateProducer = session.createProducer(updateTopic); connection.start(); } public void notify(String state) throws JMSException { TextMessage message = session.createTextMessage(state); updateProducer.send(message); } public void release() throws JMSException { if (connection != null) { connection.stop(); connection.close(); } } } Cổng thông tin Chủ thể là một cổng tin nhắn giữa chủ thể (không được hiển thị) và hệ thống nhắn tin. Chủ thể tạo ra cổng và sau đó sử dụng nó để phát thông báo. Về cơ bản, phương thức Notify() của chủ thể được triển khai để gọi SubjectGateway.notify(String). Cổng sau đó thông báo về sự thay đổi bằng cách gửi một tin nhắn trên kênh cập nhật.
Dưới đây là một ví dụ về mã cần thiết để nhận thông báo thay đổi:
import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.NamingException; public class ObserverGateway implements MessageListener { public static final String UPDATE_TOPIC_NAME = "jms/Update"; private Observer observer; private Connection connection; private MessageConsumer updateConsumer; protected ObserverGateway() { super(); } public static ObserverGateway newGateway(Observer observer) throws JMSException, NamingException { ObserverGateway gateway = new ObserverGateway(); gateway.initialize(observer); return gateway; } protected void initialize(Observer observer) throws JMSException, NamingException { this.observer = observer; ConnectionFactory connectionFactory = JndiUtil.getQueueConnectionFactory(); connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination updateTopic = JndiUtil.getDestination(UPDATE_TOPIC_NAME); updateConsumer = session.createConsumer(updateTopic); updateConsumer.setMessageListener(this); } public void onMessage(Message message) { try { TextMessage textMsg = (TextMessage) message; // assume cast always works String newState = textMsg.getText(); update(newState); } catch (JMSException e) { e.printStackTrace(); } } public void attach() throws JMSException { connection.start(); } public void detach() throws JMSException { if (connection != null) { connection.stop(); connection.close(); } } private void update(String newState) throws JMSException { observer.update(newState); } } Gateway Observer là một Cổng thông điệp khác, lần này giữa bộ quan sát (không được hiển thị) và hệ thống nhắn tin. Bộ quan sát tạo ra cổng, sau đó sử dụng phương thức attach() để bắt đầu kết nối (điều này tương tự như việc gọi phương thức Attach(Observer) trong mẫu Observer). Cổng là một Người tiêu dùng Theo sự kiện, vì vậy nó triển khai giao diện MessageListener, yêu cầu phương thức onMessage. Bằng cách này, khi một cập nhật được nhận, cổng sẽ xử lý thông điệp để lấy trạng thái mới và gọi phương thức update(String) của riêng nó, sau đó gọi thông điệp tương ứng trong bộ quan sát.
Hai lớp này thực hiện phiên bản mô hình đẩy của Observer. Với thông điệp thông báo được gửi bởi SubjectGateway.notify(String), sự tồn tại của thông điệp cho biết rằng một sự thay đổi đã xảy ra, nhưng nội dung của thông điệp mới cho biết trạng thái mới của đối tượng là gì. Trạng thái mới đang được đẩy từ đối tượng đến người quan sát. Như chúng ta sẽ thấy sau, có một cách khác để thực hiện chức năng này bằng cách sử dụng mô hình kéo.
Để phân phối thông báo giữa các ứng dụng, phương pháp công bố-đăng ký (ví dụ: nhắn tin) có một số lợi thế so với phương pháp đồng bộ truyền thống (ví dụ: RPC) trong việc triển khai Observer.
Đơn giản hóa thông báo. Việc thực hiện Notify() của chủ thể trở nên cực kỳ đơn giản; mã chỉ cần gửi một thông điệp qua một kênh. Tương tự, Observer.Update() chỉ cần nhận một thông điệp.
Đơn giản hóa việc gắn/bỏ gắn. Thay vì gắn và bỏ gắn vào đối tượng, một người quan sát cần phải đăng ký và hủy đăng ký từ kênh. Đối tượng không cần phải thực hiện các phương thức Gắn(Kẻ quan sát) hoặc Bỏ gắn(Kẻ quan sát) (mặc dù người quan sát có thể thực hiện các phương thức này để bao bọc hành vi đăng ký và hủy đăng ký).
Đơn giản hóa việc tạo luồng đồng thời. Chủ thể chỉ cần một luồng để cập nhật tất cả các quan sát viên đồng thời; kênh sẽ gửi thông điệp thông báo đến các quan sát viên đồng thời và mỗi quan sát viên xử lý cập nhật trong luồng riêng của nó. Điều này đơn giản hóa việc triển khai của chủ thể, và vì mỗi quan sát viên sử dụng luồng riêng của mình, những gì một quan sát viên thực hiện trong luồng cập nhật của nó sẽ không ảnh hưởng đến những người khác.
Đơn giản hóa việc truy cập từ xa. Cả đối tượng và người quan sát đều không cần phải triển khai bất kỳ phương pháp từ xa nào, cũng như không cần phải chạy trong một ORB. Họ chỉ cần truy cập vào hệ thống nhắn tin, và hệ thống sẽ xử lý việc phân phối.
Tăng cường độ tin cậy. Bởi vì kênh sử dụng giao tiếp, các thông báo sẽ được xếp hàng cho đến khi người quan sát có thể xử lý chúng, điều này cũng cho phép người quan sát điều chỉnh số lượng thông báo. Nếu một người quan sát muốn nhận các thông báo được gửi trong khi người đó bị ngắt kết nối, họ nên thiết lập mình thành một Người Đăng Ký Bền Vững.
Một vấn đề mà phương pháp công bố - đăng ký không thay đổi là việc tuần tự hóa. Dù Observer được triển khai qua RPC hay nhắn tin, dữ liệu trạng thái được phân phối từ không gian bộ nhớ của đối tượng sang không gian bộ nhớ của mỗi observer, vì vậy dữ liệu phải được tuần tự hóa (tức là, đóng gói). Hành vi này phải được thực hiện cho cả hai phương pháp.
Nếu phương pháp pub-sub có một nhược điểm, đó là phương pháp này yêu cầu có hệ thống nhắn tin, có nghĩa là các ứng dụng chủ đề và người quan sát phải có quyền truy cập vào một hệ thống nhắn tin chung và phải được triển khai như là các khách hàng của hệ thống nhắn tin đó. Tuy nhiên, việc biến các ứng dụng thành khách hàng nhắn tin không khó khăn hơn, và có lẽ dễ hơn, so với việc sử dụng phương pháp RPC.
Một nhược điểm tiềm tàng khác của phương pháp xuất bản-đăng ký là mô hình kéo phức tạp hơn mô hình đẩy. Như đã thảo luận trước đó, mô hình kéo yêu cầu nhiều trao đổi qua lại hơn so với mô hình đẩy. Khi cuộc thảo luận diễn ra giữa các ứng dụng phân tán, việc giao tiếp thêm có thể ảnh hưởng đáng kể đến hiệu suất.
Giao tiếp phức tạp hơn với nhắn tin so với RPC. Trong cả hai trường hợp, Update() là một giao tiếp một chiều, either là một RPC trả về void hoặc một Thông điệp Sự kiện duy nhất từ chủ thể đến người quan sát. Phần khó hơn là khi một người quan sát cần truy vấn trạng thái của chủ thể. GetState() là một giao tiếp hai chiều, either là một RPC duy nhất yêu cầu trạng thái và trả lại nó, hoặc một yêu cầu-trả lời, một cặp thông điệp trong đó một Thông điệp Lệnh yêu cầu trạng thái và một Thông điệp Tài liệu riêng biệt trả lại nó.
Điều làm cho Request-Reply trở nên khó khăn hơn không chỉ là nó yêu cầu một cặp tin nhắn, mà còn yêu cầu một cặp kênh để truyền tải những tin nhắn đó. Một kênh, kênh yêu cầu lấy trạng thái, đi từ người quan sát đến đối tượng; người quan sát gửi yêu cầu trạng thái qua kênh đó. Kênh còn lại, kênh phản hồi trạng thái, đi từ đối tượng trở lại người quan sát; đối tượng gửi phản hồi trạng thái qua kênh đó. Tất cả các người quan sát có thể chia sẻ cùng một kênh yêu cầu, nhưng có lẽ mỗi người sẽ cần kênh phản hồi riêng. Mỗi người quan sát cần nhận được không chỉ bất kỳ phản hồi nào mà là phản hồi cụ thể cho yêu cầu của mình, và cách dễ nhất để đảm bảo điều này là để mỗi người quan sát có kênh phản hồi riêng. (Một lựa chọn thay thế là sử dụng một kênh phản hồi duy nhất và sử dụng mã nhận dạng tương quan để xác định phản hồi nào đi đến người quan sát nào, nhưng việc có một kênh riêng cho mỗi người quan sát dễ triển khai hơn rất nhiều.)
Mô hình công bố - đăng ký sử dụng phương thức kéo

Một kênh phản hồi cho mỗi quan sát viên có thể dẫn đến một sự bùng nổ kênh. Số lượng kênh lớn như vậy có thể quản lý được, nhưng quản trị viên hệ thống nhắn tin không biết phải tạo bao nhiêu kênh tĩnh khi số lượng quan sát viên cần sử dụng những kênh này thay đổi động tại thời gian chạy. Ngay cả khi có đủ kênh cho tất cả các quan sát viên, làm thế nào mỗi quan sát viên biết kênh nào để sử dụng?
JMS có một tính năng, TemporaryQueue, đặc biệt cho mục đích này [Hapner]. (Cũng xem thảo luận về Request-Reply.) Một đối tượng quan sát có thể tạo một hàng đợi tạm thời chỉ dành cho việc sử dụng của riêng mình, chỉ định hàng đợi đó là Địa chỉ Trả về trong yêu cầu của nó và chờ đợi phản hồi trên hàng đợi đó. Việc tạo hàng đợi mới thường xuyên có thể không hiệu quả, tùy thuộc vào cách triển khai hệ thống nhắn tin của bạn, và hàng đợi tạm thời không thể bền vững (để sử dụng với Giao hàng Đảm bảo). Tuy nhiên, nếu bạn không muốn sử dụng mô hình đẩy, bạn có thể triển khai mô hình kéo bằng cách sử dụng hàng đợi tạm thời.
Hai lớp này cho thấy cách triển khai các cổng sử dụng mô hình kéo.
import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.NamingException; public class PullSubjectGateway { public static final String UPDATE_TOPIC_NAME = "jms/Update"; private PullSubject subject; private Connection connection; private Session session; private MessageProducer updateProducer; protected PullSubjectGateway() { super(); } public static PullSubjectGateway newGateway(PullSubject subject) throws JMSException, NamingException { PullSubjectGateway gateway = new PullSubjectGateway(); gateway.initialize(subject); return gateway; } protected void initialize(PullSubject subject) throws JMSException, NamingException { this.subject = subject; ConnectionFactory connectionFactory = JndiUtil.getQueueConnectionFactory(); connection = connectionFactory.createConnection(); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination updateTopic = JndiUtil.getDestination(UPDATE_TOPIC_NAME); updateProducer = session.createProducer(updateTopic); new Thread(new GetStateReplier()).start(); connection.start(); } public void notifyNoState() throws JMSException { TextMessage message = session.createTextMessage(); updateProducer.send(message); } public void release() throws JMSException { if (connection != null) { connection.stop(); connection.close(); } } private class GetStateReplier implements Runnable, MessageListener { public static final String GET_STATE_QUEUE_NAME = "jms/GetState"; private Session session; private MessageConsumer requestConsumer; public void run() { try { session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination getStateQueue = JndiUtil.getDestination(GET_STATE_QUEUE_NAME); requestConsumer = session.createConsumer(getStateQueue); requestConsumer.setMessageListener(this); } catch (Exception e) { e.printStackTrace(); } } public void onMessage(Message message) { try { Destination replyQueue = message.getJMSReplyTo(); MessageProducer replyProducer = session.createProducer(replyQueue); Message replyMessage = session.createTextMessage(subject.getState()); replyProducer.send(replyMessage); } catch (JMSException e) { e.printStackTrace(); } } } } PullSubjectGateway rất tương tự với SubjectGateway. Phiên bản pull hiện có một tham chiếu đến chủ đề của nó, vì vậy cổng có thể truy vấn chủ đề để lấy trạng thái của nó khi được yêu cầu bởi một người quan sát. notify(String) giờ đã trở thành notifyNoState(), vì mô hình pull đơn giản chỉ gửi thông báo mà không bao gồm bất kỳ trạng thái nào (và vì Java đã sử dụng tên phương thức notify()).
Bổ sung lớn cho mô hình kéo là GetStateReplier, một lớp nội bộ triển khai Runnable để có thể chạy trong chính luồng của nó. Nó cũng là một MessageListener, điều này làm cho nó trở thành một Người tiêu dùng theo sự kiện. Phương thức onMessage của nó đọc các yêu cầu từ hàng đợi GetState và gửi phản hồi chứa trạng thái của đối tượng đến hàng đợi được chỉ định bởi yêu cầu. Bằng cách này, khi một người quan sát thực hiện yêu cầu GetState(), cổng sẽ gửi một phản hồi (xem Request-Reply).
import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.QueueRequestor; import javax.jms.QueueSession; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.NamingException; public class PullObserverGateway implements MessageListener { public static final String UPDATE_TOPIC_NAME = "jms/Update"; public static final String GET_STATE_QUEUE_NAME = "jms/GetState"; private PullObserver observer; private QueueConnection connection; private QueueSession session; private MessageConsumer updateConsumer; private QueueRequestor getStateRequestor; protected PullObserverGateway() { super(); } public static PullObserverGateway newGateway(PullObserver observer) throws JMSException, NamingException { PullObserverGateway gateway = new PullObserverGateway(); gateway.initialize(observer); return gateway; } protected void initialize(PullObserver observer) throws JMSException, NamingException { this.observer = observer; QueueConnectionFactory connectionFactory = JndiUtil.getQueueConnectionFactory(); connection = connectionFactory.createQueueConnection(); session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Destination updateTopic = JndiUtil.getDestination(UPDATE_TOPIC_NAME); updateConsumer = session.createConsumer(updateTopic); updateConsumer.setMessageListener(this); Queue getStateQueue = (Queue) JndiUtil.getDestination(GET_STATE_QUEUE_NAME); getStateRequestor = new QueueRequestor(session, getStateQueue); } public void onMessage(Message message) { try { // message's contents are empty updateNoState(); } catch (JMSException e) { e.printStackTrace(); } } public void attach() throws JMSException { connection.start(); } public void detach() throws JMSException { if (connection != null) { connection.stop(); connection.close(); } } private void updateNoState() throws JMSException { TextMessage getStateRequestMessage = session.createTextMessage(); Message getStateReplyMessage = getStateRequestor.request(getStateRequestMessage); TextMessage textMsg = (TextMessage) getStateReplyMessage; // assume cast always works String newState = textMsg.getText(); observer.update(newState); } } Một lần nữa, PullObserverGateway tương tự như ObserverGateway nhưng có thêm một số mã để triển khai mô hình pull. Trong hàm khởi tạo, nó thiết lập không chỉ updateConsumer để lắng nghe các bản cập nhật mà còn getStateRequestor để gửi các yêu cầu GetState(). (getStateRequestor là một QueueRequestor; xem Request-Reply.) Trong phiên bản pull, mã onMessage của gateway bỏ qua nội dung của tin nhắn vì tin nhắn là rỗng. Sự tồn tại của tin nhắn cho thấy rằng đối tượng đã thay đổi, nhưng nó không cho biết trạng thái mới của đối tượng là gì. Do đó, tất cả những gì cần làm là gọi hàm updateNoState() (được đặt tên tương tự như notifyNoState()).
Sự khác biệt đối với người quan sát giữa mô hình đẩy và kéo trở nên rõ ràng trong việc triển khai updateNoState() so với update(String). Trong khi phiên bản đẩy nhận trạng thái mới như một tham số và chỉ cần cập nhật người quan sát, phiên bản kéo phải lấy trạng thái mới trước khi có thể cập nhật người quan sát. Để lấy trạng thái mới, nó sử dụng getStateRequestor để gửi một yêu cầu và nhận phản hồi. Phản hồi chứa trạng thái mới của đối tượng, mà cổng sử dụng để cập nhật người quan sát. (Lưu ý rằng trong triển khai đơn giản này, cổng là đơn luồng, vì vậy trong khi nó đang gửi yêu cầu lấy trạng thái và chờ phản hồi, nó không xử lý thêm bất kỳ cập nhật nào nữa. Do đó, nếu tin nhắn yêu cầu hoặc phản hồi mất nhiều thời gian để truyền tải, cổng sẽ bị kẹt trong khi chờ đợi, và mọi cập nhật khác xảy ra sẽ chỉ xếp hàng chờ.)
Như bạn có thể thấy, mô hình kéo phức tạp hơn mô hình đẩy. Nó yêu cầu nhiều kênh hơn (bao gồm một kênh tạm thời cho mỗi người quan sát) và nhiều thông điệp hơn (ba thông điệp cho mỗi cập nhật cho mỗi người quan sát có quan tâm thay vì một thông điệp cho tất cả người quan sát), các lớp chủ đề và người quan sát yêu cầu nhiều mã hơn để quản lý thông điệp bổ sung, và các đối tượng trong thời gian thực thi yêu cầu nhiều luồng hơn để thực hiện thông điệp bổ sung. Nếu tất cả điều này được chấp nhận trong ứng dụng của bạn, thì mô hình kéo là một phương pháp khả thi. Tuy nhiên, nếu có nghi ngờ, bạn có thể nên bắt đầu với mô hình đẩy vì nó đơn giản hơn.
Đến nay, chúng ta đã xem xét một chủ đề với một phần trạng thái thông báo cho các quan sát viên của nó. Sử dụng mô hình push, điều này yêu cầu một Kênh Xuất-Biểu để truyền đạt những thay đổi trong trạng thái của chủ đề đến các quan sát viên.
Các ứng dụng doanh nghiệp thực sự phức tạp hơn nhiều. Một ứng dụng có thể chứa nhiều đối tượng cần thông báo sự thay đổi. Mỗi đối tượng thường chứa nhiều phần trạng thái khác nhau, được gọi là khía cạnh, mà có thể thay đổi độc lập. Một người quan sát đơn lẻ có thể quan tâm đến nhiều khía cạnh khác nhau trong nhiều đối tượng khác nhau, trong đó các đối tượng không chỉ là nhiều thể hiện của cùng một lớp mà có thể là các thể hiện của các lớp khác nhau.
Vì vậy, nghĩa cập nhật trong các ứng dụng tinh vi có thể nhanh chóng trở nên phức tạp. Mẫu Observer giải quyết điều này với các vấn đề triển khai như "Quan sát nhiều hơn một đối tượng" và "Chỉ định rõ ràng các thay đổi quan tâm." Ngoài ra, mẫu SASE (Bì thư có dán tem tự địa chỉ) mô tả sự kết hợp của các mẫu Observer và Command, trong đó một observer chỉ định lệnh mà một đối tượng nên gửi cho nó khi một thay đổi nhất định xảy ra [Alpert].
Không đi sâu vào các vấn đề đảm bảo rằng những người quan sát chỉ nhận được các bản cập nhật mà họ cần, hãy xem xét các hệ quả cho việc nhắn tin, cụ thể là: Chúng ta sẽ cần bao nhiêu kênh?
Hãy xem xét trước một trường hợp đơn giản. Một doanh nghiệp có thể có nhiều ứng dụng khác nhau chịu trách nhiệm lưu trữ thông tin liên lạc của khách hàng, chẳng hạn như địa chỉ gửi thư. Khi địa chỉ của khách hàng được cập nhật trong một trong những ứng dụng này, ứng dụng đó nên thông báo cho các ứng dụng khác có thể cần thông tin mới này. Trong khi đó, có thể có nhiều ứng dụng cần biết khi nào địa chỉ thay đổi, vì vậy họ muốn đăng ký để nhận thông báo.
Đây là một vấn đề đơn giản để giải quyết. Tất cả những gì cần thiết là một Kênh Công Bố-Đăng Ký duy nhất để thông báo sự thay đổi địa chỉ. Mỗi ứng dụng có thể thay đổi địa chỉ cũng có trách nhiệm thông báo sự thay đổi đó bằng cách công bố một tin nhắn trên kênh. Mỗi ứng dụng muốn nhận thông báo đăng ký kênh. Một tin nhắn thay đổi cụ thể có thể trông như thế này.
<AddressChange customer_id="12345"> <OldAddress> <Street>123 Wall Street</Street> <City>New York</City> <State>NY</State> <Zip>10005</Zip> </OldAddress> <NewAddress> <Street>321 Sunset Blvd</Street> <City>Los Angeles</City> <State>CA</State> <Zip>90012</Zip> </NewAddress> </AddressChange>
Bây giờ hãy xem xét một vấn đề khác. Doanh nghiệp cũng có thể có những ứng dụng cần thông báo khi họ hết sản phẩm và những ứng dụng khác cần nhận những thông báo này để có thể đặt hàng lại sản phẩm. Đây chỉ là một ví dụ khác của vấn đề trước, và nó được giải quyết theo cách tương tự bằng cách sử dụng Kênh Xuất-Biến để thực hiện các thông báo hết hàng. Một trong những tin nhắn này có thể trông như thế này.
<OutOfProduct> <ProductID>12345</ProductID> <StoreID>67890</StoreID> <QuantityRequested>100</QuantityRequested> </OutOfProduct>
Nhưng điều này khiến chúng ta đặt câu hỏi: Liệu chúng ta có thể sử dụng cùng một kênh cho việc thay đổi địa chỉ khách hàng và cho các thông báo hết sản phẩm không? Có lẽ không. Đầu tiên, Kênh Loại Dữ liệu cho chúng ta biết rằng tất cả các thông điệp trên một kênh phải cùng loại, điều này có nghĩa là chúng phải tuân theo cùng một sơ đồ XML. <AddressChange> rõ ràng là một loại yếu tố rất khác với <OutOfProduct>, vì vậy chúng không nên được gửi trên cùng một kênh. Có lẽ các định dạng dữ liệu có thể được làm lại để cả hai loại thông điệp đều phù hợp với cùng một sơ đồ, và sau đó người nhận có thể phân biệt được thông điệp nào là về địa chỉ và thông điệp nào là về sản phẩm. Nhưng vấn đề là ứng dụng quan tâm đến việc thay đổi địa chỉ có thể không phải là những ứng dụng quan tâm đến cập nhật sản phẩm, vì vậy nếu các thông điệp sử dụng cùng một kênh, một ứng dụng sẽ thường xuyên nhận được các thông báo mà nó không quan tâm. Do đó, hợp lý khi có hai kênh tách biệt cho việc thay đổi địa chỉ và cập nhật sản phẩm.
Bây giờ, hãy xem xét một trường hợp thứ ba nơi xếp hạng tín dụng của một khách hàng có thể thay đổi. Tin nhắn có thể trông như thế này:
<CreditRatingChange customer_id="12345"> <OldRating>AAA</OldRating> <NewRating>BBB</NewRating> </CreditRatingChange>
Giống như trường hợp với thông báo sản phẩm, có thể sẽ thật hấp dẫn khi giải quyết vấn đề này bằng một kênh thay đổi xếp hạng tín dụng mới (bên cạnh các kênh thay đổi địa chỉ và kênh hết sản phẩm). Điều này sẽ giữ cho việc thay đổi xếp hạng tín dụng tách biệt khỏi việc thay đổi địa chỉ và cho phép những người phụ thuộc chỉ đăng ký cho loại thay đổi mà họ quan tâm.
Vấn đề với cách tiếp cận này là nó có thể dẫn đến việc bùng nổ kênh. Hãy xem xét tất cả các phần dữ liệu có thể được biết về một khách hàng: tên; thông tin liên lạc (địa chỉ, số điện thoại, email) cho việc gửi thư, giao hàng và thanh toán; xếp hạng tín dụng; mức độ dịch vụ; chiết khấu tiêu chuẩn; và nhiều điều khác. Mỗi khi bất kỳ một trong những khía cạnh này thay đổi, các ứng dụng khác có thể cần biết về điều đó. Việc tạo ra một kênh cho mỗi khía cạnh có thể dẫn đến việc có rất nhiều kênh.
Số lượng lớn các kênh có thể gây áp lực cho hệ thống nhắn tin. Nhiều kênh với ít lưu lượng truy cập trên mỗi kênh có thể lãng phí tài nguyên và làm cho việc phân phối tải trở nên khó khăn. Nhiều kênh với nhiều tin nhắn nhỏ có thể gia tăng chi phí nhắn tin. Những đối tượng phụ thuộc có thể trở nên bối rối về việc nên đăng ký kênh nào trong số một số lượng lớn các kênh. Nhiều kênh yêu cầu nhiều người gửi và người nhận, có thể dẫn đến việc có rất nhiều luồng kiểm tra rất nhiều kênh thường xuyên rỗng. Vì vậy, việc tạo thêm nhiều kênh có thể không phải là một ý tưởng tốt.
Điều có thể hiệu quả hơn là gửi cả hai thông điệp thay đổi địa chỉ và thay đổi xếp hạng tín dụng trên cùng một kênh, vì chúng đều liên quan đến sự thay đổi của khách hàng và một ứng dụng quan tâm đến một loại thay đổi có thể cũng quan tâm đến những thay đổi khác. Tuy nhiên, một kênh ngoài sản phẩm riêng biệt vẫn là một ý tưởng tốt, vì các ứng dụng quan tâm đến khách hàng có thể không quan tâm đến sản phẩm, và ngược lại.
Các thông điệp thay đổi địa chỉ và thay đổi tín dụng có định dạng khác nhau, nhưng Kênh Dữ liệu cho chúng ta biết rằng để nằm trên cùng một kênh, các thông điệp phải có cùng một định dạng. Với XML, điều này có nghĩa là tất cả các thông điệp phải có cùng một loại phần tử gốc nhưng có thể có các phần tử lồng ghép tùy chọn khác nhau. Vì vậy, các thông điệp thay đổi khách hàng thống nhất có thể trông như thế này:
<CustomerChange customer_id="12345"> <AddressChange> <OldAddress> <Street>123 Wall Street</Street> <City>New York</City> <State>NY</State> <Zip>10005</Zip> </OldAddress> <NewAddress> <Street>321 Sunset Blvd</Street> <City>Los Angeles</City> <State>CA</State> <Zip>90012</Zip> </NewAddress> </AddressChange> </CustomerChange> <CustomerChange customer_id="12345"> <CreditRatingChange> <OldRating>AAA</OldRating> <NewRating>BBB</NewRating> </CreditRatingChange> </CustomerChange>
Có thể vẫn còn vấn đề là các ứng dụng liên quan đến việc thay đổi địa chỉ không quan tâm đến những thay đổi về xếp hạng tín dụng, và các ứng dụng thanh toán lại quan tâm đến điều ngược lại. Những ứng dụng này có thể sử dụng Người tiêu dùng Chọn lọc để chỉ nhận những thông điệp quan tâm. Nếu người tiêu dùng chọn lọc chứng tỏ phức tạp và một hệ thống nhắn tin có thể dễ dàng hỗ trợ nhiều kênh hơn, thì có lẽ các kênh riêng biệt sẽ tốt hơn.
Như với nhiều vấn đề trong kiến trúc và thiết kế doanh nghiệp, không có câu trả lời đơn giản và có nhiều sự đánh đổi. Với Kênh Xuất Bản-Đăng Ký, cũng như với bất kỳ kênh tin nhắn nào, mục tiêu là đảm bảo rằng những người quan sát chỉ nhận được các thông báo mà họ cần, mà không làm phát sinh quá nhiều kênh riêng lẻ và không làm cho người quan sát điển hình bị quá tải với nhiều luồng chạy nhiều người tiêu dùng theo dõi nhiều kênh.
Ví dụ này cho thấy rằng Kênh Publish-Subscribe là một triển khai của mẫu Observer giúp cho mẫu này dễ sử dụng hơn trong các môi trường phân tán. Khi một kênh được sử dụng, Subject.Notify() và Observer.Update() trở nên đơn giản hơn rất nhiều vì tất cả những gì chúng cần làm chỉ là gửi và nhận tin nhắn. Hệ thống nhắn tin quản lý việc phân phối và đồng thời giúp việc thông báo từ xa trở nên đáng tin cậy hơn. Mô hình push đơn giản hơn và thường hiệu quả hơn mô hình pull, đặc biệt cho thông báo phân tán và với nhắn tin. Tuy nhiên, mô hình pull cũng có thể được triển khai bằng cách sử dụng nhắn tin. Trong các ứng dụng phức tạp mà nhiều dữ liệu có thể thay đổi, có thể bạn sẽ có xu hướng tạo một kênh cho mỗi điều khác nhau có thể thay đổi, nhưng thường thực tiễn hơn là sử dụng cùng một kênh để truyền tải thông báo tương tự đến cùng một người quan sát. Ngay cả khi các ứng dụng của bạn không cần nhắn tin cho bất kỳ thứ gì khác, nếu chúng cần thông báo cho nhau về các thay đổi, thì việc sử dụng Nhắn tin để tận dụng Kênh Publish-Subscribe vẫn có thể là điều xứng đáng.
Giới thiệu
Bộ định tuyến dựa trên nội dung
Bộ lọc tin nhắn
Bộ điều hướng động
Danh sách người nhận
Bộ chia
Tổng hợp
Resequencer in Vietnamese is "Tái sắp xếp".
Bộ xử lý tin nhắn hợp thành
Rải-Ráp
Giấy ghi lô hàng
Quản lý quy trình
"Môi giới tin nhắn"
Trong Chương 3, "Hệ thống Nhắn tin," chúng ta đã thảo luận về cách một Bộ định tuyến Thông điệp có thể được sử dụng để tách rời nguồn thông điệp khỏi điểm đến cuối cùng của thông điệp. Chương này làm rõ thêm về các loại Bộ định tuyến Thông điệp cụ thể để giải thích cách cung cấp khả năng định tuyến và môi giới cho một giải pháp tích hợp. Hầu hết các mẫu là sự tinh chỉnh của mẫu Bộ định tuyến Thông điệp, trong khi những mẫu khác kết hợp nhiều Bộ định tuyến Thông điệp để giải quyết các vấn đề phức tạp hơn. Do đó, chúng ta có thể phân loại các mẫu định tuyến thông điệp thành các nhóm sau:
Router đơn giản là các biến thể của Router Tin nhắn và định tuyến tin nhắn từ một kênh vào đến một hoặc nhiều kênh ra.
Các bộ định tuyến hợp thành kết hợp nhiều bộ định tuyến đơn giản để tạo ra các luồng tin nhắn phức tạp hơn.
Mô hình Kiến trúc mô tả các phong cách kiến trúc dựa trên Bộ định tuyến Tin nhắn.
Bộ định tuyến dựa trên nội dung kiểm tra nội dung của một thông điệp và định tuyến nó đến một kênh khác dựa trên nội dung của thông điệp. Việc sử dụng một bộ định tuyến như vậy cho phép nhà sản xuất thông điệp gửi thông điệp đến một kênh duy nhất và để bộ định tuyến dựa trên nội dung định tuyến chúng đến đích thích hợp. Điều này giúp giảm bớt công việc của ứng dụng gửi và tránh việc liên kết nhà sản xuất thông điệp với các kênh đích cụ thể.
Bộ lọc tin nhắn là một hình thức đặc biệt của Bộ định tuyến dựa trên nội dung. Nó kiểm tra nội dung tin nhắn và chuyển tin nhắn đến một kênh khác chỉ khi nội dung tin nhắn khớp với các tiêu chí nhất định. Nếu không, nó sẽ loại bỏ tin nhắn đó. Bộ lọc tin nhắn thực hiện một chức năng rất giống với một Người tiêu dùng phân chọn, với sự khác biệt chính là Bộ lọc tin nhắn là một phần của hệ thống nhắn tin, định tuyến các tin nhắn phù hợp đến một kênh khác, trong khi đó Người tiêu dùng phân chọn được tích hợp vào Điểm cuối Tin nhắn.
Một Bộ Chỉ Đạo Dựa Trên Nội Dung và một Bộ Lọc Thông Điệp thực sự có thể giải quyết một vấn đề tương tự. Một Bộ Chỉ Đạo Dựa Trên Nội Dung chuyển tiếp một thông điệp đến đích chính xác dựa trên tiêu chí được mã hóa trong Bộ Chỉ Đạo Dựa Trên Nội Dung. Hành vi tương đương có thể đạt được bằng cách sử dụng một Kênh Công Bố-Đăng Ký và một mảng Bộ Lọc Thông Điệp, mỗi bộ cho từng người nhận tiềm năng. Mỗi Bộ Lọc Thông Điệp loại bỏ những thông điệp không phù hợp với tiêu chí cho đích cụ thể. Bộ Chỉ Đạo Dựa Trên Nội Dung chuyển tiếp theo cách dự đoán đến một kênh đơn lẻ và do đó có quyền kiểm soát tổng thể, nhưng cũng phụ thuộc vào danh sách tất cả các kênh đích có thể. Ngược lại, mảng Bộ Lọc Thông Điệp lọc theo cách phản ứng, phân bổ logic chuyển tiếp trên nhiều Bộ Lọc Thông Điệp nhưng tránh được một thành phần duy nhất phụ thuộc vào tất cả các đích có thể. Sự đánh đổi giữa các giải pháp này được mô tả chi tiết hơn trong mẫu Bộ Lọc Thông Điệp.
Một Bộ Định Tuyến Tin Nhắn cơ bản sử dụng các quy tắc cố định để xác định đích đến của một tin nhắn đến. Khi cần nhiều tính linh hoạt hơn, một Bộ Định Tuyến Động có thể rất hữu ích. Bộ định tuyến này cho phép logic định tuyến được chỉnh sửa bằng cách gửi các tin nhắn điều khiển đến một cổng điều khiển chỉ định. Tính chất động của Bộ Định Tuyến Động có thể được kết hợp với hầu hết các dạng của Bộ Định Tuyến Tin Nhắn.
Chương 4, "Các Kênh Gửi Thông Điệp," đã giới thiệu các khái niệm Kênh Điểm-đến-Điểm và Kênh Xuất-bản-Dăng Ký. Đôi khi, bạn cần gửi một thông điệp đến nhiều người nhận nhưng vẫn muốn kiểm soát các người nhận đó. Danh sách Người Nhận cho phép bạn làm điều đó. Về bản chất, Danh sách Người Nhận là một Bộ Định Tuyến Dựa Trên Nội Dung có thể định tuyến một thông điệp đơn đến nhiều kênh đích khác nhau.
Một số thông điệp chứa danh sách các mục riêng lẻ. Bạn xử lý các mục này như thế nào? Sử dụng một Bộ tách để chia thông điệp lớn thành các thông điệp riêng lẻ. Mỗi thông điệp sau đó có thể được định tuyến tiếp và xử lý một cách riêng lẻ.
Tuy nhiên, bạn có thể cần kết hợp lại các thông điệp mà bộ phân tách đã tạo thành một thông điệp duy nhất. Đây là một trong những chức năng mà bộ tổng hợp thực hiện. Một bộ tổng hợp có thể nhận một chuỗi thông điệp, xác định các thông điệp liên quan và kết hợp chúng thành một thông điệp duy nhất. Khác với các mẫu định tuyến khác, bộ tổng hợp là một Bộ Phân Phối Thông Điệp có trạng thái vì nó phải lưu trữ các thông điệp bên trong cho đến khi các điều kiện cụ thể được thỏa mãn. Điều này có nghĩa là bộ tổng hợp có thể tiêu thụ nhiều thông điệp trước khi nó công bố một thông điệp.
Bởi vì chúng tôi sử dụng nhắn tin để kết nối các ứng dụng hoặc thành phần chạy trên nhiều máy tính, nhiều thông điệp có thể được xử lý song song. Ví dụ, hơn một quy trình có thể tiêu thụ thông điệp từ một kênh duy nhất. Một trong những quy trình này có thể thực thi nhanh hơn quy trình khác, khiến cho các thông điệp bị xử lý không theo thứ tự. Tuy nhiên, một số thành phần - ví dụ, các hệ thống dựa trên sổ cái - phụ thuộc vào thứ tự chính xác của từng thông điệp. Bộ xếp lại đưa các thông điệp không theo thứ tự quay trở lại thứ tự. Bộ xếp lại cũng là một Bộ định tuyến Thông điệp có trạng thái vì nó có thể cần lưu trữ một số thông điệp bên trong cho đến khi thông điệp hoàn thành trình tự đến. Tuy nhiên, khác với Bộ tổng hợp, Bộ xếp lại cuối cùng phát hành số lượng thông điệp giống như nó đã tiêu thụ.
Bảng dưới đây tóm tắt các thuộc tính của các biến thể Bộ định tuyến Tin nhắn (chúng tôi không đưa Bộ định tuyến Năng động như là một phương án riêng biệt vì bất kỳ bộ định tuyến nào cũng có thể được triển khai dưới dạng biến thể năng động):
Mẫu | Số lượng tin nhắn đã tiêu thụ | Số Lượng Tin Nhắn Được Xuất Bản | Có trạng thái? | Bình luận |
|---|---|---|---|---|
Bộ định tuyến dựa trên nội dung | 1 | 1 | Không (chủ yếu là không) | |
Bộ lọc | 1 | 0 hoặc 1 | Không (chủ yếu) | |
Danh sách người nhận | 1 | nhiều (bao gồm 0) | Không | |
Bộ điều phối | 1 | đa dạng | Không | |
Tổng hợp viên | đã nhiều | 1 | Có | |
Resequencer in Vietnamese is "Tái sắp xếp". | nhiều | nhiều | Có | Công bố số lượng bằng với số lượng tiêu thụ |
Một lợi thế chính của kiến trúc Pipes and Filters là chúng ta có thể kết hợp nhiều bộ lọc thành một giải pháp lớn hơn. Bộ xử lý tin nhắn phối hợp và Scatter-Gather kết hợp nhiều biến thể Bộ định tuyến tin nhắn để tạo ra các giải pháp toàn diện hơn. Cả hai mẫu này cho phép chúng ta lấy thông tin từ nhiều nguồn và kết hợp lại thành một tin nhắn duy nhất. Bộ xử lý tin nhắn phối hợp chia một tin nhắn duy nhất thành nhiều phần, trong khi Scatter-Gather gửi một bản sao của cùng một tin nhắn đến nhiều người nhận.
Cả Bộ Xử Lý Tin Nhắn Tổ Chức và Scatter-Gather đều hướng một tin nhắn tới nhiều người tham gia đồng thời và tái hợp các phản hồi thành một tin nhắn duy nhất. Chúng ta có thể nói rằng những mẫu này quản lý việc định tuyến song song của một tin nhắn. Hai mẫu bổ sung quản lý việc định tuyến tuần tự của một tin nhắn, tức là, hướng một tin nhắn qua một chuỗi các bước riêng lẻ. Nếu chúng ta muốn kiểm soát đường đi của một tin nhắn từ một điểm trung tâm, chúng ta có thể sử dụng một Giấy Tờ Định Tuyến để chỉ định con đường mà tin nhắn nên đi. Mẫu này hoạt động giống như giấy tờ định tuyến gắn liền với các tài liệu văn phòng để chuyển chúng theo thứ tự cho một số người nhận. Ngoài ra, chúng ta có thể sử dụng Quản Lý Quy Trình, cho phép chúng ta linh hoạt hơn nhưng yêu cầu tin nhắn quay lại một thành phần trung tâm sau mỗi chức năng.
Các Bộ định tuyến Tin nhắn cho phép chúng ta xây dựng một giải pháp tích hợp sử dụng một Trung tâm Tin nhắn trung tâm. Khác với các mẫu thiết kế định tuyến tin nhắn khác nhau, mẫu này mô tả một phong cách kiến trúc trung tâm và xung quanh.
Chương này chứa 12 mẫu. Làm thế nào chúng ta có thể tạo điều kiện dễ dàng để tìm kiếm mẫu phù hợp cho mục đích đúng? Biểu đồ quyết định sau đây giúp bạn tìm mẫu phù hợp cho mục đích đúng thông qua các quyết định đơn giản có hoặc không. Ví dụ, nếu bạn đang tìm kiếm một mẫu định tuyến đơn giản mà chỉ tiêu thụ một thông điệp tại một thời điểm nhưng xuất bản nhiều thông điệp theo thứ tự tuần tự, bạn nên sử dụng Splitter. Biểu đồ cũng giúp minh họa mức độ liên quan giữa các mẫu cá nhân. Ví dụ, Routing Slip và Process Manager giải quyết các vấn đề tương tự, trong khi Message Filter làm một điều gì đó khá khác biệt.

Giả sử rằng chúng ta đang xây dựng một hệ thống xử lý đơn hàng. Khi một đơn hàng đến được nhận, chúng ta trước tiên sẽ xác thực đơn hàng và sau đó xác minh rằng mặt hàng được đặt hàng có sẵn trong kho. Chức năng này được thực hiện bởi hệ thống kho. Chuỗi các bước xử lý này là một ứng cử viên hoàn hảo cho kiểu Pipes and Filters. Chúng ta tạo ra hai bộ lọc, một cho bước xác thực và một cho hệ thống kho, và định tuyến các thông điệp đến qua cả hai bộ lọc. Tuy nhiên, trong nhiều kịch bản tích hợp doanh nghiệp, có hơn một hệ thống kho tồn tại, và mỗi hệ thống chỉ có thể xử lý các mặt hàng cụ thể.
| Chúng ta xử lý tình huống nào khi việc triển khai một chức năng logic đơn lẻ được phân tán trên nhiều hệ thống vật lý? |
Các giải pháp tích hợp kết nối các ứng dụng hiện có để chúng hoạt động cùng nhau. Bởi vì nhiều ứng dụng này được phát triển mà không nghĩ đến việc tích hợp, nên các giải pháp tích hợp hiếm khi tìm thấy một kịch bản lý tưởng nơi mà một chức năng kinh doanh được bao gói tốt bên trong một hệ thống duy nhất. Ví dụ, việc mua lại hoặc hợp tác kinh doanh thường dẫn đến nhiều hệ thống thực hiện cùng một chức năng kinh doanh. Ngoài ra, nhiều doanh nghiệp hoạt động như những đơn vị tổng hợp hoặc bán lẻ thường giao tiếp với nhiều hệ thống thực hiện cùng một chức năng (ví dụ: kiểm tra hàng tồn kho, đặt hàng). Để làm cho mọi việc trở nên phức tạp hơn, các hệ thống này có thể được vận hành trong công ty hoặc có thể dưới sự kiểm soát của các đối tác hoặc chi nhánh kinh doanh. Ví dụ, các nhà bán lẻ lớn như Amazon cho phép bạn đặt hàng bất cứ thứ gì từ sách đến cưa xích đến quần áo. Tùy thuộc vào loại mặt hàng, đơn hàng có thể được xử lý bởi các hệ thống xử lý đơn hàng của các thương gia "ở phía sau" khác nhau.
Giả sử rằng công ty đang bán các sản phẩm và thiết bị và có hai hệ thống quản lý kho: một cho sản phẩm và một cho thiết bị. Giả sử rằng mỗi mặt hàng được xác định bằng một số hiệu duy nhất. Khi công ty nhận được đơn hàng, họ cần quyết định hệ thống quản lý kho nào sẽ nhận đơn hàng dựa trên loại mặt hàng được đặt. Chúng ta có thể tạo các kênh tách biệt cho các đơn hàng đến dựa trên loại mặt hàng được đặt. Tuy nhiên, điều này sẽ yêu cầu khách hàng phải biết kiến trúc hệ thống nội bộ của chúng tôi, trong khi thực tế họ có thể không nhận ra rằng chúng tôi phân biệt giữa sản phẩm và thiết bị. Do đó, chúng tôi nên giấu đi thực tế rằng việc triển khai chức năng kinh doanh được phân tán trên nhiều hệ thống khỏi phần còn lại của giải pháp tích hợp, bao gồm cả khách hàng. Vì vậy, chúng tôi phải mong đợi rằng các tin nhắn cho các mặt hàng khác nhau sẽ đến trên cùng một kênh.
Chúng tôi có thể chuyển tiếp đơn hàng đến tất cả các hệ thống tồn kho (sử dụng Kênh Xuất-Biến), và để mỗi hệ thống quyết định xem nó có thể xử lý đơn hàng hay không. Cách tiếp cận này giúp việc thêm các hệ thống tồn kho mới trở nên dễ dàng vì chúng tôi không phải thay đổi bất kỳ thành phần nào hiện có khi có một hệ thống tồn kho mới ra mắt. Tuy nhiên, cách tiếp cận này giả định việc phối hợp phân tán qua nhiều hệ thống. Điều gì sẽ xảy ra nếu đơn hàng không thể được xử lý bởi bất kỳ hệ thống nào? Hoặc nếu có nhiều hệ thống có thể xử lý đơn hàng? Liệu khách hàng có nhận được các lô hàng trùng lặp không? Ngoài ra, trong nhiều trường hợp, một hệ thống tồn kho sẽ coi đơn hàng cho một mặt hàng mà nó không thể xử lý như một lỗi. Nếu đúng như vậy, mỗi đơn hàng sẽ gây ra lỗi ở tất cả các hệ thống tồn kho ngoại trừ một cái. Sẽ thật khó để phân biệt những lỗi này với các lỗi "thực sự", chẳng hạn như một đơn hàng không hợp lệ.
Một cách tiếp cận thay thế là sử dụng số hiệu của mặt hàng như một địa chỉ kênh. Mỗi mặt hàng sẽ có kênh riêng của nó, và khách hàng có thể đơn giản gửi đơn hàng tới kênh tương ứng với số hiệu của mặt hàng mà không cần phải biết về bất kỳ sự phân biệt nào giữa thiết bị và dụng cụ. Các hệ thống quản lý kho có thể lắng nghe tất cả các kênh cho những mặt hàng mà nó có thể xử lý. Cách tiếp cận này tận dụng khả năng địa chỉ kênh để hướng tin nhắn đến hệ thống quản lý kho chính xác. Tuy nhiên, một số lượng lớn các mặt hàng có thể nhanh chóng dẫn đến sự bùng nổ về số lượng kênh, làm cho hệ thống bị vướng bận với chi phí hoạt động và quản lý. Việc tạo ra các kênh mới cho mỗi mặt hàng được cung cấp sẽ nhanh chóng dẫn đến sự hỗn loạn.
Chúng ta cũng nên cố gắng giảm thiểu lưu lượng tin nhắn. Ví dụ, chúng ta có thể định tuyến thông điệp đơn hàng qua từng hệ thống kho một. Hệ thống đầu tiên có thể chấp nhận đơn hàng sẽ tiêu thụ thông điệp và xử lý đơn hàng. Nếu nó không thể xử lý đơn hàng, nó sẽ chuyển thông điệp đơn hàng cho hệ thống tiếp theo. Cách tiếp cận này loại bỏ nguy cơ các đơn hàng được chấp nhận bởi nhiều hệ thống đồng thời. Ngoài ra, chúng ta biết rằng đơn hàng đã không được xử lý bởi bất kỳ hệ thống nào nếu hệ thống cuối cùng trả lại nó. Tuy nhiên, giải pháp này yêu cầu các hệ thống phải biết đủ về nhau để chuyển thông điệp từ hệ thống này sang hệ thống khác. Cách tiếp cận này tương tự như mẫu Chain of Responsibility [GoF]. Tuy nhiên, trong thế giới hội nhập dựa trên thông điệp, việc truyền thông điệp qua chuỗi hệ thống có thể gây ra khả năng tiêu tốn tài nguyên đáng kể. Ngoài ra, cách tiếp cận này sẽ yêu cầu sự hợp tác của các hệ thống cá nhân, điều này có thể không khả thi nếu một số hệ thống được duy trì bởi các đối tác kinh doanh bên ngoài và do đó không nằm trong tầm kiểm soát của chúng ta.
Tóm lại, chúng ta cần một giải pháp tổng hợp thực tế rằng chức năng kinh doanh được phân tán trên các hệ thống, sử dụng hiệu quả các kênh tin nhắn và lưu lượng tin nhắn, và đảm bảo rằng đơn hàng được xử lý bởi đúng một hệ thống tồn kho.
| Sử dụng một Router Dựa trên Nội dung để định tuyến mỗi tin nhắn đến người nhận đúng dựa trên nội dung của tin nhắn.
|
Bộ định tuyến dựa trên nội dung kiểm tra nội dung của thông điệp và định tuyến thông điệp sang một kênh khác dựa trên dữ liệu có trong thông điệp. Việc định tuyến có thể dựa trên một số tiêu chí, chẳng hạn như sự tồn tại của các trường, giá trị trường cụ thể, và nhiều hơn nữa. Khi triển khai bộ định tuyến dựa trên nội dung, cần đặc biệt thận trọng để đảm bảo chức năng định tuyến dễ bảo trì, vì bộ định tuyến có thể trở thành một điểm cần bảo trì thường xuyên. Trong các kịch bản tích hợp phức tạp hơn, bộ định tuyến dựa trên nội dung có thể trở thành một công cụ quy tắc cấu hình cho phép tính toán kênh đích dựa trên một tập hợp các quy tắc có thể cấu hình.
Bộ định tuyến dựa trên nội dung là một hình thức thường được sử dụng của bộ định tuyến tin nhắn tổng quát hơn. Nó sử dụng định tuyến dự đoán, nghĩa là nó kết hợp kiến thức về khả năng của tất cả các hệ thống khác. Điều này giúp định tuyến hiệu quả vì mỗi tin nhắn đi ra đều được gửi trực tiếp đến hệ thống đúng. Nhược điểm là bộ định tuyến dựa trên nội dung phải có kiến thức về tất cả các người nhận có thể và khả năng của họ. Khi các người nhận được thêm vào, gỡ bỏ hoặc thay đổi, bộ định tuyến dựa trên nội dung phải được thay đổi mỗi lần. Điều này có thể trở thành một cơn ác mộng trong việc bảo trì.
Chúng ta có thể tránh sự phụ thuộc của Bộ định tuyến dựa trên nội dung vào các người nhận cá nhân nếu các người nhận có thể kiểm soát nhiều hơn quá trình định tuyến. Những tùy chọn này có thể được tóm tắt là lọc phản ứng vì chúng cho phép mỗi người tham gia lọc các thông điệp liên quan khi chúng đến. Việc phân phối kiểm soát định tuyến loại bỏ nhu cầu về một Bộ định tuyến dựa trên nội dung, nhưng giải pháp này thường kém hiệu quả hơn. Những giải pháp này và các sự đánh đổi liên quan được mô tả chi tiết hơn trong Bộ lọc thông điệp và Giấy định tuyến.
Router Động mô tả một sự thỏa hiệp giữa Router Dựa trên Nội dung và phương pháp lọc phản ứng bằng cách yêu cầu mỗi người nhận thông báo cho Router Dựa trên Nội dung về khả năng của mình. Router Dựa trên Nội dung duy trì một danh sách về khả năng của từng người nhận và định tuyến các tin nhắn đến phù hợp. Giá phải trả cho sự linh hoạt này là độ phức tạp của giải pháp và khó khăn trong việc gỡ lỗi hệ thống như vậy so với một Router Dựa trên Nội dung đơn giản.
| Ví dụ: Bộ định tuyến dựa trên nội dung với C# và MSMQ Ví dụ mã này minh họa một Bộ định tuyến Dựa trên Nội dung rất đơn giản, định tuyến các thông điệp dựa trên ký tự đầu tiên trong nội dung thông điệp. Nếu văn bản nội dung bắt đầu bằng W, bộ định tuyến sẽ định tuyến thông điệp đến hàng đợi widgetQueue; nếu bắt đầu bằng G, nó sẽ được gửi đến hàng đợi gadgetQueue. Nếu không thuộc cả hai, bộ định tuyến sẽ gửi nó đến hàng đợi dunnoQueue. Hàng đợi này thực ra là một ví dụ của Kênh Thông điệp Không hợp lệ. Bộ định tuyến này không có trạng thái, tức là, nó không "nhớ" bất kỳ thông điệp trước đó nào khi đưa ra quyết định định tuyến. [View full width] class ContentBasedRouter { protected MessageQueue inQueue; protected MessageQueue widgetQueue; protected MessageQueue gadgetQueue; protected MessageQueue dunnoQueue; public ContentBasedRouter(MessageQueue inQueue, MessageQueue Ví dụ sử dụng một trình tiêu thụ tin nhắn dựa trên sự kiện bằng cách đăng ký phương thức OnMessage làm trình xử lý cho các tin nhắn đến trong inQueue. Điều này khiến cho .NET Framework gọi phương thức OnMessage cho mỗi tin nhắn đến trong inQueue. Thuộc tính Formatter của hàng đợi tin nhắn cho framework biết loại tin nhắn nào mong đợi; trong ví dụ của chúng tôi, chúng tôi chỉ xử lý các tin nhắn dạng chuỗi đơn giản. OnMessage xác định nơi để định tuyến tin nhắn và thông báo cho .NET rằng nó đã sẵn sàng cho tin nhắn tiếp theo bằng cách gọi phương thức BeginReceive trên hàng đợi. Để giữ cho mã nguồn ở mức tối thiểu, router đơn giản này không phải là giao dịch: Nếu router gặp sự cố sau khi tiêu thụ một tin nhắn từ kênh đầu vào và trước khi phát hành nó sang kênh đầu ra, chúng tôi sẽ mất một tin nhắn. Các chương sau sẽ giải thích cách làm cho các điểm cuối trở thành giao dịch (xem Khách hàng Giao dịch). |
| Ví dụ: TIBCO MessageBroker Việc định tuyến tin nhắn là một nhu cầu phổ biến đến nỗi hầu hết các bộ công cụ EAI đều cung cấp các công cụ tích hợp sẵn để đơn giản hóa việc xây dựng logic định tuyến. Ví dụ, trong ví dụ C#, chúng ta đã phải lập trình logic để đọc một tin nhắn từ hàng đợi đến, giải mã nó, phân tích nó và công bố lại nó đến kênh đầu ra đúng. Trong nhiều công cụ EAI, loại logic này có thể được triển khai bằng các thao tác kéo và thả đơn giản thay vì phải viết mã. Mã duy nhất cần viết là logic quyết định thực sự cho Bộ định tuyến dựa trên nội dung. Một công cụ EAI như vậy thực hiện định tuyến tin nhắn là bộ TIBCO ActiveEnterprise. Bộ này bao gồm TIB/MessageBroker, được thiết kế để tạo ra các luồng tin nhắn đơn giản bao gồm các chức năng biến đổi và định tuyến. Bộ định tuyến widget giống như định tuyến các tin nhắn đến dựa trên chữ cái đầu tiên của số mặt hàng trông như thế này khi được triển khai trong TIB/MessageBroker:
Chúng ta có thể đọc luồng tin nhắn từ trái sang phải. Thành phần ở bên trái (được biểu thị bằng một tam giác chỉ sang bên phải) là thành phần đăng ký mà tiêu thụ các tin nhắn từ router kênh. Tên kênh được chỉ định trong một ô thuộc tính không hiển thị trong hình này. Nội dung tin nhắn được hướng tới nhà phát hành tin nhắn (được biểu thị bằng tam giác ở bên phải màn hình). Đường thẳng từ đầu ra Dữ liệu của thành phần đăng ký đến đầu vào Tin nhắn của nhà phát hành thể hiện thực tế rằng một Bộ định tuyến Dựa trên Nội dung không sửa đổi nội dung tin nhắn. Để xác định kênh đầu ra chính xác, hàm ComputeSubject (ở giữa) phân tích nội dung tin nhắn. Hàm này sử dụng một cái gọi là từ điển (được đánh dấu là "Bảng" trong hình) như một bảng dịch giữa nội dung tin nhắn và tên kênh đích. Từ điển được cấu hình với các giá trị sau:
Chức năng ComputeSubject sử dụng chữ cái đầu tiên của số hiệu mặt hàng trong tin nhắn đến để tra cứu kênh đích từ từ điển. Để tạo thành tên đầy đủ của kênh đầu ra, nó thêm kết quả từ điển vào chuỗi router.out, tạo thành một tên kênh như router.out.widget. Kết quả của phép toán này được truyền đến thành phần nhà xuất bản ở bên phải để được sử dụng làm tên của kênh. Do đó, bất kỳ mặt hàng nào có số hiệu mặt hàng bắt đầu bằng G sẽ được định tuyến đến kênh router.out.gadget, trong khi bất kỳ mặt hàng nào có số hiệu mặt hàng bắt đầu bằng W sẽ được định tuyến đến kênh router.out.widget. Triển khai hàm ComputeSubject của TIBCO trông như thế này: concat("router.out.",DGet(map,Upper(Left(OrderItem.ItemNumber,1)))) Hàm này trích xuất chữ cái đầu tiên của số đơn hàng (sử dụng hàm Left) và chuyển đổi nó thành chữ hoa (sử dụng hàm Upper). Hàm sử dụng kết quả này làm khóa cho từ điển để lấy tên của kênh xuất ra (sử dụng hàm DGet). Ví dụ này chứng minh sức mạnh của các công cụ EAI thương mại. Thay vì phải viết vài chục dòng mã, chúng ta chỉ cần lập trình một hàm duy nhất để triển khai chức năng bộ định tuyến widget tương tự. Thêm vào đó, chúng ta nhận được những tính năng như giao dịch, quản lý luồng và quản lý hệ thống miễn phí. Nhưng ví dụ này cũng nêu bật những khó khăn trong việc trình bày một giải pháp được tạo ra bằng các công cụ đồ họa. Chúng tôi đã phải sử dụng ảnh chụp màn hình để mô tả giải pháp. Nhiều cài đặt quan trọng bị ẩn trong các trường thuộc tính không hiển thị trên màn hình. Điều này có thể gây khó khăn trong việc tài liệu hóa một giải pháp được xây dựng bằng các công cụ phát triển đồ họa. |
Tiếp tục với ví dụ xử lý đơn hàng, giả sử rằng ban lãnh đạo công ty đã quyết định công bố các thay đổi về giá và các chương trình khuyến mãi cho các khách hàng lớn. Chúng tôi muốn gửi một tin nhắn để thông báo cho khách hàng mỗi khi giá của một mặt hàng thay đổi. Chúng tôi làm điều tương tự nếu chúng tôi đang thực hiện một chương trình khuyến mãi đặc biệt, chẳng hạn như giảm giá 10% cho tất cả các sản phẩm widget trong tháng 11. Một số khách hàng có thể quan tâm đến việc nhận cập nhật giá hoặc các chương trình khuyến mãi chỉ liên quan đến những mặt hàng cụ thể. Ví dụ, nếu tôi chủ yếu mua các thiết bị điện tử cầm tay, tôi có thể không quan tâm đến việc biết liệu các sản phẩm widget có đang giảm giá hay không.
| Làm thế nào một thành phần có thể tránh nhận được những tin nhắn không thú vị? |
Cách cơ bản nhất để một thành phần chỉ nhận các thông điệp liên quan là chỉ đăng ký vào những kênh phát sóng mang các thông điệp đó. Tùy chọn này tận dụng khả năng định tuyến vốn có của các Kênh Xuất Bản-Đăng Ký. Một thành phần chỉ nhận những thông điệp đi qua các kênh mà thành phần đó đã đăng ký. Ví dụ, chúng ta có thể tạo một kênh cho các cập nhật widget và một kênh khác cho các cập nhật gadget. Khách hàng có thể tự do đăng ký vào một trong hai kênh hoặc cả hai. Điều này có lợi thế là các thuê bao mới có thể tham gia mà không cần thay đổi gì trong hệ thống. Tuy nhiên, việc đăng ký vào Kênh Xuất Bản-Đăng Ký thường chỉ giới hạn ở một điều kiện nhị phân đơn giản: Nếu một thành phần đăng ký vào một kênh, nó sẽ nhận tất cả các thông điệp trên kênh đó. Cách duy nhất để đạt được độ chi tiết hơn là tạo nhiều kênh hơn. Nếu chúng ta đang xử lý một sự kết hợp của nhiều tham số, số lượng kênh có thể nhanh chóng bùng nổ. Ví dụ, nếu chúng ta muốn cho phép người tiêu dùng nhận tất cả các thông điệp thông báo về tất cả các đợt giảm giá của widget hoặc gadget trên 5%, 10% hoặc 15%, chúng ta đã cần sáu kênh (2 loại sản phẩm nhân với 3 giá trị ngưỡng). Cách tiếp cận này sẽ cuối cùng trở nên khó quản lý và tiêu tốn tài nguyên đáng kể do số lượng kênh đã phân bổ lớn. Vì vậy, chúng ta cần tìm một giải pháp cho phép linh hoạt hơn so với những gì mà việc đăng ký kênh cung cấp.
Chúng ta cũng cần một giải pháp có khả năng đáp ứng sự thay đổi thường xuyên. Ví dụ, chúng ta có thể điều chỉnh một Bộ định tuyến dựa trên nội dung để chuyển tiếp tin nhắn đến nhiều đích khác nhau (một khái niệm được mô tả trong Danh sách Người nhận). Bộ định tuyến dự đoán này chỉ gửi những tin nhắn liên quan đến từng người nhận, sao cho người nhận không phải thực hiện bất kỳ bước bổ sung nào. Tuy nhiên, bây giờ chúng ta lại tạo gánh nặng cho người phát tin trong việc duy trì sở thích cho từng người đăng ký. Nếu danh sách người nhận hoặc sở thích của họ thay đổi nhanh chóng, giải pháp này sẽ trở thành một cơn ác mộng trong việc bảo trì.
Chúng tôi có thể đơn giản phát sóng các thay đổi đến tất cả các thành phần và kỳ vọng mỗi thành phần sẽ lọc ra các tin nhắn không mong muốn. Tuy nhiên, cách tiếp cận này giả định rằng chúng tôi có quyền kiểm soát đối với thành phần thực tế. Trong nhiều kịch bản tích hợp, điều này không đúng bởi vì chúng tôi đang xử lý các ứng dụng đóng gói, ứng dụng kế thừa, hoặc các ứng dụng không thuộc quyền kiểm soát của tổ chức chúng tôi.
| Sử dụng một loại Bộ định tuyến Tin nhắn đặc biệt, một Bộ lọc Tin nhắn, để loại bỏ các tin nhắn không mong muốn từ một kênh dựa trên một tập hợp các tiêu chí.
|
Bộ lọc tin nhắn là một bộ định tuyến tin nhắn với một kênh đầu ra duy nhất. Nếu nội dung của một tin nhắn đến khớp với các tiêu chí được chỉ định bởi Bộ lọc tin nhắn, tin nhắn sẽ được chuyển đến kênh đầu ra. Nếu nội dung tin nhắn không khớp với các tiêu chí, tin nhắn sẽ bị loại bỏ.
Trong ví dụ của chúng tôi, chúng tôi sẽ định nghĩa một Kênh Đăng Ký-Phát Hành duy nhất mà mỗi khách hàng tự do lắng nghe. Khách hàng sau đó có thể sử dụng Bộ Lọc Tin Nhắn để loại bỏ các tin nhắn dựa trên tiêu chí mà họ chọn, chẳng hạn như loại mặt hàng hoặc mức độ thay đổi giá.
Bộ lọc tin nhắn có thể được miêu tả như một trường hợp đặc biệt của Bộ định tuyến Dựa trên Nội dung, mà định tuyến tin nhắn đến kênh đầu ra hoặc kênh null, một kênh loại bỏ bất kỳ tin nhắn nào được phát hành tới nó. Mục đích của một kênh như vậy tương tự như đích /dev/null có mặt trong nhiều hệ điều hành hoặc một Đối tượng Null [PLoPD3].
Ví dụ về widget và gadget mô tả một bộ lọc tin nhắn không trạng thái: Bộ lọc tin nhắn kiểm tra một tin nhắn duy nhất và quyết định xem có nên chuyển tiếp nó hay không chỉ dựa trên thông tin có trong tin nhắn đó. Do đó, bộ lọc tin nhắn không cần duy trì trạng thái giữa các tin nhắn và được coi là không trạng thái. Các thành phần không trạng thái có ưu điểm là cho phép chúng ta chạy nhiều phiên bản của thành phần đó song song để tăng tốc độ xử lý. Tuy nhiên, một bộ lọc tin nhắn không nhất thiết phải không trạng thái. Ví dụ, có những tình huống mà bộ lọc tin nhắn cần theo dõi lịch sử tin nhắn. Một kịch bản phổ biến là sử dụng bộ lọc tin nhắn để loại bỏ tin nhắn trùng lặp. Giả sử mỗi tin nhắn có một định danh tin nhắn duy nhất, bộ lọc tin nhắn sẽ lưu trữ các định danh của các tin nhắn trước đó để có thể nhận ra một tin nhắn trùng lặp bằng cách so sánh định danh của mỗi tin nhắn với danh sách các định danh đã lưu.
Một số hệ thống nhắn tin tích hợp các khía cạnh của Bộ lọc Tin nhắn bên trong hạ tầng nhắn tin. Ví dụ, một số hệ thống xuất bản-tham gia cho phép bạn định nghĩa cấu trúc phân cấp cho các Kênh Xuất bản-Tham gia. Nhiều hệ thống xuất bản-tham gia, bao gồm hầu hết các triển khai JMS, cho phép điều này. Ví dụ, một người có thể xuất bản các chương trình khuyến mãi lên kênh wgco.update.promotion.widget. Một người đăng ký sau đó có thể sử dụng ký tự đại diện để đăng ký một tập hợp cụ thể của các tin nhắn; ví dụ, nếu một người đăng ký lắng nghe chủ đề wgco.update.*.widget, họ sẽ nhận tất cả các cập nhật (chương trình khuyến mãi và thay đổi giá) liên quan đến đồ dùng. Một người đăng ký khác có thể lắng nghe wgco.update.promotion.*, sẽ gửi tất cả các chương trình khuyến mãi liên quan đến đồ dùng và thiết bị, nhưng không có thay đổi giá. Cấu trúc kênh phân cấp cho phép chúng ta tinh chỉnh nghĩa của một kênh bằng cách thêm các tham số bổ sung, để thay vì một khách hàng đăng ký tất cả các cập nhật, khách hàng có thể lọc tin nhắn bằng cách chỉ định các tiêu chí bổ sung như một phần của tên kênh. Tuy nhiên, tính linh hoạt mà cái tên kênh phân cấp cung cấp vẫn còn hạn chế khi so sánh với một Bộ lọc Tin nhắn. Ví dụ, một Bộ lọc Tin nhắn có thể quyết định chuyển tiếp một tin nhắn thay đổi giá chỉ khi giá thay đổi hơn 11,5 phần trăm, điều này sẽ rất khó để diễn đạt thông qua các tên kênh.
Các hệ thống nhắn tin khác cung cấp hỗ trợ API cho những Người tiêu dùng Chọn lọc bên trong ứng dụng nhận. Bộ chọn tin nhắn là các biểu thức đánh giá các phần tử tiêu đề hoặc thuộc tính bên trong một tin nhắn đến trước khi ứng dụng có thể thấy tin nhắn. Nếu điều kiện không đánh giá là đúng, tin nhắn sẽ bị bỏ qua và không được chuyển tiếp đến logic ứng dụng. Bộ chọn tin nhắn hoạt động như một Bộ lọc Tin nhắn được tích hợp vào ứng dụng. Mặc dù việc sử dụng bộ chọn tin nhắn vẫn yêu cầu bạn phải sửa đổi ứng dụng (điều này thường không thể thực hiện trong EAI), việc thực thi các quy tắc lựa chọn được tích hợp vào cơ sở hạ tầng nhắn tin. Một sự khác biệt quan trọng giữa Bộ lọc Tin nhắn và Người tiêu dùng Chọn lọc là một người tiêu dùng sử dụng Người tiêu dùng Chọn lọc sẽ không tiêu thụ các tin nhắn không phù hợp với tiêu chí đã chỉ định. Mặt khác, một Bộ lọc Tin nhắn loại bỏ tất cả các tin nhắn khỏi kênh đầu vào, chỉ công bố trên kênh đầu ra những tin nhắn khớp với tiêu chí đã chỉ định.
Bởi vì Người Tiêu Dùng Chọn Lọc đăng ký biểu thức lọc với cơ sở hạ tầng nhắn tin, cơ sở hạ tầng có khả năng đưa ra quyết định định tuyến nội bộ thông minh dựa trên tiêu chí lọc. Giả sử rằng người nhận tin nhắn nằm trên một phân khúc mạng khác với người phát nguồn tin nhắn (hoặc thậm chí ở xa qua Internet). Sẽ khá lãng phí khi định tuyến tin nhắn tất cả đi đến Bộ Lọc Tin Nhắn chỉ để phát hiện rằng chúng ta muốn loại bỏ tin nhắn. Mặt khác, chúng ta muốn sử dụng cơ chế Bộ Lọc Tin Nhắn để người nhận có quyền kiểm soát việc định tuyến tin nhắn thay vì một Bộ Định Tuyến Tin Nhắn trung tâm. Nếu Bộ Lọc Tin Nhắn là một phần của API mà cơ sở hạ tầng nhắn tin cung cấp cho người đăng ký tin nhắn, cơ sở hạ tầng có thể tự do truyền bá biểu thức lọc gần hơn đến nguồn. Điều này sẽ duy trì ý định ban đầu là giữ quyền kiểm soát với người đăng ký tin nhắn, nhưng cho phép cơ sở hạ tầng nhắn tin tránh được lưu lượng mạng không cần thiết. Hành vi này giống như một Danh Sách Người Nhận động.
Chúng ta có thể sử dụng một Kênh Đăng Ký - Phát Sóng kết nối với một tập hợp các Bộ Lọc Tin Nhắn để loại bỏ các tin nhắn không mong muốn nhằm thực hiện chức năng tương đương với một Router Dựa Trên Nội Dung. Các sơ đồ dưới đây minh hoạ cho hai tùy chọn:
Tùy chọn 1: Sử dụng Bộ định tuyến Dựa trên Nội dung

Trong ví dụ đơn giản này, chúng ta có hai người nhận: người nhận Gadgets chỉ quan tâm đến các tin nhắn gadget, trong khi người nhận Widgets chỉ quan tâm đến các tin nhắn widget. Router dựa trên nội dung đánh giá nội dung của từng tin nhắn và định tuyến nó một cách dự đoán đến người nhận thích hợp.
Lựa chọn 2: Sử dụng Kênh Phát sóng và Một Bộ Bộ Lọc Tin nhắn

Tùy chọn thứ hai phát sóng thông điệp đến một Kênh Xuất Bản-Đăng Ký. Mỗi người nhận được trang bị một Bộ Lọc Thông Điệp để loại bỏ các thông điệp không mong muốn. Ví dụ, bộ nhận Widgets sử dụng một bộ lọc widget chỉ cho phép các thông điệp về widget đi qua.
Bảng sau mô tả một số sự khác biệt giữa hai giải pháp:
Bộ định tuyến dựa trên nội dung | Kênh Phân phối-Cấp phát với Bộ lọc Tin nhắn |
|---|---|
Chính xác một người tiêu dùng nhận mỗi tin nhắn. | Nhiều hơn một người tiêu dùng có thể tiêu thụ một thông điệp. |
Kiểm soát trung tâm và định tuyến bảo trì dự đoán. | Kiểm soát phân tán và lọc phản ứng bảo trì. |
Bộ định tuyến cần biết về các thành viên tham gia. Bộ định tuyến có thể cần được cập nhật nếu có thành viên tham gia được thêm vào hoặc loại bỏ. | Không cần kiến thức về người tham gia. Thêm hoặc xóa người tham gia rất dễ dàng. |
Thường được sử dụng cho các giao dịch thương mại, ví dụ: đơn hàng. | Thường được sử dụng cho thông báo sự kiện hoặc tin nhắn thông tin. |
Thường hiệu quả hơn với các kênh dựa trên hàng đợi. | Thông thường hiệu quả hơn với các kênh công bố-nhận. |
Làm thế nào để chúng ta quyết định giữa hai tùy chọn? Trong một số trường hợp, quyết định được dẫn dắt bởi chức năng yêu cầu; ví dụ, nếu chúng ta cần khả năng cho nhiều người nhận cùng xử lý một tin nhắn, chúng ta cần sử dụng Kênh Xuất Bản - Đăng Ký với Bộ Lọc Tin Nhắn. Tuy nhiên, trong phần lớn các trường hợp, chúng ta quyết định dựa trên bên nào kiểm soát (và cần duy trì) quyết định định tuyến. Chúng ta muốn giữ quyền kiểm soát trung tâm hay phân tán nó cho các người nhận? Nếu các tin nhắn chứa dữ liệu nhạy cảm chỉ được nhìn thấy bởi một số người nhận nhất định, chúng ta cần sử dụng Bộ Định Tuyến Dựa Trên Nội Dung vì chúng ta không muốn tin tưởng vào các người nhận khác để lọc các tin nhắn. Ví dụ, hãy giả sử chúng ta cung cấp giảm giá đặc biệt cho các khách hàng cao cấp: Chúng ta sẽ không gửi những điều này cho các khách hàng không cao cấp và mong họ sẽ bỏ qua các ưu đãi đặc biệt này.
Các yếu tố liên quan đến lưu lượng mạng có thể ảnh hưởng đến quyết định. Nếu chúng ta có một cách hiệu quả để phát thông tin (ví dụ: sử dụng multicast IP trên một mạng nội bộ), việc sử dụng bộ lọc có thể rất hiệu quả và tránh được nút thắt tiềm ẩn của một bộ định tuyến đơn. Tuy nhiên, nếu thông tin này được chuyển tuyến qua Internet, chúng ta bị hạn chế ở các kết nối điểm-đến-điểm. Trong trường hợp này, một bộ định tuyến duy nhất sẽ hiệu quả hơn nhiều, vì nó tránh việc gửi các thông điệp riêng lẻ đến tất cả các bên tham gia bất kể sự quan tâm của họ. Nếu chúng ta muốn chuyển quyền kiểm soát cho các người nhận nhưng cần sử dụng một bộ định tuyến vì lý do hiệu quả mạng, chúng ta có thể sử dụng một Danh sách Người Nhận Động. Loại Danh sách Người Nhận này hoạt động như một Bộ Định Tuyến Động, cho phép các người nhận thể hiện sở thích của họ thông qua các thông điệp điều khiển đến bộ định tuyến. Danh sách Người Nhận lưu trữ sở thích của người nhận trong một cơ sở dữ liệu hoặc cơ sở quy tắc. Khi một thông điệp đến, Danh sách Người Nhận sẽ chuyển tiếp thông điệp đến tất cả các người nhận quan tâm có tiêu chí phù hợp với thông điệp.
Bạn đang sử dụng một Bộ định tuyến Tin nhắn để chuyển tiếp tin nhắn giữa nhiều đích đến khác nhau.
| Làm thế nào bạn có thể tránh việc router phụ thuộc vào tất cả các điểm đến có thể có trong khi vẫn duy trì hiệu quả của nó? |
Một Bộ định tuyến tin nhắn rất hiệu quả vì nó có thể định tuyến một tin nhắn trực tiếp đến đích đúng. Các giải pháp khác cho việc định tuyến tin nhắn, đặc biệt là các giải pháp lọc phản ứng, kém hiệu quả hơn vì chúng sử dụng phương pháp thử và sai: Ví dụ, một Giấy định tuyến gửi mỗi tin nhắn đến đích khả thi đầu tiên. Nếu đích đó là đúng, nó chấp nhận tin nhắn; nếu không, tin nhắn sẽ được chuyển đến đích khả thi thứ hai và cứ tiếp tục như vậy. Tương tự, một phương pháp dựa trên Bộ lọc tin nhắn gửi tin nhắn đến tất cả các người nhận khả thi cho dù họ có quan tâm hay không.
Các giải pháp định tuyến phân tán cũng gặp rủi ro là có nhiều người nhận một tin nhắn hoặc không có ai cả. Cả hai tình huống này có thể không được phát hiện trừ khi chúng ta sử dụng một yếu tố định tuyến trung tâm.
Để đạt được độ chính xác này, chúng ta cần sử dụng một Bộ định tuyến Tin nhắn (Message Router) kết hợp kiến thức về từng điểm đến và các quy tắc để chuyển tiếp tin nhắn đến các điểm đến đó. Tuy nhiên, điều này có thể biến Bộ định tuyến Tin nhắn thành gánh nặng bảo trì nếu danh sách các điểm đến có thể thay đổi thường xuyên.
| Sử dụng một Bộ định tuyến Động, một bộ định tuyến có thể tự cấu hình dựa trên các thông điệp cấu hình đặc biệt từ các đích tham gia.
|
Ngoài các kênh đầu vào và đầu ra thông thường, Bộ định tuyến Động sử dụng một kênh điều khiển bổ sung. Trong quá trình khởi động hệ thống, mỗi người nhận tiềm năng gửi một thông điệp đặc biệt đến Bộ định tuyến Động trên kênh điều khiển này, thông báo sự hiện diện của mình và liệt kê các điều kiện mà họ có thể xử lý một thông điệp. Bộ định tuyến Động lưu trữ sở thích của từng người tham gia trong một cơ sở quy tắc. Khi một thông điệp đến, Bộ định tuyến Động đánh giá tất cả các quy tắc và định tuyến thông điệp tới người nhận có các quy tắc được thỏa mãn. Điều này cho phép định tuyến hiệu quả, dự đoán mà không phụ thuộc vào việc bảo trì của Bộ định tuyến Động đối với mỗi người nhận tiềm năng.
Trong kịch bản cơ bản nhất, mỗi người tham gia thông báo về sự tồn tại và sở thích định tuyến của mình đến Bộ định tuyến Động tại thời điểm khởi động. Điều này yêu cầu mỗi người tham gia phải biết về hàng đợi điều khiển được Bộ định tuyến Động sử dụng. Nó cũng yêu cầu Bộ định tuyến Động lưu trữ các quy tắc một cách bền vững. Nếu không, nếu Bộ định tuyến Động gặp sự cố và phải khởi động lại, nó sẽ không thể khôi phục các quy tắc định tuyến. Ngoài ra, Bộ định tuyến Động có thể gửi một tin nhắn phát sóng đến tất cả các người tham gia có thể để kích hoạt họ trả lời bằng tin nhắn điều khiển. Cấu hình này mạnh mẽ hơn nhưng yêu cầu sử dụng một Kênh Đăng ký-Publish bổ sung.
Có thể hợp lý để nâng cấp kênh điều khiển cho phép người tham gia gửi cả tin nhắn đăng ký và hủy đăng ký đến Bộ định tuyến Động. Điều này sẽ cho phép người nhận thêm hoặc xóa bản thân khỏi sơ đồ định tuyến trong thời gian thực.
Bởi vì các người nhận độc lập với nhau, Bộ định tuyến động phải xử lý các xung đột quy tắc, chẳng hạn như nhiều người nhận cùng thông báo quan tâm đến cùng một loại tin nhắn. Bộ định tuyến động có thể áp dụng một số chiến lược khác nhau để giải quyết những xung đột như vậy:
Bỏ qua các thông điệp điều khiển mâu thuẫn với các thông điệp hiện có. Tùy chọn này đảm bảo rằng các quy tắc định tuyến không có xung đột. Tuy nhiên, trạng thái của bảng định tuyến có thể phụ thuộc vào thứ tự mà các người nhận tiềm năng khởi động. Nếu tất cả các người nhận khởi động cùng một lúc, điều này có thể dẫn đến hành vi không thể đoán trước vì tất cả các người nhận sẽ công bố sở thích của họ cùng một lúc đến hàng đợi điều khiển.
Gửi tin nhắn đến người nhận đầu tiên có tiêu chí phù hợp. Tùy chọn này cho phép bảng định tuyến chứa các xung đột nhưng giải quyết chúng khi các tin nhắn đến.
Gửi tin nhắn đến tất cả người nhận có tiêu chí phù hợp. Tùy chọn này cho phép xử lý xung đột nhưng biến Bộ định tuyến Động thành Danh sách Người nhận. Thông thường, hành vi của Bộ định tuyến Dựa trên Nội dung ám chỉ rằng nó phát hành một tin nhắn đầu ra cho mỗi tin nhắn đầu vào. Chiến lược này vi phạm quy tắc đó.
Các trách nhiệm chính của Bộ định tuyến động là độ phức tạp của giải pháp và khó khăn trong việc gỡ lỗi một hệ thống được cấu hình động.
Một Bộ Định Tuyến Động là một ví dụ khác trong đó phần mềm trung gian dựa trên tin nhắn thực hiện các chức năng tương tự như mạng IP cấp thấp. Một Bộ Định Tuyến Động hoạt động rất giống với bảng định tuyến động được sử dụng trong định tuyến IP để định tuyến các gói IP giữa các mạng. Giao thức mà các bên nhận sử dụng để cấu hình Bộ Định Tuyến Động tương tự như Giao thức Thông tin Định tuyến IP (RIP; để biết thêm thông tin, xem [Stevens]).
Một ứng dụng phổ biến của Bộ định tuyến Động là phát hiện dịch vụ động trong các kiến trúc theo dịch vụ. Nếu một ứng dụng khách muốn truy cập vào một dịch vụ, nó sẽ gửi một tin nhắn chứa tên của dịch vụ đến Bộ định tuyến Động. Bộ định tuyến Động duy trì một thư mục dịch vụ, một danh sách tất cả các dịch vụ với tên và kênh mà chúng đang lắng nghe. Bộ định tuyến xây dựng thư mục này dựa trên các tin nhắn điều khiển từ từng nhà cung cấp dịch vụ. Khi một yêu cầu dịch vụ đến, Bộ định tuyến Động sử dụng thư mục dịch vụ để tra cứu dịch vụ theo tên, sau đó chuyển tiếp tin nhắn đến kênh thích hợp. Cấu trúc này cho phép ứng dụng khách gửi tin nhắn lệnh đến một kênh duy nhất mà không cần phải lo lắng về bản chất hoặc vị trí của nhà cung cấp dịch vụ đã chỉ định, ngay cả khi nhà cung cấp thay đổi.
Một mẫu liên quan, mẫu Khách hàng-Trình phân phối-Máy chủ [POSA], cho phép một khách hàng yêu cầu một dịch vụ cụ thể mà không cần biết vị trí vật lý của nhà cung cấp dịch vụ. Trình phân phối sử dụng danh sách các dịch vụ đã đăng ký để thiết lập kết nối giữa khách hàng và máy chủ vật lý thực hiện dịch vụ được yêu cầu. Bộ định tuyến động thực hiện một chức năng tương tự nhưng khác với trình phân phối ở chỗ nó có thể sử dụng phương thức định tuyến thông minh hơn so với việc tra cứu đơn giản trong bảng.
| Ví dụ: Bộ định tuyến động sử dụng C# và MSMQ Ví dụ này dựa trên ví dụ đã được trình bày trong Bộ định tuyến dựa trên nội dung và cải tiến nó để hoạt động như một Bộ định tuyến động. Thành phần mới lắng nghe trên hai kênh: inQueue và controlQueue. Hàng đợi điều khiển có thể nhận các tin nhắn theo định dạng X:QueueName, khiến Bộ định tuyến động chuyển tiếp tất cả các tin nhắn có nội dung bắt đầu bằng chữ X đến hàng đợi QueueName. [View full width] class DynamicRouter { protected MessageQueue inQueue; protected MessageQueue controlQueue; protected MessageQueue dunnoQueue; protected IDictionary routingTable = (IDictionary)(new Ví dụ này sử dụng một cơ chế giải quyết xung đột rất đơn giản: cái cuối cùng thắng. Nếu hai người nhận bày tỏ sự quan tâm đến việc nhận tin nhắn bắt đầu bằng chữ X, chỉ có người nhận thứ hai sẽ nhận được tin nhắn vì Hashtable chỉ lưu trữ một hàng đợi cho mỗi giá trị khóa. Cũng lưu ý rằng dunnoQueue bây giờ có thể nhận hai loại tin nhắn: tin nhắn đến không có quy tắc định tuyến phù hợp hoặc tin nhắn điều khiển không khớp với định dạng yêu cầu. |
Một Bộ định tuyến dựa trên nội dung cho phép chúng ta định tuyến một tin nhắn đến hệ thống đúng dựa trên nội dung của tin nhắn. Quá trình này hoàn toàn minh bạch đối với người gửi ban đầu theo nghĩa là người gửi chỉ cần gửi tin nhắn đến một kênh, nơi bộ định tuyến nhận và xử lý mọi thứ.
Trong một số trường hợp, chúng ta có thể muốn chỉ định một hoặc nhiều người nhận cho tin nhắn. Một phép ẩn dụ phổ biến là danh sách người nhận được triển khai trong hầu hết các hệ thống email. Đối với mỗi tin nhắn email, người gửi có thể chỉ định một danh sách người nhận. Hệ thống thư sau đó đảm bảo vận chuyển nội dung tin nhắn đến từng người nhận. Một ví dụ từ lĩnh vực tích hợp doanh nghiệp sẽ là một tình huống mà một chức năng có thể được thực hiện bởi một hoặc nhiều nhà cung cấp. Ví dụ, chúng ta có thể có một hợp đồng với nhiều cơ quan tín dụng để đánh giá mức độ tín nhiệm của khách hàng. Khi một đơn hàng nhỏ được gửi đến, chúng ta có thể đơn giản chuyển tin nhắn yêu cầu tín dụng đến một cơ quan tín dụng. Nếu một khách hàng đặt hàng lớn, chúng ta có thể muốn chuyển tin nhắn yêu cầu tín dụng đến nhiều cơ quan và so sánh kết quả trước khi đưa ra quyết định. Trong trường hợp này, danh sách người nhận phụ thuộc vào giá trị đô la của đơn hàng.
Trong một tình huống khác, chúng ta có thể muốn gửi thông điệp đặt hàng đến một danh sách nhà cung cấp được chọn để nhận báo giá cho một mặt hàng đã yêu cầu. Thay vì gửi yêu cầu đến tất cả các nhà cung cấp, chúng ta có thể muốn kiểm soát những nhà cung cấp nào nhận được yêu cầu, có thể dựa trên sở thích của người dùng.
| Làm thế nào chúng ta gửi một tin nhắn đến một danh sách người nhận động? |
Vấn đề này là một sự mở rộng cho vấn đề mà một Bộ định tuyến Dựa trên Nội dung giải quyết, vì vậy một số lực và phương án tương tự được mô tả trong mẫu đó cũng phát huy tác dụng ở đây.
Hầu hết các hệ thống nhắn tin cung cấp Kênh Xuất Bản-Đăng Ký, một loại kênh gửi một bản sao của mỗi tin nhắn đã xuất bản tới mỗi người nhận đã đăng ký kênh. Tập hợp người nhận dựa trên việc đăng ký vào kênh hoặc chủ đề cụ thể. Tuy nhiên, danh sách những người đăng ký hoạt động cho một kênh có phần tĩnh và không thể kiểm soát trên cơ sở từng tin nhắn. Điều chúng ta cần là một cái gì đó giống như Kênh Xuất Bản-Đăng Ký có thể gửi mỗi tin nhắn tới một danh sách người đăng ký khác nhau. Điều này khó khăn vì việc đăng ký vào một Kênh Xuất Bản-Đăng Ký là nhị phân - bạn hoặc là đã đăng ký cho tất cả các tin nhắn trên kênh hoặc không có tin nhắn nào.
Mỗi người nhận tiềm năng có thể lọc các tin nhắn đến dựa trên nội dung tin nhắn, có thể bằng cách sử dụng Bộ Lọc Tin Nhắn hoặc Người Tiêu Thụ Chọn Lọc. Thật không may, giải pháp này phân tán logic về việc ai nhận được tin nhắn cho từng người đăng ký, điều này có thể trở thành gánh nặng bảo trì. Để giữ một điểm kiểm soát trung tâm, tin nhắn có thể chỉ định các người nhận dự kiến trong một danh sách đính kèm với tin nhắn. Sau đó, khi tin nhắn được phát sóng đến tất cả các người nhận có thể, mỗi người nhận không có trong danh sách người nhận của tin nhắn sẽ loại bỏ tin nhắn đó.
Vấn đề với những phương pháp này là sự kém hiệu quả của chúng: Mỗi người nhận tiềm năng phải xử lý mọi tin nhắn, ngay cả khi trong nhiều trường hợp người nhận sẽ quyết định bỏ qua tin nhắn đó. Cấu hình này cũng dựa vào một "hệ thống danh dự" nào đó từ phía người nhận, vì một người nhận có thể quyết định xử lý một tin nhắn mà họ không nên xử lý. Điều này chắc chắn không mong muốn trong những tình huống mà một tin nhắn cần được giữ kín khỏi một số người nhận nhất định, chẳng hạn như khi chuyển tiếp một yêu cầu báo giá tới một tập hợp nhà cung cấp được chọn và mong đợi những người khác sẽ bỏ qua yêu cầu khi họ nhận được nó.
Chúng tôi cũng có thể yêu cầu người gửi tin nhắn phát hành tin nhắn một cách riêng lẻ đến từng người nhận mong muốn. Tuy nhiên, trong trường hợp đó, chúng tôi sẽ đặt gánh nặng giao hàng cho tất cả người nhận lên người gửi tin nhắn. Nếu người gửi là một ứng dụng đóng gói, điều này thường không phải là một lựa chọn. Ngoài ra, điều này sẽ nhúng logic quyết định vào bên trong ứng dụng, điều này sẽ làm cho ứng dụng gắn kết chặt chẽ hơn với cơ sở hạ tầng tích hợp. Trong nhiều trường hợp, các ứng dụng đang được tích hợp không nhận ra rằng chúng tham gia vào một giải pháp tích hợp, vì vậy kỳ vọng ứng dụng chứa logic định tuyến tin nhắn là không thực tế.
| Định nghĩa một kênh cho mỗi người nhận. Sau đó, sử dụng một Danh sách Người nhận để kiểm tra một thông điệp đến, xác định danh sách những người nhận mong muốn, và chuyển tiếp thông điệp đến tất cả các kênh liên quan đến những người nhận trong danh sách.
|
Logic được nhúng trong Danh sách Người Nhận có thể được hình dung như hai phần tách biệt mặc dù việc triển khai thường được kết hợp với nhau. Phần đầu tiên tính toán một danh sách các người nhận. Phần thứ hai đơn giản là duyệt qua danh sách và gửi một bản sao của tin nhắn nhận được đến từng người nhận. Giống như một Bộ định tuyến Dựa trên Nội dung, Danh sách Người Nhận thường không thay đổi nội dung tin nhắn.
Danh sách người nhận có thể tính toán các người nhận (bên trái) hoặc có một thành phần khác cung cấp danh sách (bên phải).

Danh sách người nhận có thể được lấy từ một số nguồn khác nhau. Việc tạo danh sách có thể diễn ra bên ngoài Danh sách Người Nhận, để người gửi tin nhắn hoặc một thành phần khác đính kèm danh sách vào tin nhắn đến. Trong trường hợp đó, Danh sách Người Nhận chỉ cần lặp qua danh sách đã chuẩn bị sẵn này. Danh sách Người Nhận thường loại bỏ danh sách khỏi tin nhắn để giảm kích thước của các tin nhắn gửi đi và ngăn các người nhận cá nhân thấy ai khác trong danh sách. Mặt khác, việc cung cấp danh sách người nhận kèm theo tin nhắn đến là hợp lý nếu đích đến của mỗi tin nhắn phụ thuộc vào các yếu tố bên ngoài, chẳng hạn như lựa chọn của người dùng.
Trong hầu hết các trường hợp, Danh sách Người nhận tính toán danh sách người nhận dựa trên nội dung của tin nhắn và một tập hợp các quy tắc được nhúng trong Danh sách Người nhận. Những quy tắc này có thể được mã hóa cứng hoặc có thể cấu hình (xem trang tiếp theo).
Danh sách người nhận phải tuân theo cùng một cân nhắc về việc liên kết như đã thảo luận trong Trình định tuyến tin nhắn. Việc định tuyến các tin nhắn một cách dự đoán đến từng người nhận có thể dẫn đến sự liên kết chặt chẽ hơn giữa các thành phần vì một thành phần trung tâm phải có kiến thức về một loạt các thành phần khác.
Để Danh sách Người nhận có thể kiểm soát dòng thông tin, chúng ta cần đảm bảo rằng người nhận không thể đăng ký trực tiếp vào kênh đầu vào của Danh sách Người nhận, vượt qua bất kỳ sự kiểm soát nào mà Danh sách Người nhận thực thi.
Thành phần Danh sách Người nhận chịu trách nhiệm gửi tin nhắn đến từng người nhận được chỉ định trong danh sách người nhận. Một triển khai vững chắc của Danh sách Người nhận phải có khả năng xử lý tin nhắn đến nhưng chỉ "tiêu thụ" nó sau khi tất cả các tin nhắn đi đã được gửi thành công. Do đó, thành phần Danh sách Người nhận phải đảm bảo rằng toàn bộ quá trình nhận một tin nhắn và gửi nhiều tin nhắn là nguyên tử. Nếu một Danh sách Người nhận gặp lỗi, nó phải có thể khởi động lại, có nghĩa là nó phải có khả năng hoàn thành bất kỳ hoạt động nào đang tiến hành khi thành phần gặp lỗi. Điều này có thể được thực hiện theo nhiều cách:
Giao dịch đơn lẻ: Danh sách Người Nhận có thể sử dụng các kênh giao dịch và đặt thông điệp trên các kênh xuất phát như một phần của một giao dịch đơn lẻ. Nó sẽ không cam kết các thông điệp cho đến khi tất cả các thông điệp được đặt trên các kênh. Điều này đảm bảo rằng hoặc là tất cả hoặc không có thông điệp nào được gửi đi.
Danh sách người nhận bền vững: Danh sách người nhận có thể "nhớ" những tin nhắn mà nó đã gửi để trong trường hợp thất bại và khởi động lại, nó có thể gửi tin nhắn đến những người nhận còn lại. Danh sách người nhận có thể được lưu trữ trên đĩa hoặc cơ sở dữ liệu để nó có thể tồn tại sau khi thành phần Danh sách người nhận gặp sự cố.
Nhận diện không đổi: Ngoài ra, Danh sách Người nhận có thể đơn giản gửi lại tất cả tin nhắn khi khởi động lại. Tùy chọn này yêu cầu tất cả người nhận tiềm năng phải là không đổi (xem Nhận diện không đổi). Các hàm không đổi là những hàm không thay đổi trạng thái của hệ thống nếu chúng được áp dụng lên chính chúng; tức là, trạng thái của thành phần không bị ảnh hưởng nếu cùng một tin nhắn được xử lý hai lần. Tin nhắn có thể vốn dĩ là không đổi (ví dụ, các tin nhắn "Tất cả sản phẩm giảm giá đến ngày 30 tháng 5" hoặc "Hãy cho tôi một báo giá cho sản phẩm XYZ" khó có thể gây hại nếu chúng được nhận hai lần), hoặc thành phần nhận có thể được làm cho không đổi bằng cách chèn một Bộ lọc Tin nhắn đặc biệt loại bỏ các tin nhắn trùng lặp. Tính không đổi rất tiện lợi vì nó cho phép chúng ta đơn giản gửi lại tin nhắn khi chúng ta không chắc chắn liệu người nhận đã nhận được hay chưa. Giao thức TCP/IP sử dụng một cơ chế tương tự để đảm bảo việc gửi tin nhắn đáng tin cậy mà không có overhead không cần thiết.
Mặc dù mục đích của Danh Sách Người Nhận là để duy trì kiểm soát, nhưng việc để cho chính những người nhận cấu hình các quy tắc lưu trữ trong Danh Sách Người Nhận cũng có thể hữu ích. Ví dụ, nếu những người nhận muốn đăng ký nhận các thông điệp cụ thể dựa trên các quy tắc mà không thể dễ dàng được biểu diễn dưới dạng các chủ đề Kênh Xuất Bản - Đăng Ký. Chúng tôi đã đề cập đến các loại quy tắc đăng ký này trong mẫu Bộ Lọc Thông Điệp, ví dụ "chấp nhận thông điệp nếu giá thấp hơn 48,31 đô la." Để giảm thiểu lưu lượng mạng, chúng tôi vẫn muốn gửi thông điệp chỉ đến các bên quan tâm, thay vì phát sóng và để mỗi người nhận tự quyết định có xử lý thông điệp hay không. Để thực hiện chức năng này, các người nhận có thể gửi sở thích đăng ký của họ đến Danh Sách Người Nhận thông qua một kênh điều khiển đặc biệt. Danh Sách Người Nhận sẽ lưu trữ các sở thích trong một cơ sở quy tắc và sử dụng nó để biên soạn danh sách người nhận cho mỗi thông điệp. Cách tiếp cận này mang lại cho các người đăng ký quyền kiểm soát đối với việc lọc thông điệp nhưng vẫn tận dụng hiệu quả của Danh Sách Người Nhận để phân phối thông điệp. Giải pháp này kết hợp các thuộc tính của một Bộ Định Tuyến Động với Danh Sách Người Nhận để tạo ra một Danh Sách Người Nhận động (xem hình).
Danh sách người nhận động được cấu hình bởi các người nhận thông qua một kênh điều khiển.

Cách tiếp cận này sẽ hoạt động tốt cho ví dụ cập nhật giá được thảo luận trong mẫu Lọc Tin nhắn. Tuy nhiên, vì nó giao quyền điều khiển cho từng người nhận, nên không phù hợp cho ví dụ báo giá đã được đề cập ở đầu mẫu này, vì chúng tôi muốn kiểm soát các nhà cung cấp được phép tham gia vào đấu thầu.
Việc gửi một tin nhắn đến tất cả các người nhận có thể có hoặc không có khả năng lọc tin nhắn hoặc gửi tin nhắn riêng lẻ đến từng người nhận phụ thuộc rất nhiều vào việc triển khai hạ tầng nhắn tin. Nhìn chung, chúng ta có thể giả định rằng càng nhiều người nhận một tin nhắn có, thì càng nhiều lưu lượng mạng mà nó gây ra. Tuy nhiên, có những trường hợp ngoại lệ. Một số hệ thống nhắn tin dựa trên mô hình phát hành-đăng ký dựa vào chức năng IP Multicast và có thể định tuyến tin nhắn đến nhiều người nhận với một lần truyền tải mạng duy nhất (chỉ cần truyền lại cho những tin nhắn bị mất). IP Multicast tận dụng kiến trúc bus của Ethernet. Khi một gói IP được gửi qua mạng, tất cả các bộ điều hợp mạng (NIC) trên cùng một phân đoạn Ethernet nhận gói tin đó. Thông thường, NIC xác minh người nhận dự định của gói tin và bỏ qua nếu gói tin không được gửi đến địa chỉ IP mà NIC liên kết. Định tuyến multicast cho phép tất cả các người nhận là một phần của nhóm multicast được chỉ định đọc gói tin từ bus. Điều này dẫn đến việc một gói duy nhất có thể được nhận bởi nhiều NIC, sau đó chuyển dữ liệu đến ứng dụng tương ứng liên quan đến kết nối mạng. Phương pháp này có thể rất hiệu quả trên các mạng cục bộ do kiến trúc bus của Ethernet. Nó không hoạt động qua Internet, nơi yêu cầu các kết nối TCP/IP điểm đến điểm. Nhìn chung, chúng ta có thể nói rằng càng xa nhau những người nhận, thì càng hiệu quả khi sử dụng Danh sách Người nhận thay vì Kênh Phát hành-Đăng ký.
Việc phương pháp phát sóng có hiệu quả hơn so với Danh sách Người nhận hay không không chỉ phụ thuộc vào cơ sở hạ tầng mạng, mà còn vào tỷ lệ giữa tổng số người nhận và số người được dự kiến sẽ xử lý tin nhắn. Nếu trung bình hầu hết người nhận đều có trong danh sách người nhận, có thể sẽ hiệu quả hơn nếu đơn giản phát sóng tin nhắn và để cho những (ít) người không tham gia lọc tin nhắn ra. Tuy nhiên, nếu trung bình chỉ có một phần nhỏ trong số tất cả các người nhận có thể quan tâm đến một tin nhắn cụ thể, thì Danh sách Người nhận gần như đảm bảo sẽ hiệu quả hơn.
Nhiều lần chúng tôi đã so sánh việc triển khai cùng một chức năng bằng cách sử dụng định tuyến dự đoán với Danh sách Người nhận và sử dụng lọc phản ứng thông qua Kênh Đăng ký - Phát hành và một mảng Lọc Tin nhắn. Một số tiêu chí quyết định giống với những tiêu chí so sánh giữa Bộ định tuyến Dựa trên Nội dung và mảng Lọc Tin nhắn. Tuy nhiên, trong trường hợp của Danh sách Người nhận, tin nhắn có thể gửi đến nhiều người nhận, làm cho tùy chọn lọc trở nên hấp dẫn hơn.
Danh sách Người Nhận so với Mảng Lọc Tin Nhắn

Bảng dưới đây so sánh hai giải pháp:
Danh sách người nhận | Kênh Đăng-Quảng với Bộ Lọc Tin Nhắn |
|---|---|
Kiểm soát trung tâm và định tuyến bảo trì dự đoán. | Kiểm soát phân tán và lọc phản ứng bảo trì. |
Bộ định tuyến cần biết về các tham gia viên. Bộ định tuyến có thể cần được cập nhật nếu có các tham gia viên được thêm vào hoặc gỡ bỏ (trừ khi sử dụng bộ định tuyến động, nhưng sẽ mất kiểm soát). | Không cần kiến thức về người tham gia. Việc thêm hoặc xóa người tham gia rất dễ dàng. |
Thường được sử dụng cho các giao dịch kinh doanh, ví dụ: yêu cầu báo giá. | Thường được sử dụng để thông báo sự kiện hoặc tin nhắn thông tin. |
Nói chung, hiệu quả hơn nếu chỉ giới hạn ở các kênh dựa trên hàng đợi. | Có thể hiệu quả hơn với các kênh đăng ký - phát (tuỳ thuộc vào hạ tầng). |
Nếu chúng ta gửi một thông điệp đến nhiều người nhận, chúng ta có thể cần phải đối chiếu các kết quả sau này. Ví dụ, nếu chúng ta gửi yêu cầu về điểm tín dụng đến nhiều cơ quan tín dụng, chúng ta nên đợi cho đến khi tất cả kết quả trở về để có thể so sánh kết quả và tính toán chính xác điểm tín dụng trung vị. Đối với những chức năng khác, ít quan trọng hơn, chúng ta có thể chỉ lấy phản hồi đầu tiên có sẵn để tối ưu hóa thông lượng tin nhắn. Những loại chiến lược này thường được thực hiện bên trong một Bộ tổng hợp. Phương pháp Scatter-Gather mô tả các tình huống trong đó chúng ta bắt đầu với một thông điệp duy nhất, gửi nó đến nhiều người nhận, và kết hợp lại các phản hồi thành một thông điệp duy nhất.
Danh sách Người Nhận động có thể được sử dụng để triển khai Kênh Xuất Bản - Đăng Ký nếu một hệ thống nhắn tin chỉ cung cấp các Kênh Điểm-Đến-Điểm nhưng không có Kênh Xuất Bản - Đăng Ký. Danh sách Người Nhận sẽ giữ danh sách tất cả các Kênh Điểm-Đến-Điểm đã đăng ký vào chủ đề. Mỗi chủ đề có thể được đại diện bởi một thể hiện cụ thể của Danh sách Người Nhận. Giải pháp này cũng có thể hữu ích nếu chúng ta cần áp dụng các tiêu chí đặc biệt để cho phép người nhận đăng ký vào một nguồn dữ liệu cụ thể. Trong khi hầu hết các Kênh Xuất Bản - Đăng Ký cho phép bất kỳ thành phần nào đăng ký vào kênh, Danh sách Người Nhận có thể dễ dàng triển khai logic để kiểm soát quyền truy cập vào dữ liệu nguồn bằng cách hạn chế ai được phép đăng ký vào danh sách. Tất nhiên, điều này giả định rằng hệ thống nhắn tin ngăn chặn người nhận truy cập trực tiếp vào kênh đầu vào của Danh sách Người Nhận.
| Ví dụ: Nhà môi giới vay mượn Ví dụ về thông điệp được soạn thảo trong Chương 9, "Kỳ nghỉ: Thông điệp được soạn thảo," sử dụng Danh sách Người nhận để chuyển hướng yêu cầu báo giá vay chỉ đến các ngân hàng đủ điều kiện. Phần nghỉ cho thấy các triển khai của Danh sách Người nhận trong Java, C# và TIBCO. |
| Ví dụ: Danh sách người nhận động trong C# và MSMQ Ví dụ này dựa trên ví dụ Router Động để biến nó thành một Danh sách Người Nhận Động. Cấu trúc mã rất giống nhau. Danh sách Người Nhận Động lắng nghe trên hai hàng đợi đầu vào, một cho các tin nhắn đến (inQueue) và một hàng đợi điều khiển (controlQueue) nơi người nhận có thể gửi sở thích đăng ký của họ. Các tin nhắn trên hàng đợi điều khiển phải được định dạng dưới dạng một chuỗi bao gồm hai phần được phân tách bằng dấu hai chấm (:). Phần đầu tiên là một danh sách các ký tự cho biết sở thích đăng ký của người nhận. Người nhận bày tỏ rằng họ muốn nhận tất cả các tin nhắn bắt đầu bằng một trong những chữ cái đã chỉ định. Phần thứ hai của tin nhắn điều khiển chỉ định tên của hàng đợi mà người nhận lắng nghe. Ví dụ, tin nhắn điều khiển W:WidgetQueue thông báo cho Danh sách Người Nhận Động để định tuyến tất cả các tin nhắn đến bắt đầu bằng W đến hàng đợi WidgetQueue. Tương tự, tin nhắn WG:WidgetGadgetQueue chỉ dẫn Danh sách Người Nhận Động định tuyến các tin nhắn bắt đầu bằng W hoặc G đến hàng đợi WidgetGadgetQueue. [View full width] class DynamicRecipientList { protected MessageQueue inQueue; protected MessageQueue controlQueue; protected IDictionary routingTable = (IDictionary)(new Danh sách Người Nhận Động Dùng một cách lưu trữ sở thích của người nhận thông minh hơn một chút (đọc là phức tạp hơn). Để tối ưu hóa việc xử lý các tin nhắn đến, Danh sách Người Nhận Động duy trì một Hashtable được khóa theo chữ cái đầu tiên của các tin nhắn đến. Khác với ví dụ về Bộ định tuyến Động, Hashtable không chứa một đích duy nhất, mà là một Danh sách Mảng của tất cả các đích đã đăng ký. Khi Danh sách Người Nhận Động nhận được một tin nhắn, nó xác định danh sách đích đúng từ Hashtable và sau đó lặp qua danh sách để gửi một tin nhắn đến mỗi đích. Ví dụ này không sử dụng kênh dunno (xem Router dựa trên nội dung hoặc Router động) cho các tin nhắn đến không khớp với bất kỳ tiêu chí nào. Thông thường, Danh sách Nhận không coi đó là lỗi nếu có không có người nhận nào cho một tin nhắn. Việc triển khai này không cho phép người nhận hủy đăng ký. Nó cũng không phát hiện các đăng ký trùng lặp. Ví dụ, nếu một người nhận đăng ký hai lần cho cùng một loại tin nhắn, họ sẽ nhận được các tin nhắn trùng lặp. Điều này khác với ngữ nghĩa xuất bản-đăng ký điển hình, nơi một người nhận cụ thể chỉ có thể đăng ký vào một kênh một lần. Danh sách Người Nhận Động có thể dễ dàng được thay đổi để không cho phép các đăng ký trùng lặp nếu điều đó được mong muốn. |
Nhiều tin nhắn qua một giải pháp tích hợp bao gồm nhiều phần tử. Ví dụ, một đơn hàng do khách hàng đặt thường bao gồm nhiều hơn một mục hàng đơn. Như đã nêu trong mô tả về Bộ định tuyến Dựa trên Nội dung, mỗi mục hàng có thể cần được xử lý bởi một hệ thống tồn kho khác nhau. Do đó, chúng ta cần tìm một cách tiếp cận để xử lý một đơn hàng hoàn chỉnh nhưng xem xét từng mục hàng có trong đơn hàng một cách riêng biệt.
| Làm thế nào chúng ta có thể xử lý một thông điệp nếu nó chứa nhiều phần tử, mỗi phần tử có thể cần được xử lý theo cách khác nhau? |
Giải pháp cho vấn đề định tuyến này cần phải đủ chung chung để có thể xử lý các số lượng và loại yếu tố khác nhau. Ví dụ, một đơn hàng có thể chứa bất kỳ số lượng mục nào, vì vậy chúng ta không muốn tạo ra một giải pháp giả định một số lượng mục cố định. Chúng ta cũng không muốn đưa ra quá nhiều giả định về loại mục mà tin nhắn chứa. Ví dụ, nếu công ty Widgets & Gadgets 'R Us bắt đầu bán sách vào ngày mai, chúng ta muốn giảm thiểu tác động đến giải pháp tổng thể.
Chúng tôi cũng muốn duy trì kiểm soát đối với các mặt hàng trong đơn hàng và tránh việc xử lý bị trùng lặp hoặc mất mát. Ví dụ, chúng tôi có thể gửi toàn bộ đơn hàng đến từng hệ thống quản lý đơn hàng thông qua một Kênh Xuất-Bản và Đăng Ký, và để nó chọn ra các mặt hàng mà nó có thể xử lý. Cách tiếp cận này có những nhược điểm tương tự như đã mô tả trong Bộ Định Tuyến Dựa Trên Nội Dung; sẽ rất khó để tránh mất mát hoặc trùng lặp việc giao hàng của các mặt hàng cá nhân.
Giải pháp cũng cần sử dụng tài nguyên mạng một cách hiệu quả. Việc gửi toàn bộ thông điệp đơn hàng đến mỗi hệ thống có thể chỉ xử lý một phần của đơn hàng có thể gây thêm lưu lượng tin nhắn, đặc biệt khi số lượng điểm đến tăng lên.
Để tránh việc gửi toàn bộ tin nhắn nhiều lần, chúng ta có thể chia tin nhắn gốc thành nhiều tin nhắn tương ứng với số hệ thống quản lý tồn kho. Mỗi tin nhắn sẽ chỉ chứa các mục hàng có thể được hệ thống cụ thể xử lý. Phương pháp này tương tự như một Bộ định tuyến dựa trên nội dung, ngoại trừ việc chúng ta đang chia tin nhắn và sau đó định tuyến các tin nhắn riêng lẻ. Phương pháp này sẽ hiệu quả nhưng gắn liền giải pháp với kiến thức về các loại mục cụ thể và các điểm đến liên quan. Điều gì sẽ xảy ra nếu chúng ta muốn thay đổi quy tắc định tuyến? Chúng ta sẽ phải thay đổi thành phần "định tuyến mục" phức tạp hơn này. Chúng tôi đã sử dụng kiến trúc Ống và Bộ lọc trước đây để tách quá trình xử lý thành các thành phần có định nghĩa rõ ràng, có thể kết hợp, thay vì gộp nhiều chức năng lại với nhau, vì vậy chúng ta cũng nên tận dụng kiến trúc này ở đây.
| Sử dụng một bộ chia để tách thông điệp tổng hợp thành một loạt thông điệp riêng lẻ, mỗi thông điệp chứa dữ liệu liên quan đến một mục.
|
Public Splitter sẽ xuất ra một thông điệp cho từng phần tử đơn lẻ (hoặc một tập hợp con các phần tử) trong thông điệp đến. Trong nhiều trường hợp, chúng ta muốn lặp lại một số phần tử chung trong mỗi thông điệp kết quả. Những phần tử thêm này có thể cần thiết để làm cho thông điệp con kết quả tự chứa và cho phép xử lý không trạng thái của từng thông điệp con. Nó cũng cho phép việc hòa giải các thông điệp con liên quan sau này. Ví dụ, mỗi thông điệp mặt hàng đơn hàng nên chứa một bản sao của số đơn hàng để chúng ta có thể liên kết đúng mặt hàng đơn hàng với đơn hàng và tất cả các thực thể liên quan như khách hàng đặt hàng (xem hình).
Sao chép một Yếu tố Dữ liệu Chung vào Mỗi Thông điệp Con

Như đã đề cập trước đây, nhiều hệ thống tích hợp doanh nghiệp lưu trữ dữ liệu tin nhắn trong cấu trúc cây. Vẻ đẹp của một cấu trúc cây là nó có tính đệ quy. Mỗi nút con dưới một nút là gốc của một cây con khác. Điều này cho phép chúng ta trích xuất các phần của cây tin nhắn và xử lý chúng như một cây tin nhắn riêng. Nếu chúng ta sử dụng cây tin nhắn, Bộ tách (Splitter) có thể dễ dàng được cấu hình để lặp qua tất cả các nút con dưới một nút chỉ định và gửi một tin nhắn cho mỗi nút con. Một triển khai Bộ tách như vậy sẽ hoàn toàn tổng quát vì nó không đưa ra bất kỳ giả định nào về số lượng và loại phần tử con. Nhiều công cụ EAI thương mại cung cấp loại chức năng này dưới thuật ngữ bộ lặp (iterator) hoặc bộ tuần tự (sequencer). Vì chúng ta đang cố gắng tránh từ ngữ của nhà cung cấp để giảm khả năng gây nhầm lẫn, chúng tôi gọi phong cách Bộ tách này là Bộ tách lặp (iterating Splitter).
Việc sử dụng Splitter không chỉ giới hạn ở việc lặp lại các phần tử. Một thông điệp lớn có thể được chia thành các thông điệp cá nhân để đơn giản hóa quá trình xử lý. Ví dụ, một số tiêu chuẩn trao đổi thông tin B2B quy định các định dạng thông điệp rất toàn diện. Những thông điệp khổng lồ này thường là kết quả của việc thiết kế theo hình thức ủy ban, và một phần lớn của các thông điệp có thể hiếm khi được sử dụng. Trong nhiều trường hợp, việc chia những thông điệp khổng lồ này thành các thông điệp cá nhân, mỗi thông điệp tập trung vào một phần cụ thể của thông điệp lớn, là rất hữu ích. Điều này làm cho việc phát triển các chuyển đổi tiếp theo dễ dàng hơn nhiều và cũng có thể tiết kiệm băng thông mạng, vì chúng ta có thể định tuyến những thông điệp nhỏ hơn đến những thành phần chỉ xử lý một phần của thông điệp khổng lồ. Các thông điệp kết quả thường được phát hành đến các kênh khác nhau thay vì cùng một kênh vì chúng đại diện cho những thông điệp của các loại con khác nhau. Trong kịch bản này, số lượng thông điệp kết quả thường cố định, trong khi đó Splitter tổng quát hơn giả định một số lượng phần tử biến đổi. Để phân biệt kiểu Splitter này, chúng tôi gọi nó là Splitter tĩnh. Một Splitter tĩnh về mặt chức năng tương đương với việc sử dụng một kênh phát sóng theo sau là một tập hợp các Bộ lọc Nội dung.
Một bộ chia tĩnh chia một thông điệp lớn thành một số lượng thông điệp nhỏ hơn cố định.

Trong một số trường hợp, việc trang bị cho các thông điệp con số hiệu thứ tự là hữu ích để cải thiện khả năng truy tìm thông điệp và đơn giản hóa nhiệm vụ của một Aggregator. Ngoài ra, cũng là một ý tưởng tốt khi trang bị cho mỗi thông điệp một tham chiếu đến thông điệp gốc (đã kết hợp) để kết quả xử lý từ các thông điệp riêng lẻ có thể được liên kết trở lại với thông điệp gốc. Tham chiếu này hoạt động như một Định danh Tương quan.
Nếu các bao bì tin nhắn được sử dụng (xem Bao bì Tin nhắn), mỗi tin nhắn mới nên được cung cấp với bao bì tin nhắn riêng để phù hợp với hạ tầng tin nhắn. Ví dụ, nếu hạ tầng yêu cầu một tin nhắn mang theo dấu thời gian trong tiêu đề tin nhắn, chúng tôi sẽ truyền dấu thời gian của tin nhắn gốc vào tiêu đề của từng tin nhắn.
| Ví dụ: Chia tách tài liệu đơn hàng XML trong C# Nhiều hệ thống nhắn tin sử dụng tin nhắn XML. Ví dụ, hãy giả định một đơn đặt hàng đến trông như sau: <order> <date>7/18/2002</date> <ordernumber>3825968</ordernumber> <customer> <id>12345</id> <name>Joe Doe</name> </customer> <orderitems> <item> <quantity>3.0</quantity> <itemno>W1234</itemno> <description>A Widget</description> </item> <item> <quantity>2.0</quantity> <itemno>G2345</itemno> <description>A Gadget</description> </item> </orderitems> </order> Chúng tôi muốn Splitter tách đơn hàng thành các mục đơn hàng riêng lẻ. Đối với tài liệu ví dụ, Splitter nên tạo ra hai thông điệp sau: <orderitem> <date>7/18/2002</date> <ordernumber>3825968</ordernumber> <customerid>12345</customerid> <quantity>3.0</quantity> <itemno>W1234</itemno> <description>A Widget</description> </orderitem> <orderitem> <date>7/18/2002</date> <ordernumber>3825968</ordernumber> <customerid>12345</customerid> <quantity>2.0</quantity> <itemno>G2345</itemno> <description>A Gadget</description> </orderitem> Mỗi thông điệp mặt hàng đơn hàng đang được làm giàu với ngày đặt hàng, số đơn hàng và ID khách hàng từ thông điệp đơn hàng gốc. Việc bao gồm ID khách hàng và ngày đặt hàng khiến thông điệp trở nên tự chứa và giữ cho người tiêu thụ thông điệp không phải lưu trữ ngữ cảnh qua các thông điệp riêng lẻ. Điều này rất quan trọng nếu các thông điệp được xử lý bởi các máy chủ không trạng thái. Việc thêm trường số đơn hàng là cần thiết cho việc tái tập hợp các mặt hàng sau này (xem Bộ tập hợp). Trong ví dụ này, chúng tôi giả định rằng thứ tự cụ thể của các mặt hàng bên trong một đơn hàng là không quan trọng cho việc hoàn thành đơn hàng, vì vậy chúng tôi không cần phải bao gồm số mặt hàng. Hãy xem mã Splitter trông như thế nào trong C#. [View full width] class XMLSplitter { protected MessageQueue inQueue; protected MessageQueue outQueue; public XMLSplitter(MessageQueue inQueue, MessageQueue outQueue) { this.inQueue = inQueue; this.outQueue = outQueue; inQueue.ReceiveCompleted += new Phần lớn mã tập trung vào việc xử lý XML. XMLSplitter sử dụng cùng một cấu trúc Người tiêu dùng theo sự kiện như các ví dụ định tuyến khác. Mỗi tin nhắn đến sẽ kích hoạt phương thức OnMessage, chuyển đổi nội dung tin nhắn thành một tài liệu XML để xử lý. Đầu tiên, chúng ta trích xuất các giá trị liên quan từ tài liệu đơn hàng. Sau đó, chúng ta lặp qua từng phần tử con <item>. Chúng ta làm điều này bằng cách xác định biểu thức XPath /order/orderitems/item. Một biểu thức XPath đơn giản rất giống với đường dẫn tệp; nó đi xuống cây tài liệu, khớp với các tên phần tử được chỉ định trong đường dẫn. Đối với mỗi <item>, chúng ta tạo thành một tài liệu XML mới, sao chép các trường từ đơn hàng và các nút con của phần tử đó. |
| Ví dụ: Chia tách tài liệu đơn hàng XML trong C# và XSL Thay vì phải thao tác thủ công với các nút và phần tử XML, chúng ta có thể tạo một tài liệu XSL để biến đổi XML đầu vào thành định dạng mong muốn và sau đó tạo các tin nhắn đầu ra từ tài liệu XML đã được biến đổi. Điều này dễ bảo trì hơn khi định dạng tài liệu có khả năng thay đổi. Tất cả những gì chúng ta cần làm là thay đổi quá trình biến đổi XSL mà không cần thay đổi mã C#. Mã mới sử dụng phương thức Transform được cung cấp bởi lớp XslTransform để chuyển đổi tài liệu đầu vào thành định dạng tài liệu trung gian. Định dạng tài liệu trung gian có một phần tử con, orderitem, cho mỗi thông điệp kết quả. Mã đơn giản duyệt qua tất cả các phần tử con và xuất bản một thông điệp cho mỗi phần tử. [View full width] class XSLSplitter { protected MessageQueue inQueue; protected MessageQueue outQueue; protected String styleSheet = "..\\..\\Order2OrderItem.xsl"; protected XslTransform xslt; public XSLSplitter(MessageQueue inQueue, MessageQueue outQueue) { this.inQueue = inQueue; this.outQueue = outQueue; xslt = new XslTransform(); xslt.Load(styleSheet, null); outQueue.Formatter = new ActiveXMessageFormatter(); inQueue.ReceiveCompleted += new Chúng tôi đọc tài liệu XSL từ một tệp riêng để dễ dàng chỉnh sửa và kiểm tra. Ngoài ra, điều này cho phép chúng tôi thay đổi hành vi của Bộ tách mà không cần biên dịch lại mã. [View full width] <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999 XSL là một ngôn ngữ khai báo, vì vậy rất khó để hiểu trừ khi bạn đã viết một số lượng hợp lý mã XSL cho chính mình (hoặc đã đọc một cuốn sách XSL tốt như [Tennison]). Biến đổi XSL này tìm kiếm bất kỳ sự xuất hiện nào của phần tử order (có một phần tử trong tài liệu của chúng tôi). Khi nó tìm thấy phần tử này, nó tạo ra một phần tử gốc mới cho tài liệu đầu ra (tất cả tài liệu XML đều phải có một phần tử gốc duy nhất) và tiếp tục xử lý tất cả các phần tử item bên trong phần tử orderitems của tài liệu đầu vào. XSL chỉ định một "mẫu" mới cho mỗi item được tìm thấy. Mẫu này sao chép các phần tử date, ordernumber và customerid từ phần tử order (mà là cha của cha của item) và sau đó thêm bất kỳ phần tử nào từ item. Tài liệu kết quả có một phần tử orderitem cho mỗi phần tử item trong tài liệu đầu vào. Điều này giúp cho mã C# dễ dàng lặp qua các phần tử và công bố chúng như các tin nhắn. Chúng tôi rất tò mò về cách hai triển khai sẽ hoạt động. Chúng tôi quyết định thực hiện một bài kiểm tra hiệu suất nhanh chóng, không khoa học. Chúng tôi đơn giản chỉ cần đưa 5.000 tin nhắn đơn hàng vào hàng đợi đầu vào, khởi động bộ phân chia, và đo thời gian cần thiết để 10.000 tin nhắn mục đến hàng đợi đầu ra. Chúng tôi thực hiện tất cả trong một chương trình duy nhất trên một máy sử dụng hàng đợi tin nhắn cục bộ. Chúng tôi đo được 7 giây cho bộ phân chia XML sử dụng DOM để trích xuất các phần tử và 5,3 giây cho bộ phân chia dựa trên XSL. Để thiết lập một tiêu chuẩn, một bộ xử lý giả lập tiêu thụ một tin nhắn từ hàng đợi đầu vào và phát hành cùng một tin nhắn hai lần trên hàng đợi đầu ra mất chưa đầy 2 giây cho 5.000 tin nhắn. Thời gian này bao gồm bộ xử lý giả lập tiêu thụ 5.000 tin nhắn và phát hành 10.000 tin nhắn, và bộ kiểm tra tiêu thụ 10.000 tin nhắn mà bộ xử lý đã phát hành. Vì vậy, có vẻ như việc thao tác XSL thì hiệu quả hơn một chút so với việc di chuyển các phần tử "bằng tay" (nếu chúng tôi trừ tiêu chuẩn, XSL nhanh hơn khoảng 35 phần trăm). Chúng tôi chắc chắn rằng bất kỳ chương trình nào cũng có thể được tinh chỉnh để đạt hiệu suất tối đa, nhưng thật thú vị khi thấy chúng chạy đồng thời. |
Một Splitter hữu ích để tách một thông điệp đơn thành một chuỗi các submessage có thể được xử lý riêng lẻ. Tương tự, một Danh sách Người Nhận hoặc Kênh Xuất Bản-Đăng Ký hữu ích để chuyển tiếp một thông điệp yêu cầu đến nhiều người nhận đồng thời nhằm nhận được nhiều phản hồi để lựa chọn. Trong hầu hết các kịch bản này, quá trình xử lý tiếp theo phụ thuộc vào việc xử lý thành công các submessage. Ví dụ, chúng ta muốn chọn giá thầu tốt nhất từ một số phản hồi của nhà cung cấp hoặc chúng ta muốn lập hóa đơn cho khách hàng về một đơn hàng sau khi tất cả các mặt hàng đã được lấy từ kho.
| Làm thế nào chúng ta kết hợp các kết quả của các thông điệp cá nhân nhưng có liên quan để chúng có thể được xử lý như một thể thống nhất? |
Bản chất không đồng bộ của một hệ thống nhắn tin khiến việc thu thập thông tin từ nhiều tin nhắn trở nên thách thức. Có bao nhiêu tin nhắn? Nếu chúng ta phát một tin nhắn đến một kênh phát, có thể chúng ta không biết có bao nhiêu người nhận đã lắng nghe kênh đó và do đó không thể biết có bao nhiêu phản hồi để mong đợi.
Ngay cả khi chúng ta sử dụng một Splitter, các tin nhắn phản hồi có thể không đến theo cùng một thứ tự mà chúng được tạo ra. Bởi vì các tin nhắn cá nhân có thể được định tuyến qua các đường mạng khác nhau, hạ tầng nhắn tin thường có thể đảm bảo việc giao nhận từng tin nhắn nhưng có thể không đảm bảo thứ tự mà các tin nhắn cá nhân được giao. Ngoài ra, các tin nhắn cá nhân có thể được xử lý bởi các bên khác nhau với tốc độ xử lý khác nhau. Do đó, các tin nhắn phản hồi có thể được giao nhận không đúng thứ tự (xem Resequencer để biết mô tả chi tiết hơn về vấn đề này).
Ngoài ra, hầu hết các hạ tầng nhắn tin hoạt động trong chế độ "đảm bảo, cuối cùng" về việc giao hàng, có nghĩa là các tin nhắn được đảm bảo sẽ được gửi đến người nhận đã định, nhưng không có đảm bảo về thời gian mà các tin nhắn sẽ được giao. Chúng ta nên chờ bao lâu cho một tin nhắn? Nếu chúng ta chờ quá lâu, có thể chúng ta sẽ trì hoãn việc xử lý tiếp theo. Nếu chúng ta quyết định tiến hành mà không có tin nhắn bị thiếu, chúng ta phải tìm cách làm việc với thông tin chưa đầy đủ. Dù vậy, chúng ta nên làm gì khi tin nhắn bị thiếu (hoặc các tin nhắn) cuối cùng đến? Trong một số trường hợp, chúng ta có thể xử lý tin nhắn đó riêng biệt, nhưng trong các trường hợp khác, việc này có thể dẫn đến việc xử lý trùng lặp. Ngoài ra, nếu chúng ta bỏ qua các tin nhắn đến muộn, chúng ta sẽ mất vĩnh viễn nội dung thông tin của chúng.
Tất cả những vấn đề này có thể làm phức tạp quá trình xử lý đồng thời nhiều tin nhắn liên quan. Sẽ dễ dàng hơn nhiều để triển khai logic kinh doanh nếu một thành phần riêng biệt có thể xử lý những phức tạp này và truyền một tin nhắn duy nhất cho quá trình kinh doanh tiếp theo mà phụ thuộc vào sự hiện diện của tất cả các tin nhắn con.
| Sử dụng một bộ lọc có trạng thái, một Bộ tổng hợp, để thu thập và lưu trữ các tin nhắn cá nhân cho đến khi nó nhận được một tập hợp hoàn chỉnh các tin nhắn liên quan. Sau đó, Bộ tổng hợp sẽ công bố một tin nhắn đơn lẻ được tinh chế từ các tin nhắn cá nhân.
|
Bộ tổng hợp là một bộ lọc đặc biệt (trong kiến trúc ống và bộ lọc) nhận một luồng thông điệp và xác định các thông điệp có mối tương quan. Khi một tập hợp hoàn chỉnh các thông điệp đã được nhận (sẽ có thêm thông tin sau về cách xác định khi nào một tập hợp là hoàn chỉnh), Bộ tổng hợp thu thập thông tin từ mỗi thông điệp có mối tương quan và phát hành một thông điệp duy nhất, được tổng hợp đến kênh đầu ra để xử lý thêm.
Khác với hầu hết các mẫu định tuyến trước đó, Bộ tổng hợp (Aggregator) là một thành phần có trạng thái. Các mẫu định tuyến đơn giản như Bộ định tuyến dựa trên nội dung (Content-Based Router) thường là không có trạng thái, có nghĩa là thành phần này xử lý các tin nhắn đến một cách tuần tự và không cần giữ bất kỳ thông tin nào giữa các tin nhắn. Sau khi xử lý một tin nhắn, thành phần như vậy ở trong trạng thái giống như trước khi tin nhắn đó đến. Do đó, chúng ta gọi thành phần như vậy là không có trạng thái. Bộ tổng hợp không thể không có trạng thái, vì nó cần phải lưu trữ mỗi tin nhắn đến cho đến khi tất cả các tin nhắn thuộc về nhau đã được nhận. Sau đó, nó phải chắt lọc thông tin liên quan đến mỗi tin nhắn vào tin nhắn tổng hợp. Bộ tổng hợp không nhất thiết phải lưu trữ mỗi tin nhắn đến một cách hoàn chỉnh. Ví dụ, nếu chúng ta đang xử lý các lượt đấu giá đến, có thể chúng ta chỉ cần giữ lại mức giá cao nhất và ID của người đấu giá liên quan, chứ không phải lịch sử của tất cả các tin nhắn đấu giá riêng lẻ. Tuy nhiên, Bộ tổng hợp vẫn phải lưu trữ một số thông tin giữa các tin nhắn và do đó là có trạng thái.
Khi thiết kế một Trình tổng hợp, chúng ta cần chỉ định các thuộc tính sau:
Tương quan: Những tin nhắn nào đến cùng nhau?
Điều kiện hoàn thiện: Khi nào chúng ta sẵn sàng để công bố thông điệp kết quả?
Thuật toán Tổng hợp: Chúng ta kết hợp các tin nhắn được nhận thành một tin nhắn kết quả duy nhất như thế nào?
Sự tương quan thường được đạt được qua loại tin nhắn đến hoặc một Bộ định danh Tương quan rõ ràng. Các lựa chọn phổ biến cho điều kiện đầy đủ và thuật toán tập hợp được mô tả trên trang 272.
Do tính chất dựa trên sự kiện của một hệ thống nhắn tin, Bộ tổng hợp có thể nhận được các tin nhắn liên quan vào bất kỳ thời điểm nào và theo bất kỳ thứ tự nào. Để liên kết các tin nhắn, Bộ tổng hợp duy trì một danh sách các tổng hợp đang hoạt động, tức là các tổng hợp mà Bộ tổng hợp đã nhận được một số tin nhắn. Khi Bộ tổng hợp nhận được một tin nhắn mới, nó cần kiểm tra xem tin nhắn đó có phải là một phần của tổng hợp đã tồn tại hay không. Nếu không có tổng hợp nào liên quan đến tin nhắn này tồn tại, Bộ tổng hợp giả định rằng đây là tin nhắn đầu tiên của một tập hợp và tạo ra một tổng hợp mới. Sau đó, nó thêm tin nhắn vào tổng hợp mới. Nếu một tổng hợp đã tồn tại, Bộ tổng hợp đơn giản chỉ cần thêm tin nhắn vào tổng hợp đó.
Sau khi thêm thông điệp, Bộ tổng hợp đánh giá điều kiện hoàn chỉnh cho tổng hợp bị ảnh hưởng. Nếu điều kiện được đánh giá là đúng, một thông điệp tổng hợp mới được hình thành từ các thông điệp tích lũy trong tổng hợp và được công bố ra kênh đầu ra. Nếu điều kiện hoàn chỉnh được đánh giá là sai, không có thông điệp nào được công bố và Bộ tổng hợp giữ cho tổng hợp vẫn hoạt động để các thông điệp bổ sung có thể đến.
Sơ đồ sau đây minh họa chiến lược này. Trong kịch bản đơn giản này, các thông điệp đến được liên kết thông qua một Bộ nhận diện tương quan. Khi thông điệp đầu tiên có giá trị Bộ nhận diện tương quan là 100 đến, Bộ tổng hợp khởi tạo một tổng hợp mới và lưu trữ thông điệp đó bên trong tổng hợp đó. Trong ví dụ của chúng ta, điều kiện hoàn chỉnh yêu cầu tối thiểu ba thông điệp, vì vậy tổng hợp vẫn chưa hoàn chỉnh. Khi thông điệp thứ hai có giá trị Bộ nhận diện tương quan là 100 đến, Bộ tổng hợp thêm nó vào tổng hợp đã tồn tại. Một lần nữa, tổng hợp vẫn chưa hoàn chỉnh. Thông điệp thứ ba chỉ định một giá trị Bộ nhận diện tương quan khác, 101. Kết quả là, Bộ tổng hợp bắt đầu một tổng hợp mới cho giá trị đó. Thông điệp thứ tư liên quan đến tổng hợp đầu tiên (nhận diện 100). Sau khi thêm thông điệp này, tổng hợp chứa ba thông điệp, vì vậy điều kiện hoàn chỉnh giờ đã được đáp ứng. Do đó, Bộ tổng hợp tính toán thông điệp tổng hợp, đánh dấu tổng hợp là hoàn thành và phát hành thông điệp kết quả.
Nội bộ của Bộ tổng hợp

Chiến lược này tạo ra một tổng hợp mới mỗi khi Bộ tổng hợp nhận được một thông điệp không thể liên kết với một tổng hợp hiện có. Do đó, Bộ tổng hợp không cần biết trước về các tổng hợp mà nó có thể tạo ra. Do đó, chúng tôi gọi biến thể này là một Bộ tổng hợp tự khởi động.
Tùy thuộc vào chiến lược tổng hợp, Bộ tổng hợp có thể gặp phải tình huống rằng một tin nhắn đến thuộc về một tổng hợp đã được đóng lại - nghĩa là, tin nhắn đến đến sau khi tin nhắn tổng hợp đã được công bố. Để tránh việc khởi động một tổng hợp mới, Bộ tổng hợp phải giữ một danh sách các tổng hợp đã bị đóng lại. Danh sách này nên được xóa định kỳ để không phát triển vô hạn. Tuy nhiên, chúng ta cần cẩn thận không xóa các tổng hợp đã đóng lại quá sớm vì điều đó sẽ khiến bất kỳ tin nhắn nào bị trì hoãn bắt đầu một tổng hợp mới. Vì chúng ta không cần lưu trữ toàn bộ tổng hợp, chỉ cần biết rằng nó đã bị đóng lại, chúng ta có thể lưu trữ danh sách các tổng hợp đã đóng lại một cách rất hiệu quả và xây dựng một khoảng an toàn đủ vào thuật toán xóa. Chúng ta cũng có thể sử dụng Thời hạn Tin nhắn để bỏ qua các tin nhắn đã bị trì hoãn trong một khoảng thời gian không hợp lý.
Để tăng cường tính ổn định của giải pháp tổng thể, chúng ta cũng có thể cho phép Bộ tổng hợp lắng nghe trên một kênh điều khiển cụ thể cho phép thực hiện việc xóa bỏ tất cả các tập hợp hoạt động hoặc một tập hợp cụ thể. Tính năng này có thể hữu ích nếu chúng ta muốn phục hồi từ một điều kiện lỗi mà không cần khởi động lại thành phần Bộ tổng hợp. Cùng với đó, cho phép Bộ tổng hợp công bố danh sách các tập hợp hoạt động đến một kênh đặc biệt theo yêu cầu có thể là một tính năng gỡ lỗi rất hữu ích. Cả hai chức năng đều là những ví dụ điển hình về loại tính năng thường được tích hợp vào một Bus điều khiển.
Có một số chiến lược cho các điều kiện hoàn thiện của bộ tổng hợp. Các chiến lược hiện có chủ yếu phụ thuộc vào việc chúng ta có biết số lượng tin nhắn mà chúng ta mong đợi hay không. Bộ tổng hợp có thể biết số lượng tin nhắn con mà nó mong đợi vì nó nhận được một bản sao của tin nhắn tổng hợp gốc hoặc vì mỗi tin nhắn riêng lẻ chứa tổng số đếm (như đã mô tả trong ví dụ về Bộ phân tách). Tùy thuộc vào việc Bộ tổng hợp biết bao nhiêu về dòng tin nhắn, các chiến lược phổ biến nhất như sau:
Chờ Tất Cả: Chờ cho đến khi tất cả các phản hồi được nhận. Kịch bản này có khả năng cao nhất trong ví dụ về thứ tự mà chúng ta đã thảo luận trước đó. Một thứ tự không đầy đủ có thể không có ý nghĩa. Vì vậy, nếu không nhận được tất cả các mục trong một khoảng thời gian giới hạn nhất định, một điều kiện lỗi nên được đưa ra bởi Bộ Tổng Hợp. Cách tiếp cận này có thể mang lại cho chúng ta cơ sở tốt nhất để ra quyết định, nhưng cũng có thể là chậm nhất và dễ tổn thương nhất (hơn nữa, chúng ta cần biết có bao nhiêu tin nhắn mong đợi). Một tin nhắn bị thiếu hoặc bị trì hoãn sẽ ngăn cản việc xử lý tiếp theo của toàn bộ tập hợp. Giải quyết các điều kiện lỗi như vậy có thể là một vấn đề phức tạp trong các hệ thống không chặt chẽ và bất đồng bộ vì luồng tin nhắn bất đồng bộ làm khó khăn cho việc phát hiện đáng tin cậy các điều kiện lỗi (chúng ta nên chờ bao lâu trước khi một tin nhắn được coi là "thiếu"?). Một cách để xử lý các tin nhắn bị thiếu là yêu cầu lại tin nhắn. Tuy nhiên, cách tiếp cận này yêu cầu Bộ Tổng Hợp phải biết nguồn gốc của tin nhắn, điều này có thể tạo ra các phụ thuộc bổ sung giữa Bộ Tổng Hợp và các thành phần khác.
Hết thời gian chờ: Chờ đợi trong một khoảng thời gian xác định để nhận phản hồi và sau đó đưa ra quyết định bằng cách đánh giá các phản hồi nhận được trong giới hạn thời gian đó. Nếu không nhận được phản hồi nào, hệ thống có thể báo cáo một ngoại lệ hoặc thử lại. Quy tắc này hữu ích nếu các phản hồi đến được chấm điểm và chỉ thông điệp (hoặc một số ít thông điệp) có điểm cao nhất được sử dụng. Cách tiếp cận này phổ biến trong các kịch bản "đấu thầu".
Cách tốt nhất đầu tiên: Chỉ chờ đến khi nhận được phản hồi đầu tiên (nhanh nhất) và bỏ qua tất cả các phản hồi khác. Cách tiếp cận này là nhanh nhất nhưng bỏ qua rất nhiều thông tin. Nó có thể thực tiễn trong một kịch bản đấu thầu hoặc báo giá, nơi thời gian phản hồi là rất quan trọng.
Thời gian chờ với sự ghi đè: Chờ một khoảng thời gian xác định hoặc cho đến khi nhận được một tin nhắn với điểm số tối thiểu đã thiết lập. Trong kịch bản này, chúng tôi sẵn sàng hủy bỏ sớm nếu tìm thấy một phản hồi rất thuận lợi; nếu không, chúng tôi sẽ tiếp tục cho đến khi thời gian hết. Nếu không tìm thấy người chiến thắng rõ ràng vào thời điểm đó, sẽ có việc sắp xếp thứ tự giữa tất cả các tin nhắn đã nhận cho đến nay.
Sự Kiện Bên Ngoài: Đôi khi sự tổng hợp được kết thúc bởi sự xuất hiện của một sự kiện kinh doanh bên ngoài. Ví dụ, trong ngành tài chính, sự kết thúc của ngày giao dịch có thể báo hiệu sự kết thúc của một quá trình tổng hợp các báo giá vào. Việc sử dụng một bộ hẹn giờ cố định cho sự kiện như vậy giảm tính linh hoạt vì nó không cung cấp nhiều biến đổi. Ngoài ra, một sự kiện kinh doanh được chỉ định dưới dạng Thông điệp Sự kiện cho phép kiểm soát trung tâm hệ thống. Trình Tổng hợp có thể lắng nghe Thông điệp Sự kiện trên một kênh điều khiển đặc biệt hoặc nhận một thông điệp được định dạng đặc biệt cho biết sự kết thúc của quá trình tổng hợp.
Liên quan chặt chẽ đến việc chọn điều kiện đầy đủ là việc chọn thuật toán tổng hợp. Các chiến lược sau đây thường được sử dụng để cô đọng nhiều thông điệp thành một thông điệp duy nhất:
Chọn câu trả lời "tốt nhất": Cách tiếp cận này giả định rằng có một câu trả lời tốt nhất, chẳng hạn như giá thầu thấp nhất cho một mặt hàng giống hệt. Điều này cho phép Aggregator đưa ra quyết định và chỉ chuyển tiếp "thông điệp tốt nhất". Tuy nhiên, trong thực tế, tiêu chí lựa chọn hiếm khi đơn giản như vậy. Chẳng hạn, giá thầu tốt nhất cho một mặt hàng có thể phụ thuộc vào thời gian giao hàng, số lượng mặt hàng có sẵn, việc nhà cung cấp có nằm trong danh sách nhà cung cấp ưu tiên hay không, và các yếu tố khác.
Tóm tắt dữ liệu: Một Bộ tổng hợp có thể được sử dụng để giảm lưu lượng tin nhắn từ một nguồn có lưu lượng cao. Trong những trường hợp này, có thể hợp lý khi tính toán một giá trị trung bình của các tin nhắn riêng lẻ hoặc cộng các trường số từ mỗi tin nhắn vào trong một tin nhắn duy nhất. Điều này hoạt động tốt nhất khi mỗi tin nhắn đại diện cho một giá trị số, ví dụ, số lượng đơn hàng đã nhận.
Thu thập dữ liệu để đánh giá sau: Không phải lúc nào cũng có thể cho một Người tổng hợp quyết định cách chọn câu trả lời tốt nhất. Trong những trường hợp đó, vẫn có ý nghĩa khi sử dụng một Người tổng hợp để thu thập các tin nhắn cá nhân và kết hợp chúng thành một tin nhắn duy nhất. Tin nhắn này có thể đơn giản là một sự tổng hợp dữ liệu của các tin nhắn cá nhân. Quyết định tổng hợp có thể được thực hiện sau bởi một thành phần riêng biệt hoặc một con người.
Trong nhiều trường hợp, chiến lược tổng hợp được điều khiển bởi các tham số. Ví dụ, một chiến lược chờ đợi một khoảng thời gian nhất định có thể được cấu hình với thời gian chờ tối đa. Tương tự, nếu chiến lược là chờ cho đến khi một đề xuất vượt quá một ngưỡng cụ thể, chúng tôi thường sẽ thông báo trước cho Bộ tổng hợp về ngưỡng mong muốn. Nếu những tham số này có thể cấu hình tại thời gian chạy, Bộ tổng hợp có thể có một đầu vào bổ sung để nhận các thông điệp điều khiển, chẳng hạn như các cài đặt tham số này. Các thông điệp điều khiển cũng có thể chứa thông tin như số lượng thông điệp tương quan mà mong đợi, điều này có thể giúp Bộ tổng hợp thực hiện các điều kiện hoàn thành hiệu quả hơn. Trong kịch bản như vậy, Bộ tổng hợp không chỉ đơn giản là bắt đầu một tổng hợp mới khi thông điệp đầu tiên đến, mà thay vào đó nhận thông tin trước liên quan đến một chuỗi thông điệp dự kiến. Thông tin này có thể là một bản sao của thông điệp yêu cầu gốc (ví dụ: thông điệp Scatter-Gather) được bổ sung bởi bất kỳ thông tin tham số cần thiết nào. Bộ tổng hợp sau đó phân bổ một tổng hợp mới và lưu trữ thông tin tham số cùng với tổng hợp đó. Khi các thông điệp cá nhân đến, chúng được liên kết với tổng hợp tương ứng. Chúng tôi gọi sự biến thể này là Bộ tổng hợp được khởi tạo, đối lập với Bộ tổng hợp tự khởi động. Cấu hình này, rõ ràng, chỉ có thể thực hiện nếu chúng tôi có quyền truy cập vào thông điệp gốc, điều này không phải lúc nào cũng xảy ra.

Các bộ tổng hợp rất hữu ích trong nhiều ứng dụng. Bộ tổng hợp thường được kết hợp với bộ tách hoặc danh sách người nhận để tạo thành một mẫu tổng hợp. Xem Bộ xử lý tin nhắn hợp thành và Phân tán - Tập hợp để biết mô tả chi tiết hơn về các mẫu tổng hợp này.
| Ví dụ: Môi giới cho vay Ví dụ về thông điệp kết hợp trong Chương 9, "Chi tiết: Thông điệp kết hợp," sử dụng một Bộ tổng hợp để chọn ra báo giá khoản vay tốt nhất từ các thông điệp báo giá khoản vay được trả về bởi các ngân hàng. Ví dụ về môi giới khoản vay sử dụng một Bộ tổng hợp đã được khởi tạo danh sách người nhận thông báo cho Bộ tổng hợp về số lượng thông điệp báo giá mà nó mong đợi. Chi tiết này cho thấy các triển khai của Bộ tổng hợp trong Java, C# và TIBCO. |
| Ví dụ: Bộ tổng hợp như Làm cảm biến tin nhắn thiếu hụt Joe Walnes đã cho chúng tôi thấy một cách sử dụng sáng tạo của một Aggregator. Hệ thống của anh ấy gửi một thông điệp qua một chuỗi các thành phần, mà không may là khá không đáng tin cậy. Ngay cả việc sử dụng Giao Hàng Đảm Bảo cũng không khắc phục được vấn đề này vì các hệ thống tự mình thường gặp sự cố sau khi tiêu thụ một thông điệp. Do các ứng dụng không phải là Khách Hàng Giao Dịch, thông điệp đang được xử lý sẽ bị mất. Để giúp khắc phục tình huống này, Joe định tuyến một thông điệp đến bằng cách đi qua hai đường song song: một lần thông qua các thành phần cần thiết nhưng không đáng tin cậy và một lần vòng qua các thành phần bằng cách sử dụng Giao Hàng Đảm Bảo. Một Aggregator sẽ kết hợp lại các thông điệp từ hai đường này (xem hình). Một Bộ Tập Hợp với Thời Gian Chờ Phát Hiện Tin Nhắn Thiếu
Bộ tổng hợp sử dụng một điều kiện hoàn thành "Thời gian chờ với sự ghi đè", có nghĩa là bộ tổng hợp sẽ hoàn thành nếu hoặc thời gian chờ được đạt đến hoặc hai tin nhắn liên quan đã được nhận. Thuật toán tổng hợp phụ thuộc vào điều kiện nào được thỏa mãn trước. Nếu hai tin nhắn được nhận, tin nhắn đã xử lý sẽ được chuyển tiếp mà không có sự thay đổi. Nếu sự kiện thời gian chờ xảy ra, chúng ta biết rằng một trong các thành phần đã bị lỗi và "đã ăn" tin nhắn. Kết quả là, chúng tôi hướng dẫn bộ tổng hợp phát hành một tin nhắn lỗi để cảnh báo các operator rằng một trong các thành phần đã gặp sự cố. Rất tiếc, các thành phần phải được khởi động lại thủ công, nhưng một cấu hình tinh vi hơn có thể khởi động lại thành phần và gửi lại bất kỳ tin nhắn nào đã bị mất. |
| Ví dụ: Bộ tổng hợp trong JMS Ví dụ này cho thấy việc triển khai một Bộ Tổng Hợp (Aggregator) sử dụng API Dịch Vụ Tin Nhắn Java (JMS). Bộ Tổng Hợp nhận các tin nhắn đấu giá trên một kênh, tổng hợp tất cả các đấu giá liên quan và công bố một tin nhắn với giá thầu thấp nhất trên một kênh khác. Các đấu giá được liên kết thông qua một thuộc tính ID Đấu Giá, đóng vai trò như một Định Danh Liên Kết cho các tin nhắn. Chiến lược tổng hợp là nhận tối thiểu ba đấu giá. Bộ Tổng Hợp tự khởi động và không yêu cầu khởi tạo bên ngoài. Ví dụ về Bộ tổng hợp chọn giá thầu thấp nhất.
Giải pháp bao gồm các lớp chính sau đây (xem hình dưới đây):
Biểu đồ Lớp Tập Hợp Đấu Giá
Cốt lõi của giải pháp là lớp Aggregator. Lớp này yêu cầu hai Nơi đến JMS: một cho đầu vào và một cho đầu ra. Nơi đến là sự trừu tượng của JMS cho một Hàng đợi (Kênh Điểm-đến-Điểm) hoặc một Chủ đề (Kênh Xuất bản-Đăng ký). Sự trừu tượng này cho phép chúng ta viết mã JMS độc lập với loại kênh. Tính năng này có thể rất hữu ích cho việc thử nghiệm và gỡ lỗi. Ví dụ, trong quá trình thử nghiệm, chúng ta có thể sử dụng các chủ đề xuất bản-đăng ký để dễ dàng "nghe" lưu lượng tin nhắn. Khi chúng ta chuyển sang sản xuất, có thể chúng ta muốn chuyển sang hàng đợi. [View full width] public class Aggregator implements MessageListener { static final String PROP_CORRID = "AuctionID"; Map activeAggregates = new HashMap(); Destination inputDest = null; Destination outputDest = null; Session session = null; MessageConsumer in = null; MessageProducer out = null; public Aggregator (Destination inputDest, Destination Bộ tổng hợp là một người tiêu dùng theo sự kiện và triển khai giao diện MessageListener, điều này yêu cầu nó phải thực hiện phương thức onMessage. Bởi vì Bộ tổng hợp là người lắng nghe tin nhắn cho MessageConsumer, mỗi khi một tin nhắn mới đến đích của người tiêu dùng, JMS sẽ gọi phương thức onMessage. Đối với mỗi tin nhắn đến, Bộ tổng hợp sẽ trích xuất ID tương quan (được lưu dưới dạng thuộc tính tin nhắn) và kiểm tra xem có một tổng hợp đang hoạt động cho ID tương quan này hay không. Nếu không tìm thấy tổng hợp, Bộ tổng hợp sẽ khởi tạo một thể hiện mới của AuctionAggregate. Sau đó, Bộ tổng hợp kiểm tra xem tổng hợp có vẫn còn hoạt động (tức là chưa hoàn thành) hay không. Nếu tổng hợp không còn hoạt động, nó sẽ loại bỏ tin nhắn đến. Nếu tổng hợp vẫn còn hoạt động, nó sẽ thêm tin nhắn vào tổng hợp và kiểm tra xem điều kiện kết thúc đã được thực hiện hay chưa. Nếu có, nó sẽ lấy mục thầu tốt nhất và công bố nó. Mã của Aggregator rất tổng quát và chỉ phụ thuộc vào ứng dụng ví dụ cụ thể này trong hai dòng mã. Đầu tiên, mã giả định rằng ID tương quan được lưu trữ trong thuộc tính tin nhắn AuctionID. Thứ hai, nó tạo ra một thể hiện của lớp AuctionAggregate. Chúng ta có thể tránh tham chiếu này nếu sử dụng một nhà máy trả về một đối tượng loại Aggregate và nội bộ tạo ra một thể hiện của loại AuctionAggregate. Vì đây là một cuốn sách về tích hợp doanh nghiệp và không phải về thiết kế hướng đối tượng, chúng tôi đã giữ mọi thứ đơn giản và để cho sự phụ thuộc này trôi qua. Lớp AuctionAggregate cung cấp triển khai cho giao diện Aggregate. Giao diện này khá đơn giản, chỉ định nghĩa ba phương thức: một để thêm một tin nhắn mới (addMessage), một để xác định xem tập hợp có hoàn chỉnh hay không (isComplete), và một để nhận kết quả tốt nhất (getBestMessage). public interface Aggregate { public void addMessage(Message message); public boolean isComplete(); public Message getResultMessage(); } Thay vì thực hiện chiến lược tổng hợp bên trong lớp AuctionAggregate, chúng tôi quyết định tạo một lớp riêng biệt là Auction thực hiện chiến lược tổng hợp nhưng không phụ thuộc vào API JMS. public class Auction { ArrayList bids = new ArrayList(); public void addBid(Bid bid) { bids.add(bid); System.out.println(bids.size() + " Bids in auction."); } public boolean isComplete() { return (bids.size() >= 3); } public Bid getBestBid() { Bid bestBid = null; Iterator iter = bids.iterator(); if (iter.hasNext()) bestBid = (Bid) iter.next(); while (iter.hasNext()) { Bid b = (Bid) iter.next(); if (b.getPrice() < bestBid.getPrice()) { bestBid = b; } } return bestBid; } } Lớp Auction thực sự khá đơn giản. Nó cung cấp ba phương thức tương tự như giao diện Aggregate, nhưng các chữ ký phương thức khác nhau ở chỗ chúng sử dụng lớp Bid kiểu mạnh thay vì lớp Message đặc trưng của JMS. Đối với ví dụ này, điều kiện hoàn thiện rất đơn giản, chỉ cần chờ đợi cho đến khi ba giá thầu được nhận. Tuy nhiên, việc tách biệt chiến lược tổng hợp khỏi lớp Auction và API JMS giúp dễ dàng nâng cao lớp Auction để tích hợp logic phức tạp hơn. Lớp AuctionAggregate hoạt động như một Bộ chuyển đổi [GoF] giữa giao diện Aggregate và lớp Auction. Một bộ chuyển đổi là một lớp chuyển đổi giao diện của một lớp thành một giao diện khác. [View full width] public class AuctionAggregate implements Aggregate { static String PROP_AUCTIONID = "AuctionID"; static String ITEMID = "ItemID"; static String VENDOR = "Vendor"; static String PRICE = "Price"; private Session session; private Auction auction; public AuctionAggregate(Session session) { this.session = session; auction = new Auction(); } public void addMessage(Message message) { Bid bid = null; if (message instanceof MapMessage) { try { MapMessage mapmsg = (MapMessage)message; String auctionID = mapmsg.getStringProperty Sơ đồ tuần tự sau tóm tắt sự tương tác giữa các lớp: Sơ đồ tuần tự của tổng hợp đấu giá
Ví dụ đơn giản này giả định rằng ID phiên đấu giá là duy nhất trên toàn cầu. Điều này cho phép chúng ta không phải lo lắng về việc dọn dẹp danh sách đấu giá mở, chúng ta chỉ cần để nó phát triển. Trong một ứng dụng thực tế, chúng ta sẽ cần quyết định khi nào nên xóa các bản ghi đấu giá cũ để tránh rò rỉ bộ nhớ. Bởi vì đoạn mã này chỉ tham chiếu đến các Điểm đến JMS, chúng ta có thể chạy nó với cả Topics hoặc Queues. Trong một môi trường sản xuất, ứng dụng này có thể có nhiều khả năng sử dụng một Kênh Điểm-đến-Điểm (tương đương với một JMS Queue) vì chỉ nên có một người nhận duy nhất cho một đề nghị, đó là Aggregator. Như đã mô tả trong Kênh Xuất Bản-Đăng Ký, các topic có thể đơn giản hóa việc kiểm tra và gỡ lỗi. Rất dễ để thêm một trình lắng nghe bổ sung vào một topic mà không ảnh hưởng đến luồng tin nhắn. Khi gỡ lỗi một ứng dụng nhắn tin, thường rất hữu ích để chạy một cửa sổ trình lắng nghe riêng biệt theo dõi tất cả các tin nhắn được trao đổi giữa bất kỳ người tham gia nào. Nhiều triển khai JMS cho phép bạn sử dụng ký tự đại diện trong tên topic để một trình lắng nghe có thể đơn giản đăng ký tất cả các topic bằng cách chỉ định tên topic là *. Thật tiện lợi khi có một công cụ trình lắng nghe đơn giản hiển thị tất cả các tin nhắn di chuyển trên một topic và cũng ghi lại các tin nhắn vào một tệp để phân tích sau này. |
Một Bộ định tuyến Tin nhắn có thể định tuyến các tin nhắn từ một kênh sang các kênh khác dựa trên nội dung tin nhắn hoặc các tiêu chí khác. Bởi vì các tin nhắn riêng lẻ có thể đi theo các lộ trình khác nhau, một số tin nhắn có khả năng vượt qua các bước xử lý sớm hơn so với những tin nhắn khác, dẫn đến việc các tin nhắn bị xáo trộn thứ tự. Tuy nhiên, một số bước xử lý tiếp theo lại yêu cầu xử lý tin nhắn theo thứ tự, ví dụ, để duy trì tính toàn vẹn tham chiếu.
| Làm thế nào chúng ta có thể sắp xếp lại một luồng tin nhắn có liên quan nhưng không theo thứ tự về đúng thứ tự? |
Giải pháp hiển nhiên cho vấn đề ngoài trình tự là giữ cho các tin nhắn theo trình tự ngay từ đầu. Việc giữ mọi thứ theo thứ tự thực ra dễ hơn việc sắp xếp lại chúng. Đó là lý do tại sao nhiều thư viện đại học thích ngăn cản độc giả đặt sách trở lại vào kệ sách (có thứ tự). Bằng cách kiểm soát quá trình chèn, thứ tự chính xác (hầu như) được đảm bảo tại bất kỳ thời điểm nào. Nhưng việc giữ mọi thứ theo trình tự khi xử lý một giải pháp nhắn tin bất đồng bộ có thể khó khăn như việc thuyết phục một thiếu niên rằng việc giữ cho phòng của cô ấy gọn gàng thực sự là cách tiếp cận hiệu quả hơn.
Một cách phổ biến mà mọi thứ bị mất trật tự là khi các thông điệp khác nhau đi qua các con đường xử lý khác nhau. Hãy xem một ví dụ đơn giản. Giả sử chúng ta đang xử lý một chuỗi thông điệp được đánh số. Nếu tất cả các thông điệp có số chẵn phải trải qua một phép biến đổi đặc biệt, trong khi tất cả các thông điệp có số lẻ có thể được xử lý ngay lập tức, thì các thông điệp có số lẻ sẽ xuất hiện trên kênh đầu ra ngay lập tức trong khi các thông điệp có số chẵn sẽ phải xếp hàng chờ biến đổi. Nếu phép biến đổi diễn ra khá chậm, tất cả các thông điệp lẻ có thể xuất hiện trên kênh đầu ra trước khi một thông điệp chẵn nào đó được xử lý, khiến chuỗi hoàn toàn bị đảo lộn.
Tin nhắn bị lộn xộn

Để tránh việc các thông điệp bị rối loạn thứ tự, chúng ta có thể giới thiệu một cơ chế vòng lặp (xác nhận) đảm bảo rằng chỉ một thông điệp tại một thời điểm đi qua hệ thống, nghĩa là thông điệp tiếp theo sẽ không được gửi đi cho đến khi thông điệp trước đó hoàn tất xử lý. Cách tiếp cận thận trọng này sẽ giải quyết được vấn đề, nhưng có hai nhược điểm đáng kể. Đầu tiên, nó có thể làm chậm hệ thống một cách đáng kể. Nếu chúng ta có một số lượng lớn các đơn vị xử lý song song, chúng ta sẽ sử dụng rất ít công suất xử lý. Thực tế, trong nhiều trường hợp, lý do cho việc xử lý song song là nhằm tăng cường hiệu suất, vì vậy việc giới hạn lưu lượng giao thông chỉ cho một thông điệp một lúc sẽ hoàn toàn phủ nhận mục đích của giải pháp. Vấn đề thứ hai là cách tiếp cận này đòi hỏi chúng ta phải kiểm soát các thông điệp được gửi vào các đơn vị xử lý. Tuy nhiên, chúng ta thường thấy mình ở đầu nhận của một luồng thông điệp không theo thứ tự mà không có quyền kiểm soát đối với nguồn gốc của thông điệp.
Một Aggregator có thể nhận một luồng tin nhắn, xác định các tin nhắn liên quan và tổng hợp chúng thành một tin nhắn duy nhất dựa trên một số chiến lược. Trong quá trình này, Aggregator cũng phải đối mặt với thực tế rằng các tin nhắn cá nhân có thể đến vào bất kỳ thời điểm nào và theo bất kỳ thứ tự nào. Aggregator giải quyết vấn đề này bằng cách lưu trữ các tin nhắn cho đến khi tất cả các tin nhắn liên quan đến nơi trước khi nó công bố một tin nhắn kết quả.
| Sử dụng bộ lọc trạng thái, một bộ tái sắp xếp, để thu thập và sắp xếp lại các tin nhắn để chúng có thể được xuất bản lên kênh đầu ra theo thứ tự nhất định.
|
Bộ tái sắp xếp có thể nhận một luồng tin nhắn có thể không đến theo thứ tự. Nó lưu trữ các tin nhắn ngoài thứ tự trong một bộ đệm nội bộ cho đến khi có một chuỗi hoàn chỉnh, sau đó xuất bản các tin nhắn lên kênh đầu ra theo thứ tự đúng. Việc kênh đầu ra giữ nguyên thứ tự là rất quan trọng để các tin nhắn đảm bảo đến đúng thứ tự ở thành phần tiếp theo. Giống như hầu hết các bộ định tuyến khác, bộ tái sắp xếp thường không chỉnh sửa nội dung tin nhắn.
Để Resequencer hoạt động, mỗi tin nhắn phải có một số thứ tự duy nhất (xem Chuỗi Tin Nhắn). Số thứ tự này khác với định danh tin nhắn hoặc Định danh Tương quan. Định danh tin nhắn là một thuộc tính đặc biệt xác định duy nhất mỗi tin nhắn. Tuy nhiên, trong hầu hết các trường hợp, các định danh tin nhắn không thể so sánh; chúng về cơ bản là giá trị ngẫu nhiên và thường không phải là số. Ngay cả khi chúng xảy ra là các giá trị số, thì việc sử dụng lại ngữ nghĩa của số thứ tự trên một phần tử định danh tin nhắn đã tồn tại thường là một ý tưởng tồi. Định danh Tương quan được thiết kế để khớp các tin nhắn đến với các yêu cầu đầu ra ban đầu (xem Yêu cầu-Trả lời). Yêu cầu duy nhất cho Định danh Tương quan là sự duy nhất; chúng không cần phải là số hoặc theo thứ tự. Vì vậy, nếu chúng ta cần bảo tồn thứ tự của một loạt tin nhắn, chúng ta nên định nghĩa một trường riêng biệt để theo dõi vị trí của mỗi tin nhắn trong chuỗi. Thông thường, trường này có thể là một phần của tiêu đề tin nhắn.
Việc tạo ra các số thứ tự có thể tốn thời gian hơn so với việc tạo ra các định danh duy nhất. Thường thì, các định danh duy nhất có thể được tạo ra theo cách phân tán bằng cách kết hợp thông tin vị trí duy nhất (ví dụ: địa chỉ MAC của NIC) và thời gian hiện tại. Hầu hết các thuật toán GUID (định danh toàn cầu duy nhất) hoạt động theo cách này. Để tạo ra các số liên tiếp, chúng ta thường cần một bộ đếm duy nhất để gán số trong toàn bộ hệ thống. Trong hầu hết các trường hợp, việc các số chỉ đơn giản tăng dần là không đủ, mà chúng cũng cần phải là liên tiếp. Nếu không, sẽ rất khó để xác định các tin nhắn bị thiếu. Nếu chúng ta không cẩn thận, bộ tạo số thứ tự này có thể dễ dàng trở thành một nút thắt cho dòng tin nhắn. Nếu các tin nhắn cá nhân là kết quả của việc sử dụng một Splitter, thì tốt nhất là kết hợp việc đánh số ngay vào trong Splitter. Mẫu Trường Danh Tính trong [EAA] chứa một cuộc thảo luận hữu ích về cách tạo ra khóa và số thứ tự.
Số thứ tự đảm bảo rằng Bộ sắp xếp lại có thể phát hiện các thông điệp đến không đúng thứ tự. Nhưng Bộ sắp xếp lại nên làm gì khi một thông điệp đến không đúng thứ tự? Một thông điệp đến không đúng thứ tự ngụ ý rằng một thông điệp có số thứ tự cao hơn đến trước một thông điệp có số thứ tự thấp hơn. Bộ sắp xếp lại phải lưu trữ thông điệp có số thứ tự cao hơn cho đến khi nó nhận được tất cả các thông điệp "thiếu" có số thứ tự thấp hơn. Trong khi đó, nó có thể nhận được các thông điệp đến không đúng thứ tự khác nữa, cũng cần phải được lưu trữ. Khi bộ đệm chứa một chuỗi liên tiếp các thông điệp, Bộ sắp xếp lại gửi chuỗi này đến kênh xuất ra và sau đó xóa các thông điệp đã gửi khỏi bộ đệm.
Hoạt động nội bộ của máy tái cấu trúc gen

Trong ví dụ đơn giản này, Resequencer nhận các tin nhắn với số thứ tự 1, 3, 5 và 2. Chúng ta giả định rằng dãy bắt đầu bằng 1, vì vậy tin nhắn đầu tiên có thể được gửi ngay lập tức và được loại bỏ khỏi bộ đệm. Tin nhắn tiếp theo có số thứ tự 3, vì vậy chúng ta đang thiếu tin nhắn 2. Do đó, chúng ta lưu trữ tin nhắn 3 cho đến khi có một dãy tin nhắn hợp lệ. Chúng ta làm điều tương tự với tin nhắn tiếp theo, có số thứ tự 5. Khi tin nhắn 2 đến, bộ đệm chứa một dãy hợp lệ của các tin nhắn 2 và 3. Do đó, Resequencer công bố các tin nhắn này và loại bỏ chúng khỏi bộ đệm. Tin nhắn 5 vẫn nằm trong bộ đệm cho đến khi "khoảng trống" còn lại trong dãy được lấp đầy.
Bộ đệm nên lớn như thế nào? Nếu chúng ta đang xử lý một luồng các tin nhắn dài, bộ đệm có thể trở nên khá lớn. Thậm chí tệ hơn, hãy giả sử chúng ta có một cấu hình với nhiều đơn vị xử lý, mỗi đơn vị xử lý đảm nhiệm một loại tin nhắn cụ thể. Nếu một đơn vị xử lý bị lỗi, chúng ta sẽ nhận được một luồng dài các tin nhắn không đúng thứ tự. Tình trạng tràn bộ đệm gần như là điều chắc chắn. Trong một số trường hợp, chúng ta có thể sử dụng hàng đợi tin nhắn để hấp thụ các tin nhắn đang chờ. Điều này chỉ hoạt động nếu hạ tầng nhắn tin cho phép chúng ta đọc tin nhắn từ hàng đợi dựa trên tiêu chí lựa chọn thay vì luôn đọc tin nhắn cũ nhất trước. Bằng cách đó, chúng ta có thể kiểm tra hàng đợi và xem liệu tin nhắn đầu tiên bị thiếu có đến chưa mà không tiêu thụ tất cả các tin nhắn ở giữa. Tuy nhiên, vào một thời điểm nào đó, ngay cả dung lượng được phân bổ cho hàng đợi tin nhắn cũng sẽ đầy lên.
Một cách hiệu quả để tránh tràn bộ đệm là điều chỉnh tốc độ nhà sản xuất tin nhắn bằng cách sử dụng xác nhận chủ động (xem hình).
`Chấp nhận chủ động tránh tràn bộ đệm`

Như chúng ta đã thảo luận trước đó, việc chỉ gửi một tin nhắn duy nhất tại một thời điểm là rất không hiệu quả. Chúng ta cần phải thông minh hơn một chút. Một cách hiệu quả hơn là để Resequencer thông báo cho nhà sản xuất biết nó có bao nhiêu vị trí trống trong bộ đệm của nó. Bộ điều chỉnh tin nhắn sau đó có thể gửi đi nhiều tin nhắn như vậy, vì ngay cả khi chúng bị mất trật tự hoàn toàn, Resequencer sẽ có khả năng giữ toàn bộ chúng trong bộ đệm và sắp xếp lại thứ tự. Cách tiếp cận này đưa ra một thỏa hiệp tốt giữa hiệu quả và yêu cầu bộ đệm. Tuy nhiên, điều này đòi hỏi chúng ta phải có quyền truy cập vào luồng tin nhắn theo trật tự gốc để có thể chèn bộ đệm gửi và bộ điều chỉnh.
Cách tiếp cận này rất giống với cách mà giao thức mạng TCP/IP hoạt động. Một trong những đặc điểm chính của giao thức TCP là đảm bảo việc truyền các gói tin theo thứ tự qua mạng. Trên thực tế, mỗi gói tin có thể được định tuyến qua một con đường mạng khác nhau, vì vậy các gói tin ngoài thứ tự xảy ra khá thường xuyên. Bộ nhận duy trì một bộ nhớ vòng tròn được sử dụng như một cửa sổ trượt. Bộ nhận và bộ gửi thương lượng về số lượng gói tin sẽ gửi trước mỗi lần xác nhận. Bởi vì bộ gửi chờ đợi xác nhận từ bộ nhận, một bộ gửi nhanh không thể vượt qua bộ nhận hoặc gây tràn bộ nhớ đệm. Các quy tắc cụ thể cũng ngăn chặn hiện tượng gọi là Hội chứng Cửa sổ ngớ ngẩn, khi bộ gửi và bộ nhận có thể rơi vào chế độ rất kém hiệu quả, từng gói tin một.
Một giải pháp khác cho vấn đề tràn bộ đệm là tính toán các tin nhắn thay thế cho những tin nhắn bị thiếu. Phương pháp này hoạt động nếu người nhận sẵn sàng chấp nhận dữ liệu tin nhắn "đủ tốt" và không yêu cầu dữ liệu chính xác cho mỗi tin nhắn hoặc nếu tốc độ quan trọng hơn độ chính xác. Ví dụ, trong các cuộc truyền dẫn giọng nói qua IP, việc lấp đầy một gói tin trống sẽ mang lại trải nghiệm người dùng tốt hơn so với việc phát hành yêu cầu lại cho một gói tin bị mất, điều này sẽ gây ra độ trễ đáng kể trong dòng âm thanh.
Hầu hết chúng ta, những nhà phát triển ứng dụng, coi giao tiếp mạng đáng tin cậy là điều hiển nhiên. Khi thiết kế các giải pháp nhắn tin, thực sự hữu ích khi xem xét một số vấn đề nội bộ của TCP, bởi vì ở cốt lõi, lưu lượng IP là không đồng bộ và không đáng tin cậy, và phải đối mặt với nhiều vấn đề tương tự mà các giải pháp tích hợp doanh nghiệp gặp phải. Để có cái nhìn sâu sắc về các giao thức IP, xem [Stevens] và [Wright].
| Ví dụ: Sắp xếp lại trong Microsoft .NET với MSMQ Để minh họa chức năng của một Resequencer trong một kịch bản thực tế, chúng tôi sử dụng thiết lập sau: Cấu hình Kiểm tra Resequencer
Thiết lập thử nghiệm bao gồm bốn thành phần chính, mỗi thành phần được triển khai dưới dạng lớp C#. Các thành phần giao tiếp với nhau qua hàng đợi tin nhắn MSMQ được cung cấp bởi dịch vụ Gửi Nhận Tin nhắn, là một phần của Windows 2000 và Windows XP.
Nếu chúng ta khởi động tất cả các thành phần, chúng ta sẽ thấy đầu ra gỡ lỗi tương tự như hình bên dưới. Từ kích thước của các cửa sổ đầu ra vi xử lý, chúng ta có thể thấy tốc độ khác nhau mà các vi xử lý đang hoạt động. Như mong đợi, các tin nhắn đến Resequencer không theo thứ tự (trong lần chạy này, các tin nhắn đến theo thứ tự 3, 4, 1, 5, 7, 2, ...). Chúng ta có thể thấy từ đầu ra của Resequencer cách mà Resequencer đệm các tin nhắn đến nếu một tin nhắn bị thiếu. Ngay khi tin nhắn bị thiếu đến, Resequencer sẽ phát hành chuỗi đã hoàn thành giờ đã ở đúng thứ tự. Đầu ra từ các Thành phần Kiểm tra
Nhìn vào cấu hình thử nghiệm, chúng tôi nhận ra rằng cả DelayProcessor và Resequencer đều có một số điểm chung: Chúng đều đọc tin nhắn từ hàng đợi đầu vào và công bố chúng ra hàng đợi đầu ra. Sự khác biệt duy nhất là những gì xảy ra giữa quá trình xử lý thực tế của tin nhắn. Do đó, chúng tôi đã tạo ra một lớp cơ sở chung encapsulates các chức năng cơ bản của bộ lọc tổng quát này (xem Pipes and Filters). Nó bao gồm các phương thức tiện lợi và mẫu cho việc tạo hàng đợi và nhận, xử lý, gửi tin nhắn không đồng bộ. Chúng tôi gọi lớp cơ sở này là Processor (xem hình). Cả DelayProcessor và Resequencer đều kế thừa từ lớp Processor chung.
Thực hiện mặc định của Bộ xử lý đơn giản sao chép tin nhắn từ hàng đợi đầu vào sang hàng đợi đầu ra. Để thực hiện Resequencer, chúng ta cần ghi đè thực hiện mặc định của phương thức ProcessMessage. Trong trường hợp của Resequencer, phương thức processMessage thêm tin nhắn nhận được vào bộ đệm, được triển khai dưới dạng Hashtable. Các tin nhắn trong bộ đệm được lập chỉ mục theo số thứ tự của tin nhắn, được lưu trữ trong thuộc tính AppSpecific. Sau khi tin nhắn mới được thêm vào, phương thức SendConsecutiveMessages kiểm tra xem chúng ta có một chuỗi liên tiếp bắt đầu với các tin nhắn chưa hoàn thành tiếp theo hay không. Nếu có, phương thức sẽ gửi tất cả các tin nhắn liên tiếp và loại bỏ chúng khỏi bộ đệm. |
using System; using System.Messaging; using System.Collections; using MsgProcessor; namespace Resequencer { class Resequencer : Processor { private int startIndex = 1; private IDictionary buffer = (IDictionary)(new Hashtable()); private int endIndex = -1; public Resequencer(MessageQueue inputQueue, MessageQueue outputQueue) : base (inputQueue, outputQueue) {} protected override void ProcessMessage(Message m) { AddToBuffer(m); SendConsecutiveMessages(); } private void AddToBuffer(Message m) { Int32 msgIndex = m.AppSpecific; Console.WriteLine("Received message index {0}", msgIndex); if (msgIndex < startIndex) { Console.WriteLine("Out of range message index! Current start is: {0}", startIndex); } else { buffer.Add(msgIndex, m); if (msgIndex > endIndex) endIndex = msgIndex; } Console.WriteLine(" Buffer range: {0} - {1}", startIndex, endIndex); } private void SendConsecutiveMessages() { while (buffer.Contains(startIndex)) { Message m = (Message)(buffer[startIndex]); Console.WriteLine("Sending message with index {0}", startIndex); outputQueue.Send(m); buffer.Remove(startIndex); startIndex++; } } } } Như bạn có thể thấy, Resequencer giả định rằng chuỗi thông điệp bắt đầu từ số 1. Điều này hoạt động tốt nếu nhà sản xuất thông điệp cũng bắt đầu chuỗi từ số 1 và hai thành phần duy trì cùng một chuỗi trong suốt thời gian hoạt động của chúng. Để làm cho Resequencer linh hoạt hơn, nhà sản xuất thông điệp nên thương lượng một số bắt đầu chuỗi với Resequencer trước khi gửi thông điệp đầu tiên trong chuỗi. Quá trình này tương tự như các thông điệp SYN được trao đổi trong quá trình kết nối của giao thức TCP (xem [Stevens]).
Việc triển khai hiện tại cũng không có quy định cho việc tràn bộ đệm. Giả sử một DelayProcessor bị lỗi hoặc ngưng hoạt động và ăn mất một thông điệp. Resequencer sẽ chờ vô thời hạn cho thông điệp bị bỏ lỡ cho đến khi bộ đệm tràn. Trong các kịch bản có khối lượng lớn, thông điệp và Resequencer cần thương lượng một kích thước cửa sổ miêu tả số lượng thông điệp tối đa mà Resequencer có thể lưu trữ. Khi bộ đệm đã đầy, một trình xử lý lỗi sẽ phải xác định cách xử lý thông điệp bị thiếu. Ví dụ, nhà sản xuất có thể gửi lại thông điệp, hoặc một thông điệp "giả" có thể được tiêm vào.
Lớp cơ sở Processor tương đối đơn giản. Nó sử dụng xử lý tin nhắn không đồng bộ bằng cách sử dụng các phương thức BeginReceive và EndReceive. Vì dễ quên gọi BeginReceive vào cuối quá trình xử lý tin nhắn, chúng tôi đã sử dụng một phương thức mẫu bao gồm bước này. Các lớp con có thể ghi đè phương thức ProcessMessage mà không cần lo lắng về việc xử lý không đồng bộ.
using System; using System.Messaging; using System.Threading; namespace MsgProcessor { public class Processor { protected MessageQueue inputQueue; protected MessageQueue outputQueue; public Processor (MessageQueue inputQueue, MessageQueue outputQueue) { this.inputQueue = inputQueue; this.outputQueue = outputQueue; inputQueue.Formatter = new System.Messaging.XmlMessageFormatter (new String[] {"System.String,mscorlib"}); inputQueue.MessageReadPropertyFilter.ClearAll(); inputQueue.MessageReadPropertyFilter.AppSpecific = true; inputQueue.MessageReadPropertyFilter.Body = true; inputQueue.MessageReadPropertyFilter.CorrelationId = true; inputQueue.MessageReadPropertyFilter.Id = true; Console.WriteLine("Processing messages from " + inputQueue.Path + " to " + outputQueue.Path); } public void Process() { inputQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(OnReceiveCompleted); inputQueue.BeginReceive(); } private void OnReceiveCompleted(Object source, ReceiveCompletedEventArgs asyncResult) { MessageQueue mq = (MessageQueue)source; Message m = mq.EndReceive(asyncResult.AsyncResult); m.Formatter = new System.Messaging.XmlMessageFormatter (new String[] {"System.String,mscorlib"}); ProcessMessage(m); mq.BeginReceive(); } protected virtual void ProcessMessage(Message m) { string body = (string)m.Body; Console.WriteLine("Received Message: " + body); outputQueue.Send(m); } } } Ví dụ về xử lý đơn hàng được trình bày trong các mẫu Bộ điều hướng dựa trên nội dung và Bộ chia sẽ xử lý một đơn hàng đến bao gồm các mục hàng riêng lẻ. Mỗi mục hàng đều cần một lần kiểm tra tồn kho với hệ thống tồn kho tương ứng. Sau khi tất cả các mục đã được xác thực, chúng tôi muốn chuyển thông điệp đơn hàng đã được xác thực đến bước xử lý tiếp theo.
| Làm thế nào bạn có thể duy trì dòng chảy thông điệp tổng thể khi xử lý một thông điệp bao gồm nhiều phần tử, mỗi phần tử có thể yêu cầu xử lý khác nhau? |
Vấn đề này dường như chứa các yếu tố của nhiều mẫu mà chúng ta đã định nghĩa. Một Splitter có thể tách một thông điệp duy nhất thành nhiều phần. Một Content-Based Router sau đó có thể định tuyến các submessage cá nhân qua các bước xử lý đúng dựa trên nội dung hoặc loại thông điệp. Kiến trúc Pipes and Filters cho phép chúng ta kết hợp hai mẫu này với nhau để có thể định tuyến từng mục trong thông điệp kết hợp đến các bước xử lý phù hợp.
Kết hợp Bộ chia và Bộ định tuyến

Trong ví dụ của chúng tôi, điều này có nghĩa là mỗi mục đơn hàng được chuyển đến hệ thống tồn kho phù hợp để được xác minh. Các hệ thống tồn kho được tách rời khỏi nhau, và mỗi hệ thống chỉ nhận những mục có thể được xử lý bởi nó.
Sự thiếu sót của thiết lập cho đến nay là chúng tôi không thể xác định được liệu tất cả các mặt hàng đã đặt hàng có thực sự có trong kho và có thể được giao hay không. Chúng tôi cũng cần truy xuất giá cho tất cả các mặt hàng (tính đến các khoản chiết khấu theo khối lượng) và lắp ghép chúng thành một hóa đơn duy nhất. Điều này yêu cầu chúng tôi tiếp tục xử lý như thể đơn hàng vẫn là một tin nhắn đơn lẻ mặc dù chúng tôi vừa chia nhỏ nó thành nhiều tin nhắn con.
Một cách tiếp cận là chỉ cần tập hợp lại tất cả những mặt hàng đi qua một hệ thống tồn kho cụ thể thành một đơn hàng riêng biệt. Đơn hàng này có thể được xử lý như một tổng thể từ thời điểm này: Đơn hàng có thể được hoàn thành và giao hàng, và một hóa đơn có thể được gửi đi. Mỗi đơn hàng nhỏ được coi là một quy trình độc lập. Trong một số trường hợp, việc thiếu kiểm soát đối với quy trình đầu ra có thể làm cho cách tiếp cận này trở thành giải pháp duy nhất khả thi. Ví dụ, Amazon áp dụng cách tiếp cận này cho một phần lớn hàng hóa mà họ bán. Các đơn hàng được chuyển đến các nhà kho hoàn thiện khác nhau và được quản lý từ đó.
Tuy nhiên, cách tiếp cận này có thể không mang lại trải nghiệm tốt nhất cho khách hàng. Khách hàng có thể nhận được nhiều lô hàng và nhiều hóa đơn khác nhau. Việc trả hàng hoặc tranh chấp có thể khó khăn để bố trí. Điều này không phải là vấn đề lớn đối với người tiêu dùng đặt sách, nhưng có thể trở nên khó khăn nếu các mặt hàng trong đơn hàng phụ thuộc vào nhau. Giả sử rằng đơn hàng bao gồm các món đồ nội thất tạo thành một hệ thống kệ. Khách hàng sẽ không hài lòng khi nhận được nhiều hộp lớn chứa các phần nội thất chỉ để phát hiện rằng phần cứng lắp đặt cần thiết tạm thời không có sẵn và sẽ được gửi vào thời gian sau.
Tính chất bất đồng bộ của một hệ thống nhắn tin làm cho việc phân phối nhiệm vụ trở nên phức tạp hơn so với các cuộc gọi phương pháp đồng bộ. Chúng ta có thể gửi mỗi mục hàng riêng lẻ và chờ phản hồi trước khi kiểm tra mục tiếp theo. Điều này sẽ đơn giản hóa các phụ thuộc tạm thời nhưng sẽ làm cho hệ thống rất không hiệu quả. Chúng ta muốn tận dụng việc mỗi hệ thống có thể xử lý nhiều đơn hàng đồng thời.
| Sử dụng Bộ xử lý Tin nhắn Tập hợp để xử lý một tin nhắn phức hợp. Bộ xử lý Tin nhắn Tập hợp chia nhỏ tin nhắn, định tuyến các tin nhắn con đến các điểm đến thích hợp, và tổng hợp lại các phản hồi thành một tin nhắn duy nhất.
|
Bộ xử lý tin nhắn được cấu hình sử dụng một Bộ tổng hợp để hoà giải các yêu cầu được gửi đến nhiều hệ thống tồn kho. Mỗi đơn vị xử lý gửi một tin nhắn phản hồi đến Bộ tổng hợp thông báo về hàng tồn kho hiện có cho mặt hàng được chỉ định. Bộ tổng hợp thu thập các phản hồi cá nhân và xử lý chúng dựa trên một thuật toán đã được xác định trước.
Bởi vì tất cả các thông điệp phụ đều xuất phát từ một thông điệp duy nhất, chúng ta có thể truyền thêm thông tin, chẳng hạn như số lượng thông điệp phụ, đến Bộ Tổng Hợp để xác định một chiến lược tổng hợp hiệu quả hơn. Tuy nhiên, Bộ Xử Lý Thông Điệp Tổ Hợp vẫn phải đối mặt với các vấn đề liên quan đến thông điệp bị thiếu hoặc bị trì hoãn. Nếu hệ thống tồn kho không khả dụng, liệu chúng ta có muốn trì hoãn việc xử lý tất cả các đơn hàng bao gồm các mặt hàng từ hệ thống đó không? Hay chúng ta nên chuyển họ đến hàng đợi ngoại lệ để con người đánh giá thủ công? Nếu một phản hồi duy nhất bị thiếu, có nên gửi lại thông điệp yêu cầu tồn kho không? Để thảo luận chi tiết hơn về những đánh đổi này, hãy xem Bộ Tổng Hợp.
Mẫu này cho thấy cách nhiều mẫu riêng biệt có thể được kết hợp thành một mẫu lớn hơn duy nhất. Đối với phần còn lại của hệ thống, Bộ xử lý Thông điệp Kết hợp xuất hiện như một bộ lọc đơn giản với một kênh đầu vào và một kênh đầu ra duy nhất. Do đó, nó cung cấp một sự trừu tượng hiệu quả về những hoạt động nội bộ phức tạp hơn.
Bộ xử lý thông điệp tổng hợp như một bộ lọc duy nhất

Trong ví dụ xử lý đơn hàng được giới thiệu trong các mẫu trước, mỗi mục đơn hàng không có sẵn trong kho có thể được cung cấp bởi một trong nhiều nhà cung cấp bên ngoài. Tuy nhiên, các nhà cung cấp có thể có hoặc không có mục tương ứng trong kho, họ có thể tính giá khác nhau, hoặc họ có thể cung cấp phần đó vào một ngày khác nhau. Để hoàn thành đơn hàng một cách tốt nhất có thể, chúng ta nên yêu cầu báo giá từ tất cả các nhà cung cấp và quyết định nhà cung cấp nào mang lại cho chúng ta điều kiện tốt nhất cho mục hàng đã yêu cầu.
| Làm thế nào bạn duy trì dòng chảy thông điệp tổng thể khi một thông điệp phải được gửi đến nhiều người nhận, mỗi người có thể gửi phản hồi? |
Giải pháp phải cho phép linh hoạt trong việc xác định người nhận thông điệp. Chúng ta có thể xác định danh sách các nhà cung cấp được phê duyệt một cách tập trung hoặc có thể để bất kỳ nhà cung cấp nào quan tâm tham gia thầu. Vì chúng ta không có (hoặc ít) kiểm soát đối với người nhận, chúng ta phải chuẩn bị để nhận phản hồi từ một số, nhưng không từ tất cả, người nhận. Những thay đổi như vậy trong quy tắc thầu không nên ảnh hưởng đến tính toàn vẹn cấu trúc của giải pháp.
Giải pháp nên che giấu số lượng và danh tính của các người nhận cá nhân khỏi bất kỳ quy trình nào sau đó. Việc bao bọc việc phân phối tin nhắn một cách cục bộ giữ cho các thành phần khác độc lập với lộ trình của các tin nhắn cá nhân.
Chúng ta cũng cần phối hợp luồng tin nhắn tiếp theo. Giải pháp dễ nhất có thể là yêu cầu mỗi người nhận đăng phản hồi vào một kênh và để các thành phần tiếp theo xử lý việc giải quyết các tin nhắn cá nhân. Tuy nhiên, điều này sẽ đòi hỏi các thành phần tiếp theo phải nhận thức được tin nhắn đang được gửi đến nhiều người nhận. Nó cũng có thể gây khó khăn cho các thành phần tiếp theo trong việc xử lý các tin nhắn cá nhân mà không có kiến thức về logic định tuyến đã được áp dụng.
Việc kết hợp logic định tuyến, người nhận và xử lý sau của các tin nhắn riêng lẻ thành một thành phần hợp lý là hoàn toàn hợp lý.
| Sử dụng Scatter-Gather để phát tán một thông điệp tới nhiều người nhận và tập hợp lại các phản hồi thành một thông điệp duy nhất.
|
`Chức năng Scatter-Gather gửi một thông điệp yêu cầu đến nhiều người nhận. Sau đó, nó sử dụng một bộ tổng hợp để thu thập các phản hồi và đúc kết chúng thành một thông điệp phản hồi duy nhất.`
Có hai biến thể của Scatter-Gather sử dụng các cơ chế khác nhau để gửi các thông điệp yêu cầu đến các người nhận được chỉ định:
Việc phân phối qua danh sách người nhận cho phép Scatter-Gather kiểm soát danh sách người nhận nhưng yêu cầu Scatter-Gather phải biết đến kênh thông điệp của từng người nhận.
Kiểu Rải-Rút theo hình thức Đấu giá sử dụng Kênh Đăng ký-Nhận thông báo để phát sóng yêu cầu đến bất kỳ người tham gia nào quan tâm. Tùy chọn này cho phép Rải-Rút sử dụng một kênh duy nhất nhưng cũng buộc nó phải từ bỏ quyền kiểm soát.
Giải pháp này có những điểm tương đồng với Bộ Xử Lý Tin Nhắn Tổ Hợp. Thay vì sử dụng một Bộ Tách, chúng tôi phát sóng tin nhắn hoàn chỉnh đến tất cả các bên liên quan thông qua một Kênh Xuất Bản-Đăng Ký. Chúng tôi có khả năng sẽ thêm một Địa Chỉ Trả về để tất cả các phản hồi có thể được xử lý qua một kênh duy nhất. Giống như với Bộ Xử Lý Tin Nhắn Tổ Hợp, một phương pháp Rải-Ráp tổng hợp các phản hồi dựa trên các quy tắc kinh doanh đã định nghĩa. Trong ví dụ của chúng tôi, bộ Tổng Hợp có thể chọn các đề xuất tốt nhất từ các nhà cung cấp có thể thực hiện đơn hàng. Việc tổng hợp các phản hồi có thể khó khăn hơn với phương pháp Rải-Ráp so với Bộ Xử Lý Tin Nhắn Tổ Hợp, bởi vì chúng tôi có thể không biết có bao nhiêu người nhận tham gia vào tương tác này.
Cả Bộ Phân Tán - Tập Hợp và Bộ Xử Lý Thông Điệp Tổ Hợp đều định tuyến một thông điệp đơn đến nhiều người nhận và kết hợp các thông điệp phản hồi cá nhân thành một thông điệp duy nhất bằng cách sử dụng một Bộ Tập Hợp. Bộ Xử Lý Thông Điệp Tổ Hợp thực hiện nhiệm vụ đồng bộ hóa nhiều hoạt động song song. Nếu các hoạt động cá nhân tốn thời gian rất khác nhau, thì việc xử lý tiếp theo sẽ bị trì hoãn ngay cả khi nhiều phân công (hoặc thậm chí tất cả trừ một) đã hoàn thành. Yếu tố này cần được cân nhắc so với sự đơn giản và đóng gói mà Bộ Phân Tán - Tập Hợp mang lại. Một sự thỏa hiệp giữa hai lựa chọn này có thể là một Bộ Tập Hợp xếp chồng. Thiết kế này cho phép các nhiệm vụ tiếp theo được khởi động chỉ với một tập hợp con của các kết quả có sẵn.
| Ví dụ: Người môi giới vay vốn Ví dụ về Người môi giới cho vay (Chương 9, "Giai đoạn giữa: Tin nhắn đã soạn thảo") sử dụng mô hình Phân tán-Gom nhóm để định tuyến các yêu cầu báo giá vay đến một số ngân hàng và chọn ra đề nghị tốt nhất từ các phản hồi đến. Các triển khai ví dụ minh họa cả một giải pháp dựa trên Danh sách Người nhận, xem "Triển khai Bất đồng bộ với MSMQ" trong Chương 9 và một Kênh Xuất bản-Đăng ký, xem "Triển khai Bất đồng bộ với TIBCO ActiveEnterprise" trong Chương 9. |
| Ví dụ: Kết hợp các mẫu Chúng ta có thể sử dụng mô hình Scatter-Gather để triển khai ví dụ xử lý đơn hàng dành cho widget và gadget. Chúng ta có thể kết hợp Scatter-Gather với Bộ xử lý Tin nhắn Tổ hợp để xử lý từng đơn hàng đến, sắp xếp chúng thành các mục riêng lẻ, đưa từng mục lên để đấu giá, tổng hợp các giá thầu cho mỗi mục thành một phản hồi giá thầu kết hợp, và sau đó tổng hợp tất cả các phản hồi giá thầu thành một báo giá hoàn chỉnh. Đây là một ví dụ rất thực tế về cách nhiều mẫu tích hợp có thể được kết hợp thành một giải pháp hoàn chỉnh. Việc tổ hợp các mẫu cá nhân thành các mẫu lớn hơn cho phép chúng ta thảo luận về giải pháp ở mức độ trừu tượng cao hơn. Nó cũng cho phép chúng ta thay đổi các chi tiết của việc triển khai mà không ảnh hưởng đến các thành phần khác. Kết hợp một bộ xử lý tin nhắn phân tán - thu thập và một bộ xử lý tin nhắn tổ hợp.
Ví dụ này cũng cho thấy tính linh hoạt của Bộ Tổng Hợp. Giải pháp sử dụng hai Bộ Tổng Hợp cho những mục đích rất khác nhau. Bộ Tổng Hợp đầu tiên, là một phần của Scatter-Gather, chọn giá thầu tốt nhất từ một số nhà cung cấp. Bộ Tổng Hợp này có thể không yêu cầu phản hồi từ tất cả các nhà cung cấp (tốc độ có thể quan trọng hơn giá thấp) nhưng có thể yêu cầu một thuật toán phức tạp để kết hợp các phản hồi. Ví dụ, đơn hàng có thể chứa 100 sản phẩm, và nhà cung cấp có giá thấp nhất chỉ có 60 sản phẩm trong kho. Bộ Tổng Hợp phải có khả năng quyết định có chấp nhận đề nghị này hay không và lấp đầy 40 mặt hàng còn lại từ một nhà cung cấp khác. Bộ Tổng Hợp thứ hai, là một phần của Bộ Xử Lý Tin Nhắn Tổng Hợp, có thể đơn giản hơn vì nó chỉ nối tất cả các phản hồi nhận được từ Bộ Tổng Hợp đầu tiên. Tuy nhiên, Bộ Tổng Hợp này cần đảm bảo rằng tất cả các phản hồi thực sự đã được nhận và cần xử lý các điều kiện lỗi như thiếu phản hồi về mặt hàng. |
Hầu hết các mẫu định tuyến đã được trình bày cho đến nay định tuyến các tin nhắn đến một hoặc nhiều đích dựa trên một tập hợp các quy tắc. Tuy nhiên, đôi khi chúng ta cần định tuyến một tin nhắn không chỉ đến một thành phần đơn lẻ, mà thông qua một chuỗi thành phần. Giả sử, ví dụ, rằng chúng ta sử dụng kiến trúc Pipes and Filters để xử lý các tin nhắn đến phải trải qua một chuỗi các bước xử lý và xác thực quy tắc kinh doanh. Do tính chất của các xác thực rất khác nhau và có thể phụ thuộc vào các hệ thống bên ngoài (ví dụ: các xác thực thẻ tín dụng), chúng ta triển khai mỗi loại bước như một bộ lọc riêng biệt. Mỗi bộ lọc kiểm tra tin nhắn đến và áp dụng quy tắc kinh doanh vào tin nhắn. Nếu tin nhắn không đáp ứng các điều kiện được chỉ định bởi các quy tắc, nó sẽ được định tuyến đến một kênh ngoại lệ. Các kênh giữa các bộ lọc xác định chuỗi các xác thực mà tin nhắn cần trải qua.
Giờ hãy giả sử rằng tập hợp các xác thực cần thực hiện đối với mỗi tin nhắn phụ thuộc vào loại tin nhắn (ví dụ, các yêu cầu đơn hàng mua không cần xác thực thẻ tín dụng, hoặc khách hàng gửi đơn hàng qua VPN có thể không cần giải mã và xác thực). Để đáp ứng yêu cầu này, chúng ta cần tìm một cấu hình có thể định tuyến tin nhắn qua một chuỗi bộ lọc khác nhau tùy thuộc vào loại tin nhắn.
| Chúng ta làm thế nào để định tuyến một tin nhắn một cách liên tiếp qua một loạt các bước xử lý khi chuỗi bước không được biết tại thời điểm thiết kế và có thể thay đổi cho mỗi tin nhắn? |
Kiến trúc Pipes and Filters cung cấp cho chúng ta một cách tiếp cận thanh lịch để đại diện cho một chuỗi các bước xử lý dưới dạng các bộ lọc độc lập được kết nối bằng các ống (kênh). Trong cấu hình mặc định của nó, các bộ lọc được kết nối bằng các ống cố định. Nếu chúng ta muốn cho phép các thông điệp được định tuyến đến các bộ lọc khác nhau một cách động, chúng ta có thể sử dụng các bộ lọc đặc biệt hoạt động như Bộ định tuyến Thông điệp. Các bộ định tuyến xác định động bộ lọc tiếp theo để định tuyến thông điệp đến.
Các yêu cầu chính cho một giải pháp tốt cho vấn đề của chúng ta có thể được tóm tắt như sau:
Dòng chảy tin nhắn hiệu quả: Các tin nhắn nên chỉ đi qua những bước cần thiết và tránh các thành phần không cần thiết.
Sử dụng tài nguyên hiệu quả: Giải pháp không nên sử dụng một lượng lớn kênh, bộ định tuyến và các tài nguyên khác.
Linh hoạt: Lộ trình mà các tin nhắn cá nhân đi qua nên dễ dàng thay đổi.
Dễ dàng bảo trì: Nếu một loại tin nhắn mới cần được hỗ trợ, chúng tôi muốn có một điểm bảo trì duy nhất để tránh việc phát sinh lỗi.
Các sơ đồ sau minh họa các giải pháp thay thế của chúng tôi cho vấn đề. Chúng tôi giả định rằng hệ thống cung cấp ba bước xử lý riêng biệt, A, B và C, và rằng thông điệp hiện tại chỉ cần đi qua các bước A và C. Luồng thực tế cho thông điệp ví dụ này được đánh dấu bằng các mũi tên dày.

Chúng ta có thể tạo thành một chuỗi Pipes và Filters dài với tất cả các bước xác thực hợp lệ có thể và thêm mã vào mỗi bộ định tuyến để bỏ qua xác thực nếu bước đó không cần thiết cho loại thông điệp đang được truyền qua (xem Lựa chọn A). Tùy chọn này về cơ bản áp dụng phương pháp lọc phản ứng được mô tả trong Bộ lọc Thông điệp. Mặc dù sự đơn giản của giải pháp này là hấp dẫn, nhưng thực tế là các thành phần kết hợp cả logic kinh doanh (xác thực) và logic định tuyến (quyết định có nên xác thực hay không) sẽ khiến chúng trở nên khó sử dụng lại. Ngoài ra, có thể hai loại thông điệp trải qua các bước xử lý tương tự nhưng theo thứ tự khác nhau. Cách tiếp cận cố định này sẽ không dễ dàng hỗ trợ yêu cầu này.
Để cải thiện sự phân tách mối quan tâm và tăng cường khả năng kết hợp của giải pháp, chúng ta nên thay thế logic "gating" bên trong mỗi thành phần bằng các Bộ định tuyến dựa trên nội dung. Chúng ta sẽ có một chuỗi tất cả các bước xác thực hợp lệ có thể, mỗi bước được đặt trước bởi một Bộ định tuyến dựa trên nội dung, xem Lựa chọn B. Khi một tin nhắn đến Bộ định tuyến, nó sẽ kiểm tra loại tin nhắn và xác định xem loại tin nhắn này có yêu cầu bước xác thực này hay không. Nếu bước này là cần thiết, Bộ định tuyến sẽ chuyển tiếp tin nhắn qua xác thực. Nếu bước này không cần thiết, Bộ định tuyến sẽ vượt qua xác thực và chuyển tiếp tin nhắn trực tiếp đến Bộ định tuyến tiếp theo (theo cách rất giống với Detour 545). Cấu hình này hoạt động khá tốt trong các trường hợp mà mỗi bước độc lập với bất kỳ bước nào khác và quyết định định tuyến có thể được đưa ra một cách cục bộ tại mỗi bước. Nhưng nhược điểm là, cách tiếp cận này thường dẫn đến việc chuyển tin nhắn qua một loạt các bộ định tuyến dài mặc dù chỉ có một vài bước xác thực có thể được thực hiện. Trên thực tế, mỗi tin nhắn sẽ được truyền qua một kênh với tốc độ gấp hai lần số lượng thành phần có thể có. Nếu chúng ta có một thư viện thành phần lớn, điều này sẽ gây ra một lượng lưu lượng tin nhắn khổng lồ cho một chức năng khá đơn giản. Hơn nữa, logic định tuyến được phân phối trên nhiều bộ lọc, làm cho việc hiểu được các bước xác thực mà một tin nhắn của một loại cụ thể sẽ thực sự trải qua trở nên khó khăn. Tương tự, nếu chúng ta giới thiệu một loại tin nhắn mới, chúng ta có thể sẽ phải cập nhật từng Bộ định tuyến. Cuối cùng, tùy chọn này gặp phải hạn chế giống như Tùy chọn A ở chỗ các tin nhắn bị ràng buộc vào việc thực thi các bước theo một thứ tự đã định.

Nếu chúng ta mong muốn một điểm kiểm soát trung tâm, một Bộ định tuyến dựa trên nội dung (Content-Based Router) ở phía trước thường là một lựa chọn tốt trong các cuộc thảo luận về mẫu thiết kế trước đây của chúng tôi. Chúng tôi có thể hình dung một giải pháp trong đó chúng tôi thiết lập các chuỗi Ống dẫn và Bộ lọc (Pipes and Filters) riêng cho từng loại tin nhắn. Mỗi chuỗi sẽ chứa chuỗi các bước xác thực liên quan đến một loại cụ thể. Chúng tôi sẽ sử dụng một Bộ định tuyến dựa trên nội dung để chuyển tiếp tin nhắn đến chuỗi xác thực chính xác dựa trên loại tin nhắn (xem Tùy chọn C). Phương pháp này chỉ chuyển tiếp các tin nhắn qua các bước liên quan (cộng với bộ định tuyến ban đầu). Do đó, đây là phương pháp hiệu quả nhất cho đến nay vì chúng tôi chỉ thêm một bước định tuyến duy nhất để thực hiện chức năng mong muốn. Giải pháp cũng làm nổi bật đường đi mà một tin nhắn của loại cụ thể sẽ đi qua rất rõ ràng. Tuy nhiên, nó yêu cầu chúng tôi phải cố định bất kỳ sự kết hợp nào của các quy tắc xác thực. Ngoài ra, cùng một thành phần có thể được sử dụng trong nhiều đường đi khác nhau. Phương pháp này sẽ yêu cầu chúng tôi chạy nhiều phiên bản của các thành phần như vậy, dẫn đến sự trùng lặp không cần thiết. Đối với một tập hợp lớn các loại tin nhắn, phương pháp này có thể dẫn đến ác mộng trong việc bảo trì do số lượng lớn các phiên bản thành phần và các kênh liên quan mà chúng tôi phải duy trì. Tóm lại, giải pháp này rất hiệu quả nhưng đồng thời cũng gây khó khăn trong việc bảo trì.
Nếu chúng ta muốn tránh việc cắm chặt tất cả các kết hợp có thể của các bước xác thực, chúng ta cần chèn một Bộ định tuyến dựa trên nội dung giữa mỗi bước xác thực (xem Lựa chọn D). Để không gặp phải những vấn đề tương tự liên quan đến cách lọc phản ứng (được trình bày trong Lựa chọn B), chúng ta sẽ chèn Bộ định tuyến dựa trên nội dung sau mỗi bước thay vì trước (chúng ta cần một bộ định tuyến bổ sung ở phía trước bước đầu tiên để bắt đầu). Các bộ định tuyến sẽ đủ thông minh để chuyển tiếp tin nhắn trực tiếp đến bước xác thực cần thiết tiếp theo thay vì chỉ định mù quáng đến bước tiếp theo có sẵn trong chuỗi. Về mặt trừu tượng, giải pháp này trông giống như cách lọc phản ứng vì tin nhắn đi qua một tập hợp bộ định tuyến và bộ lọc xen kẽ. Tuy nhiên, trong trường hợp này, các bộ định tuyến có nhiều trí tuệ hơn một quyết định đơn giản có hoặc không, cho phép chúng ta loại bỏ các bước không cần thiết. Ví dụ, trong kịch bản đơn giản của chúng ta, tin nhắn chỉ đi qua hai bộ định tuyến thay vì ba bộ như trong Lựa chọn B. Lựa chọn này cung cấp tính hiệu quả và linh hoạt nhưng không giải quyết được mục tiêu của chúng ta là đạt được kiểm soát trung tâm, vì chúng ta vẫn phải duy trì một số lượng lớn bộ định tuyến có thể vì logic định tuyến được phân tán ra một loạt các bộ định tuyến độc lập.
Để giải quyết vấn đề thiếu sót cuối cùng này, chúng ta có thể kết hợp tất cả các bộ định tuyến thành một "siêu bộ định tuyến" (xem tùy chọn E). Sau mỗi bước xác thực, thông điệp sẽ được định tuyến trở lại siêu bộ định tuyến, thiết bị này sẽ xác định bước xác thực tiếp theo cần được thực hiện. Cấu hình này chỉ định tuyến thông điệp tới những bộ lọc cần thiết cho loại thông điệp cụ thể. Vì tất cả các quyết định định tuyến bây giờ đều được tích hợp vào một bộ định tuyến duy nhất, chúng ta cần nghĩ ra một cơ chế để nhớ những bước nào chúng ta đã hoàn tất xử lý. Do đó, siêu bộ định tuyến sẽ phải duy trì trạng thái hoặc mỗi bộ lọc sẽ phải gán một thẻ vào thông điệp để thông báo cho siêu bộ định tuyến biết tên của bộ lọc cuối cùng mà thông điệp đã đi qua. Ngoài ra, chúng ta vẫn phải đối mặt với việc mỗi bước xác thực yêu cầu thông điệp được truyền qua hai kênh: đến thành phần và sau đó trở lại siêu bộ định tuyến. Điều này dẫn đến việc lưu lượng giao thông tăng gấp đôi so với tùy chọn C.
| Đính kèm một Phiếu Chuyển Đường tới từng tin nhắn, chỉ định thứ tự các bước xử lý. Bọc mỗi thành phần với một bộ định tuyến tin nhắn đặc biệt mà đọc Phiếu Chuyển Đường và chuyển tiếp tin nhắn tới thành phần tiếp theo trong danh sách.
|
Chúng tôi chèn một thành phần đặc biệt vào đầu quá trình, thành phần này sẽ tính toán danh sách các bước cần thiết cho mỗi tin nhắn. Sau đó, nó gắn danh sách này dưới dạng Giấy chuyển giao vào tin nhắn và bắt đầu quá trình bằng cách chuyển tin nhắn tới bước xử lý đầu tiên. Sau khi xử lý thành công, mỗi bước xử lý sẽ xem Giấy chuyển giao và chuyển tin nhắn tới bước xử lý tiếp theo được chỉ định trong bảng chuyển giao.
Mẫu này hoạt động tương tự như phiếu chuyển phát đính kèm với một tạp chí để phát hành trong một nhóm hoặc phòng ban. Sự khác biệt duy nhất là Phiếu Chuyển Phát có một chuỗi thành phần xác định mà nó đi qua, trong khi ở hầu hết các công ty, bạn có thể bàn giao tạp chí sau khi đọc cho bất kỳ ai trong danh sách chưa đọc nó (dĩ nhiên, sếp thường sẽ được ưu tiên).
Giấy Chuyển Giao kết hợp sự kiểm soát trung tâm của phương pháp siêu bộ định tuyến (Tùy chọn E) với hiệu quả của giải pháp dây cứng (Tùy chọn C). Chúng tôi xác định toàn bộ sơ đồ định tuyến ngay từ đầu và gán nó vào tin nhắn, vì vậy chúng tôi không cần phải quay lại bộ định tuyến trung tâm để đưa ra quyết định thêm. Mỗi thành phần được tăng cường bằng logic định tuyến đơn giản. Trong giải pháp được đề xuất, chúng tôi giả định rằng logic định tuyến này được tích hợp vào chính thành phần xử lý. Nếu nhìn lại Tùy chọn A, chúng ta nhớ rằng chúng tôi đã loại bỏ phương pháp này một phần vì chúng tôi phải mã hóa cứng một số logic vào từng thành phần. Giấy Chuyển Giao tốt hơn ở điểm nào? Sự khác biệt chính là bộ định tuyến được sử dụng trong Giấy Chuyển Giao là chung và không cần thay đổi theo các thay đổi trong logic định tuyến. Logic định tuyến được tích hợp vào mỗi thành phần tương tự như một Địa Chỉ Trả Lại, nơi địa chỉ trả lại được chọn từ danh sách các địa chỉ. Tương tự như Địa Chỉ Trả Lại, các thành phần giữ được khả năng tái sử dụng và khả năng kết hợp ngay cả khi một phần logic định tuyến được tích hợp vào thành phần. Thêm vào đó, việc tính toán bảng định tuyến hiện có thể được thực hiện tại một nơi trung tâm mà không cần chạm vào mã bên trong bất kỳ thành phần xử lý nào.
Như thường lệ, không có bữa trưa miễn phí, vì vậy chúng ta có thể mong đợi Giấy Gửi sẽ có một số giới hạn nhất định. Đầu tiên, kích thước tin nhắn sẽ tăng nhẹ. Trong hầu hết các trường hợp, điều này sẽ không đáng kể, nhưng chúng ta cần nhận thức rằng giờ đây chúng ta đang mang theo trạng thái quá trình (các bước đã hoàn thành) bên trong tin nhắn. Điều này có thể gây ra các hiệu ứng phụ khác. Ví dụ, nếu chúng ta mất một tin nhắn, chúng ta không chỉ mất dữ liệu tin nhắn mà còn cả dữ liệu quá trình (tức là, tin nhắn đó sẽ đi đâu tiếp theo). Trong nhiều trường hợp, có thể hữu ích để duy trì trạng thái của tất cả các tin nhắn ở một nơi trung tâm để thực hiện báo cáo hoặc phục hồi lỗi.
Một hạn chế khác của Phiếu Chuyển Đường là đường đi của một tin nhắn không thể thay đổi khi nó đã bắt đầu. Điều này có nghĩa là đường đi của tin nhắn không thể phụ thuộc vào các kết quả trung gian được tạo ra bởi một bước xử lý trên đường đi. Trong nhiều quy trình kinh doanh thực tế, dòng chảy của tin nhắn thay đổi dựa trên các kết quả trung gian. Ví dụ, tùy thuộc vào sự sẵn có của các mặt hàng đã đặt hàng (như được báo cáo bởi hệ thống tồn kho), chúng ta có thể muốn tiếp tục với một con đường khác. Điều này cũng có nghĩa là một thực thể trung tâm phải có khả năng xác định tất cả các bước mà tin nhắn phải trải qua trước đó. Điều này có thể dẫn đến một số điểm yếu trong thiết kế, giống như những mối quan ngại về việc sử dụng Bộ Định Tuyến Dựa Trên Nội Dung.
Bản ghi lộ trình giả định rằng chúng ta có khả năng tăng cường các thành phần riêng lẻ với logic định tuyến. Nếu chúng ta đang xử lý các ứng dụng kế thừa hoặc ứng dụng đóng gói, có thể chúng ta không thể ảnh hưởng đến chức năng của chính thành phần đó. Thay vào đó, chúng ta cần sử dụng một bộ định tuyến bên ngoài giao tiếp với thành phần qua thông điệp. Điều này nhất định sẽ làm tăng số kênh và thành phần đang sử dụng. Tuy nhiên, Bản ghi lộ trình vẫn cung cấp sự đánh đổi tốt nhất giữa các mục tiêu về hiệu quả, linh hoạt và khả năng bảo trì của chúng ta.
Triển khai một phiếu định tuyến với các ứng dụng kế thừa

Tờ trình là hữu ích nhất trong các tình huống sau đây:
Một chuỗi các bước xác thực nhị phân. Bằng cách không thêm thông tin vào tin nhắn, hạn chế rằng chúng ta không thể thay đổi lộ trình khi tin nhắn đã được gửi đi sẽ không còn là yếu tố. Chúng ta vẫn đánh giá cao tính linh hoạt trong việc thay đổi chuỗi các bước xác thực bằng cách cấu hình lại Giấy Biên Nhận Trung Tâm. Mỗi thành phần có lựa chọn giữa việc hủy bỏ chuỗi do lỗi hoặc chuyển tiếp tin nhắn đến bước tiếp theo.
Mỗi bước là một quá trình biến đổi không trạng thái. Ví dụ, giả sử chúng ta nhận đơn hàng từ nhiều đối tác kinh doanh khác nhau. Tất cả các đơn hàng đều đến qua một kênh chung nhưng ở định dạng khác nhau tùy thuộc vào đối tác. Kết quả là, mỗi tin nhắn có thể yêu cầu các bước biến đổi khác nhau. Tin nhắn từ một số đối tác có thể yêu cầu giải mã; còn những cái khác thì không. Một số có thể yêu cầu biến đổi hoặc làm phong phú thêm; còn những cái khác thì không. Việc giữ một Giấy gửi hàng cho mỗi đối tác sẽ cho chúng ta một cách dễ dàng để cấu hình lại các bước cho từng đối tác ở một vị trí trung tâm.
Mỗi bước thu thập dữ liệu, nhưng không đưa ra quyết định (xem Bộ Tăng Cường Nội Dung). Trong một số trường hợp, chúng tôi nhận được một tin nhắn chứa các định danh tham chiếu đến dữ liệu khác. Ví dụ, nếu chúng tôi nhận được đơn đặt hàng cho một đường dây DSL, tin nhắn có thể chỉ chứa số điện thoại cố định của người nộp đơn. Chúng tôi cần truy cập vào các nguồn bên ngoài để xác định tên khách hàng, văn phòng trung tâm phục vụ đường dây, khoảng cách từ văn phòng trung tâm, và những thông tin liên quan khác. Khi chúng tôi có một tin nhắn hoàn chỉnh với tất cả dữ liệu liên quan, chúng tôi có thể quyết định gói dịch vụ nào để chào mời khách hàng. Trong kịch bản này, quyết định được hoãn lại cho đến cuối cùng, vì vậy chúng tôi có thể sử dụng Giấy Chuyển Đề để thu thập thông tin cần thiết. Tuy nhiên, chúng tôi cần xem xét liệu chúng tôi có thực sự cần tính linh hoạt của Giấy Chuyển Đề hay không. Ngược lại, một chuỗi ống và bộ lọc được kết nối cứng có thể là đủ.
Một trong những nhược điểm của Bộ Định Tuyến Dựa Trên Nội Dung là nó phải tích hợp kiến thức về từng người nhận có thể và các quy tắc định tuyến liên quan đến từng người nhận đó. Theo tinh thần của việc gắn kết lỏng lẻo, có thể không mong muốn có một thành phần trung tâm tích hợp kiến thức về nhiều thành phần khác. Một giải pháp thay thế cho Bộ Định Tuyến Dựa Trên Nội Dung là Kênh Xuất Bản-Đăng Ký kết hợp với một loạt Bộ Lọc Tin Nhắn như đã được mô tả trong Bộ Lọc Tin Nhắn. Giải pháp này cho phép mỗi người nhận tự quyết định tin nhắn nào để xử lý nhưng gặp phải nguy cơ xử lý tin nhắn trùng lặp. Một lựa chọn khác để cho phép các người nhận cá nhân quyết định liệu có xử lý một tin nhắn cụ thể hay không là sử dụng một phiên bản đã được sửa đổi của Giấy Chuyển Hướng hoạt động như một Chuỗi Trách Nhiệm như đã được mô tả trong [GoF]. Chuỗi Trách Nhiệm cho phép mỗi thành phần chấp nhận một tin nhắn hoặc chuyển nó cho thành phần tiếp theo trong danh sách. Giấy Chuyển Hướng là một danh sách tĩnh của tất cả các bên tham gia. Điều này vẫn ngụ ý rằng một thành phần trung tâm phải có kiến thức về tất cả các người nhận có thể. Tuy nhiên, thành phần đó không cần phải biết mỗi thành phần tiêu thụ tin nhắn nào.

Việc sử dụng Giấy Chuyển Đổi tránh được rủi ro của việc xử lý thông điệp bị trùng lặp. Tương tự, rất dễ để xác định nếu một thông điệp không được xử lý bởi bất kỳ thành phần nào. Sự trao đổi chính là xử lý chậm hơn và lưu lượng mạng gia tăng. Trong khi một Bộ Điều Hướng Dựa Trên Nội Dung phát hành một thông điệp duy nhất bất kể số lượng hệ thống, phương pháp Giấy Chuyển Đổi phát hành một số lượng thông điệp trung bình bằng một nửa số hệ thống. Chúng ta có thể giảm số lượng này nếu sắp xếp các hệ thống theo cách mà những hệ thống nhận thông điệp đầu tiên có khả năng xử lý thông điệp cao hơn, nhưng số lượng thông điệp sẽ có khả năng vẫn cao hơn so với một Bộ Điều Hướng Dựa Trên Nội Dung dự đoán.
Có những trường hợp mà chúng ta cần kiểm soát nhiều hơn một danh sách tuần tự đơn giản hoặc chúng ta cần thay đổi luồng của một thông điệp dựa trên các kết quả trung gian. Quản lý Quy trình có thể đáp ứng những yêu cầu này vì nó hỗ trợ điều kiện phân nhánh, tách nhánh và hợp nhất. Về cơ bản, Lịch trình Định tuyến là một trường hợp đặc biệt của một quy trình kinh doanh được cấu hình động. Những đánh đổi giữa việc sử dụng Lịch trình Định tuyến và sử dụng một Quản lý Quy trình trung tâm cần được xem xét cẩn thận. Một Lịch trình Định tuyến động kết hợp những lợi ích của một điểm bảo trì trung tâm với hiệu quả của một giải pháp cứng nhắc. Tuy nhiên, khi độ phức tạp gia tăng, việc phân tích và gỡ lỗi hệ thống có thể trở nên khó khăn hơn, vì thông tin trạng thái định tuyến phân bố trên các thông điệp. Ngoài ra, khi ngữ nghĩa của định nghĩa quy trình bắt đầu bao gồm các cấu trúc như quyết định, tách nhánh và hợp nhất, tệp cấu hình có thể trở nên khó hiểu và khó duy trì. Chúng ta có thể bao gồm các câu lệnh điều kiện bên trong bảng định tuyến và tăng cường các mô-đun định tuyến trong mỗi thành phần để giải thích các lệnh điều kiện nhằm xác định vị trí định tuyến tiếp theo. Tuy nhiên, chúng ta cần cẩn thận để không làm quá tải sự đơn giản của giải pháp này với các chức năng bổ sung. Khi chúng ta yêu cầu loại độ phức tạp này, có thể là một ý tưởng hay để từ bỏ hiệu quả thời gian chạy của Lịch trình Định tuyến và bắt đầu sử dụng một Quản lý Quy trình mạnh mẽ hơn.
| Ví dụ: Giấy chuyển phát như một dịch vụ kết hợp Khi tạo ra một kiến trúc hướng dịch vụ, một chức năng logic đơn lẻ thường được cấu thành từ nhiều bước độc lập. Tình huống này thường xảy ra vì hai lý do chính. Thứ nhất, các ứng dụng đóng gói có xu hướng cung cấp các giao diện tinh vi dựa trên các API nội bộ của chúng. Khi tích hợp các gói này vào một giải pháp tích hợp, chúng ta muốn làm việc ở mức độ tr-abstraction cao hơn. Ví dụ, thao tác "Tài khoản mới" có thể yêu cầu nhiều bước bên trong một hệ thống thanh toán: Tạo một khách hàng mới, chọn một kế hoạch dịch vụ, thiết lập các thuộc tính địa chỉ, xác minh dữ liệu tín dụng, và v.v. Thứ hai, một chức năng logic đơn lẻ có thể được phân tán qua nhiều hệ thống khác nhau. Chúng ta muốn ẩn thực tế này khỏi các hệ thống khác để có quyền linh hoạt giao lại trách nhiệm giữa các hệ thống mà không ảnh hưởng đến phần còn lại của giải pháp tích hợp. Chúng ta có thể dễ dàng sử dụng một Giấy Chuyển Đường để thực hiện nhiều bước nội bộ phản ứng với một thông điệp yêu cầu đơn lẻ. Giấy Chuyển Đường cho chúng ta sự linh hoạt để thực hiện các yêu cầu khác nhau từ cùng một kênh. Giấy Chuyển Đường thực hiện chuỗi các bước riêng lẻ nhưng xuất hiện cho bên ngoài như một bước đơn lẻ. Sử dụng Biên Nhận Lưu Hành như một Dịch Vụ Tích Hợp
|
| Ví dụ: WS-Routing Thường xuyên, một yêu cầu dịch vụ Web phải được chuyển hướng qua nhiều trung gian. Để phục vụ cho mục đích này, Microsoft đã định nghĩa đặc tả Giao thức Chuyển hướng Dịch vụ Web (WS-Routing). WS-Routing là một giao thức dựa trên SOAP để chuyển hướng tin nhắn từ một người gửi qua một chuỗi trung gian đến một người nhận. Ngữ nghĩa của WS-Routing phong phú hơn so với Ghi chú Chuyển hướng, nhưng một Ghi chú Chuyển hướng có thể được triển khai dễ dàng trong WS-Routing. Ví dụ sau đây cho thấy tiêu đề SOAP cho một tin nhắn được chuyển hướng từ nút A đến nút D qua các trung gian B và C (được biểu thị bởi phần tử <wsrp:via>). <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2001/06/soap-envelope"> <SOAP-ENV:Header> <wsrp:path xmlns:wsrp="http://schemas.xmlsoap.org/rp/"> <wsrp:action>http://www.im.org/chat</wsrp:action> <wsrp:to>soap://D.com/some/endpoint</wsrp:to> <wsrp:fwd> <wsrp:via>soap://B.com</wsrp:via> <wsrp:via>soap://C.com</wsrp:via> </wsrp:fwd> <wsrp:from>soap://A.com/some/endpoint</wsrp:from> <wsrp:id>uuid:84b9f5d0-33fb-4a81-b02b-5b760641c1d6</wsrp:id> </wsrp:path> </SOAP-ENV:Header> <SOAP-ENV:Body> ... </SOAP-ENV:Body> </SOAP-ENV:Envelope> Giống như hầu hết các đặc tả dịch vụ Web, WS-Routing có thể sẽ phát triển theo thời gian và/hoặc được hợp nhất với các đặc tả khác. Chúng tôi đã đưa ra ví dụ này như một cái nhìn tổng quan về hướng đi của cộng đồng dịch vụ Web liên quan đến việc định tuyến. |
Bản lưu chuyển hướng dẫn cho thấy cách một thông điệp có thể được chuyển qua một loạt các bước xử lý động. Giải pháp của Bản lưu chuyển hướng dựa trên hai giả định chính: Chuỗi các bước xử lý phải được xác định trước, và chuỗi này là tuyến tính. Trong nhiều trường hợp, những giả định này có thể không được thực hiện. Ví dụ, các quyết định chuyển hướng có thể phải được đưa ra dựa trên các kết quả trung gian. Hoặc, các bước xử lý có thể không theo thứ tự, nhưng nhiều bước có thể được thực hiện song song.
| Làm thế nào chúng ta có thể định tuyến một thông điệp qua nhiều bước xử lý khi các bước cần thiết có thể không được biết đến vào thời điểm thiết kế và có thể không theo thứ tự? |
Một trong những lợi thế chính của kiểu kiến trúc Pip và Bộ lọc là khả năng kết hợp các đơn vị xử lý riêng lẻ ("bộ lọc") thành một chuỗi bằng cách kết nối chúng với các kênh ("ống"). Mỗi thông điệp sau đó được định tuyến qua chuỗi các đơn vị xử lý (hoặc thành phần). Nếu chúng ta cần có khả năng thay đổi chuỗi cho mỗi thông điệp, chúng ta có thể sử dụng nhiều Bộ định tuyến Dựa trên Nội dung. Giải pháp này cung cấp tính linh hoạt tối đa nhưng có nhược điểm là logic định tuyến được phân tán trên nhiều thành phần định tuyến. Routing Slip cung cấp một điểm kiểm soát trung tâm bằng cách tính toán đường đi của thông điệp trước, nhưng không cung cấp khả năng linh hoạt để định tuyến lại thông điệp dựa trên các kết quả trung gian hoặc để thực hiện nhiều bước đồng thời.
Chúng ta có thể thu được sự linh hoạt và duy trì một điểm kiểm soát trung tâm nếu, sau mỗi đơn vị xử lý riêng lẻ, chúng ta trả lại quyền kiểm soát cho một thành phần trung tâm. Thành phần đó có thể xác định các đơn vị xử lý tiếp theo sẽ được thực hiện. Theo cách tiếp cận này, chúng ta sẽ kết thúc với một luồng quy trình thay đổi: thành phần trung tâm, đơn vị xử lý, thành phần trung tâm, đơn vị xử lý, và cứ như vậy. Kết quả là, đơn vị trung tâm nhận được một thông điệp sau mỗi bước xử lý riêng lẻ. Khi thông điệp đến, thành phần trung tâm phải xác định bước xử lý tiếp theo sẽ được thực hiện dựa trên các kết quả trung gian và bước hiện tại trong chuỗi. Điều này sẽ yêu cầu các đơn vị xử lý riêng lẻ trả lại đủ thông tin cho đơn vị trung tâm để đưa ra quyết định này. Tuy nhiên, cách tiếp cận này sẽ làm cho các đơn vị xử lý phụ thuộc vào sự tồn tại của đơn vị trung tâm vì họ có thể phải truyền qua thông tin không cần thiết mà không liên quan đến đơn vị xử lý, mà chỉ liên quan đến thành phần trung tâm. Nếu chúng ta muốn tách rời các bước xử lý riêng lẻ và định dạng thông điệp liên quan khỏi đơn vị trung tâm, chúng ta cần cung cấp cho đơn vị trung tâm một dạng "ký ức" nào đó cho nó biết bước nào trong chuỗi đã được thực hiện gần nhất.
| Sử dụng một bộ xử lý trung tâm, một Quản lý Quy trình, để duy trì trạng thái của chuỗi và xác định bước xử lý tiếp theo dựa trên các kết quả trung gian.
|
Trước hết, hãy làm rõ rằng thiết kế và cấu hình của một Quản lý Quy trình là một chủ đề khá rộng. Chúng ta có thể chắc chắn rằng có thể viết cả một cuốn sách (Có thể là Tập 2?) với các mẫu liên quan đến thiết kế quy trình làm việc hoặc quản lý quy trình kinh doanh. Do đó, mẫu này được khuech trương chủ yếu để "hoàn thiện" chủ đề của các mẫu định tuyến và cung cấp một chỉ dẫn vào hướng của quy trình và mô hình hóa quy trình. Nó không phải là một hệ thống toàn diện về thiết kế quy trình kinh doanh.
Việc sử dụng một Quản lý Quy trình dẫn đến một mô hình dòng tin nhắn gọi là mô hình tâm và nan (hub-and-spoke) (xem sơ đồ). Một tin nhắn đến khởi tạo Quản lý Quy trình. Chúng tôi gọi tin nhắn này là tin nhắn kích hoạt. Dựa trên các quy tắc bên trong Quản lý Quy trình, nó gửi một tin nhắn (1) đến bước xử lý đầu tiên, được thực hiện bởi Đơn vị Xử lý A. Sau khi đơn vị A hoàn thành nhiệm vụ của mình, nó gửi một tin nhắn phản hồi trở lại Quản lý Quy trình. Quản lý Quy trình xác định bước tiếp theo cần được thực hiện và gửi một tin nhắn (2) đến đơn vị xử lý tiếp theo. Kết quả là, tất cả lưu lượng tin nhắn đều chạy qua "trung tâm" trung tâm này, do đó có thuật ngữ tâm và nan. Nhược điểm của yếu tố điều khiển trung tâm này là nguy cơ biến Quản lý Quy trình thành một điểm nghẽn hiệu suất.
Tính linh hoạt của Quản lý Quy trình vừa là sức mạnh lớn nhất vừa là điểm yếu của nó. Một Quản lý Quy trình có thể thực hiện bất kỳ chuỗi bước nào, tuần tự hoặc song song. Do đó, gần như mọi vấn đề tích hợp đều có thể được giải quyết bằng một Quản lý Quy trình. Tương tự, hầu hết các mẫu được giới thiệu trong chương này có thể được thực hiện bằng cách sử dụng Quản lý Quy trình. Trên thực tế, nhiều nhà cung cấp EAI khiến bạn tin rằng mọi vấn đề tích hợp đều là một vấn đề quy trình. Chúng tôi nghĩ rằng việc sử dụng Quản lý Quy trình cho mọi tình huống có thể là thừa thãi. Điều này có thể phân tâm khỏi vấn đề thiết kế cốt lõi và cũng gây ra sự chậm trễ hiệu suất đáng kể.
Một trong những chức năng then chốt của Quản lý Quy trình là duy trì trạng thái giữa các thông điệp. Ví dụ, khi đơn vị xử lý thứ hai trả về một thông điệp cho Quản lý Quy trình, Quản lý Quy trình cần phải nhớ rằng đây là bước 2 trong một chuỗi nhiều bước. Chúng ta không muốn gắn kiến thức này với đơn vị xử lý vì cùng một đơn vị có thể xuất hiện nhiều lần trong cùng một quy trình. Ví dụ, Đơn vị Xử lý B có thể vừa là bước 2 vừa là bước 4 của một quy trình duy nhất. Do đó, cùng một thông điệp hồi đáp do Đơn vị Xử lý B gửi có thể kích hoạt Quản lý Quy trình thực hiện bước 3 hoặc bước 5 dựa trên ngữ cảnh của quy trình. Để thực hiện điều này mà không làm phức tạp đơn vị xử lý, Quản lý Quy trình cần duy trì vị trí hiện tại trong thực thi quy trình.
Có ích cho Quản lý Quy trình khi có thể lưu trữ thông tin bổ sung ngoài vị trí hiện tại trong quy trình. Quản lý Quy trình có thể lưu trữ các kết quả trung gian từ các xử lý trước đó nếu chúng có liên quan đến các bước sau. Ví dụ, nếu kết quả của bước 1 có liên quan đến một bước sau đó, Quản lý Quy trình có thể lưu thông tin này mà không làm phiền các đơn vị xử lý tiếp theo trong việc truyền dữ liệu qua lại. Điều này cho phép các bước xử lý riêng lẻ độc lập với nhau vì chúng không phải lo lắng về dữ liệu được sản xuất hoặc tiêu thụ bởi các đơn vị khác. Thực chất, Quản lý Quy trình đóng vai trò như một Phiếu Giữ chỗ được giải thích ở phần sau.
Vì việc thực hiện quy trình có thể kéo dài qua nhiều bước và do đó có thể mất nhiều thời gian, Trình Quản Lý Quy Trình cần chuẩn bị để nhận các thông điệp kích hoạt mới trong khi một quy trình khác vẫn đang thực thi. Để quản lý nhiều thực thi song song, Trình Quản Lý Quy Trình tạo ra một thực thể quy trình mới cho mỗi thông điệp kích hoạt đến. Thực thể quy trình lưu trữ trạng thái liên quan đến việc thực hiện quy trình được khởi xướng bởi thông điệp kích hoạt. Trạng thái bao gồm bước thực hiện hiện tại của quy trình và bất kỳ dữ liệu liên quan nào. Mỗi thực thể quy trình được xác định bởi một định danh quy trình duy nhất.
Việc tách biệt các khái niệm về định nghĩa quy trình (còn được gọi là mẫu quy trình) và một trường hợp quy trình là rất quan trọng. Định nghĩa quy trình là một cấu trúc thiết kế xác định chuỗi các bước cần thực hiện, có thể so sánh với một lớp trong các ngôn ngữ lập trình hướng đối tượng. Trường hợp quy trình là một thực thi hoạt động của một mẫu cụ thể, có thể so sánh với một thực thể đối tượng trong một ngôn ngữ OO. Biểu đồ bên dưới cho thấy một ví dụ đơn giản với một định nghĩa quy trình và hai trường hợp quy trình. Trường hợp đầu tiên (định danh quy trình 1234) hiện đang thực hiện bước 1, trong khi trường hợp quy trình thứ hai (định danh quy trình 5678) đang thực hiện các bước 2 và 5 song song.
Nhiều phiên bản quy trình dựa trên một định nghĩa quy trình

Bởi vì nhiều phiên bản quy trình có thể đang được thực thi đồng thời, Quản lý Quy trình cần có khả năng liên kết một tin nhắn đến phiên bản chính xác. Ví dụ, nếu Quản lý Quy trình trong ví dụ trước nhận một tin nhắn từ một đơn vị xử lý, thì phiên bản quy trình nào là tin nhắn đó dành cho? Nhiều phiên bản có thể đang thực hiện cùng một bước, vì vậy Quản lý Quy trình không thể suy ra phiên bản từ tên kênh hoặc loại tin nhắn. Yêu cầu liên kết một tin nhắn đến một phiên bản quy trình khiến chúng ta nghĩ đến Mã định danh Tương quan. Mã định danh Tương quan cho phép một thành phần liên kết một tin nhắn phản hồi đến yêu cầu ban đầu bằng cách lưu trữ một mã định danh duy nhất trong tin nhắn phản hồi có thể liên kết nó với tin nhắn yêu cầu. Bằng cách sử dụng mã định danh này, thành phần có thể khớp phản hồi với yêu cầu chính xác ngay cả khi thành phần đã gửi nhiều yêu cầu và các phản hồi đến không theo thứ tự. Quản lý Quy trình cũng cần một cơ chế tương tự. Khi Quản lý Quy trình nhận một tin nhắn từ một đơn vị xử lý, nó phải có khả năng liên kết tin nhắn với phiên bản quy trình đã gửi tin nhắn đến đơn vị xử lý. Quản lý Quy trình phải bao gồm một Mã định danh Tương quan bên trong các tin nhắn mà nó gửi đến các đơn vị xử lý. Thành phần cần trả lại mã định danh này trong tin nhắn phản hồi như một Mã định danh Tương quan. Nếu mỗi phiên bản quy trình duy trì một mã định danh quy trình duy nhất, nó có thể sử dụng mã định danh đó như một Mã định danh Tương quan cho các tin nhắn.
Rõ ràng rằng quản lý trạng thái là một tính năng quan trọng của Trình quản lý quy trình. Vậy làm thế nào mà các mẫu trước đó lại có thể hoạt động mà không quản lý trạng thái? Trong kiến trúc Pipes and Filters truyền thống, các ống (tức là, các Kênh Tin nhắn) quản lý trạng thái. Để tiếp tục với ví dụ trước, nếu chúng tôi triển khai quy trình với các thành phần kết nối cứng được kết nối qua các Kênh Tin nhắn, nó sẽ trông giống như hình ảnh sau. Nếu chúng ta giả định rằng hệ thống này đang ở trong trạng thái tương tự như ví dụ trước (tức là, có hai thể hiện quy trình), thì điều này tương đương với một tin nhắn có định danh 1234 nằm trong một kênh chờ được xử lý bởi thành phần 1 và hai tin nhắn có định danh 5678 chờ được xử lý bởi các thành phần 2 và 5 tương ứng. Ngay khi thành phần 1 tiêu thụ tin nhắn và hoàn thành các nhiệm vụ xử lý của nó, nó phát đi một tin nhắn mới đến các thành phần 2 và 4, hành vi hoàn toàn giống như Trình quản lý quy trình trong ví dụ trước.
Giữ Trạng Thái Trong Kênh

Thật đáng chú ý how the message flow notation được sử dụng cho ví dụ này giống như một sơ đồ hoạt động UML thường được sử dụng để mô hình hóa hành vi của các thành phần Quản lý Quy trình. Thực sự, chúng ta có thể sử dụng một ký hiệu trừu tượng để mô hình hóa hành vi của hệ thống trong quá trình thiết kế và sau đó quyết định xem chúng ta muốn triển khai hành vi đó dưới dạng kiến trúc ống và bộ lọc phân tán hay dưới dạng kiến trúc trung tâm và các nhánh sử dụng một Quản lý Quy trình trung tâm. Mặc dù chúng ta không có đủ chỗ trong cuốn sách này để đi sâu vào thiết kế các mô hình quy trình, nhiều mẫu trong ngôn ngữ này vẫn áp dụng khi thiết kế một mô hình quy trình.
Giống như hầu hết các quyết định kiến trúc, việc triển khai một Quản lý Quy trình trung tâm hoặc một kiến trúc ống dẫn và bộ lọc phân tán không phải là một quyết định đơn giản có hoặc không. Trong nhiều trường hợp, việc sử dụng nhiều thành phần Quản lý Quy trình, mỗi thành phần đảm nhận một khía cạnh cụ thể của một quy trình lớn hơn, là hợp lý nhất. Các thành phần Quản lý Quy trình có thể sau đó giao tiếp với nhau thông qua một kiến trúc ống dẫn và bộ lọc.
Quản lý trạng thái một cách rõ ràng bên trong một Quản lý Quy trình có thể yêu cầu một thành phần phức tạp hơn, nhưng nó cho phép báo cáo quy trình mạnh mẽ hơn nhiều. Ví dụ, hầu hết các triển khai của một Quản lý Quy trình cung cấp khả năng truy vấn trạng thái của các phiên bản quy trình. Điều này giúp dễ dàng thấy được có bao nhiêu đơn hàng đang chờ phê duyệt hoặc đã bị tạm dừng do thiếu hàng tồn kho. Chúng tôi cũng có thể cho mỗi khách hàng biết trạng thái đơn hàng của họ. Nếu chúng tôi sử dụng các kênh cứng, chúng tôi sẽ phải kiểm tra tất cả các kênh để có được thông tin tương tự. Tính năng này của Quản lý Quy trình không chỉ quan trọng cho việc báo cáo mà còn cho việc gỡ lỗi. Sử dụng một Quản lý Quy trình trung tâm giúp dễ dàng truy xuất trạng thái hiện tại của một quy trình và dữ liệu liên quan. Gỡ lỗi một kiến trúc phân phối hoàn toàn có thể khó khăn hơn nhiều và gần như không thể nếu không có sự hỗ trợ của các cơ chế như Lịch sử Tin nhắn hoặc Kho Tin nhắn.
Hầu hết các triển khai EAI thương mại đều bao gồm một thành phần Quản lý Quy trình kết hợp với các công cụ trực quan để mô hình hóa định nghĩa quy trình. Hầu hết các công cụ trực quan sử dụng ký hiệu giống như sơ đồ hoạt động UML vì ngữ nghĩa của Quản lý Quy trình và sơ đồ hoạt động tương đối giống nhau. Thêm vào đó, sơ đồ hoạt động là một đại diện hình ảnh tốt cho nhiều nhiệm vụ thực hiện song song. Đến gần đây, hầu hết các công cụ của nhà cung cấp đã chuyển đổi ký hiệu trực quan thành định nghĩa quy trình nội bộ, sở hữu của nhà cung cấp để thực thi bởi động cơ quy trình. Tuy nhiên, những nỗ lực thúc đẩy tiêu chuẩn hóa các khía cạnh khác nhau của hệ thống phân tán dưới sự bảo trợ của dịch vụ Web đã không bỏ qua vai trò quan trọng của các định nghĩa quy trình. Ba "ngôn ngữ" được đề xuất đã xuất hiện như một kết quả của những nỗ lực này. Microsoft đã định nghĩa XLANG, được hỗ trợ bởi các công cụ mô hình hóa điều phối BizTalk của nó. IBM soạn thảo WSFL, Ngôn ngữ Dòng Dịch vụ Web [WSFL]. Gần đây, cả hai công ty đã hợp lực để tạo ra đặc tả cho BPEL4WS, Ngôn ngữ Thực thi Quy trình Kinh doanh cho Dịch vụ Web (xem [BPEL4WS]). BPEL4WS là một ngôn ngữ mạnh mẽ mô tả một mô hình quy trình dưới dạng tài liệu XML. Mục đích là để định nghĩa một ngôn ngữ trung gian tiêu chuẩn hóa giữa các công cụ mô hình hóa quy trình và các động cơ Quản lý Quy trình. Bằng cách này, chúng ta có thể mô hình hóa các quy trình của mình với sản phẩm của Nhà cung cấp X và quyết định thực thi quy trình trên triển khai động cơ quy trình của Nhà cung cấp Y. Để biết thêm thông tin về tác động của tiêu chuẩn dịch vụ Web đến tích hợp, xem "Các Tiêu chuẩn Mới Nổi và Tương Lai trong Tích hợp Doanh Nghiệp" trong Chương 14.
Bản chất của một định nghĩa quy trình có thể được mô tả bằng các thuật ngữ khá đơn giản. Khối xây dựng cơ bản là một hoạt động (đôi khi được gọi là nhiệm vụ hoặc hành động). Thông thường, một hoạt động có thể gửi một tin nhắn đến một thành phần khác, chờ một tin nhắn đến, hoặc thực hiện một chức năng cụ thể ở bên trong (ví dụ: một Bộ dịch Tin nhắn). Các hoạt động có thể được kết nối theo cách tuần tự, hoặc nhiều hoạt động có thể được thực hiện song song bằng cách sử dụng một cấu trúc phân nhánh và hợp nhất. Một phân nhánh cho phép nhiều hoạt động thực hiện cùng một lúc. Nó về mặt ngữ nghĩa tương đương với một Kênh Xuất bản-Đăng ký trong một kiến trúc Ống và L фilt. Một hợp nhất đồng bộ hóa nhiều luồng thực thi song song trở lại một luồng duy nhất. Việc thực thi sau một hợp nhất chỉ có thể tiếp tục nếu tất cả các luồng song song đã hoàn thành các hoạt động tương ứng của chúng. Trong phong cách Ống và L фilt, một Bộ tổng hợp thường phục vụ mục đích này. Mẫu quy trình cũng phải có khả năng xác định một nhánh, hoặc điểm quyết định, để con đường thực thi có thể thay đổi dựa trên nội dung của một trường tin nhắn. Chức năng này tương đương với một Bộ định tuyến dựa trên nội dung. Nhiều công cụ mô hình hóa bao gồm khả năng thiết kế một cấu trúc vòng lặp, nhưng thực sự đây là một trường hợp đặc biệt của nhánh. Hình sau đây nhấn mạnh những điểm tương đồng ngữ nghĩa giữa một định nghĩa quy trình (được mô tả dưới dạng sơ đồ hoạt động UML) và một triển khai Ống và L фilt sử dụng các mẫu được định nghĩa trong ngôn ngữ mẫu này, mặc dù các triển khai vật lý rất khác nhau.
Ví dụ về Sơ đồ Hoạt động UML và Triển khai Tương ứng theo Mô hình Ống và Bộ lọc

Chúng tôi đã so sánh kiến trúc cơ bản Pipes and Filters, Routing Slip và Process Manager nhiều lần. Chúng tôi đã tổng hợp những khác biệt chính giữa các mẫu này vào bảng dưới đây để làm nổi bật các sự đánh đổi liên quan đến việc lựa chọn kiến trúc phù hợp.
Cống và bộ lọc phân phối | Phiếu chuyển phát | Quản lý quy trình trung tâm |
|---|---|---|
Hỗ trợ luồng tin nhắn phức tạp | Chỉ hỗ trợ luồng đơn giản, tuyến tính. | Hỗ trợ luồng tin nhắn phức tạp |
Khó thay đổi luồng | Dễ dàng thay đổi quy trình | Dễ dàng thay đổi luồng |
Không có điểm thất bại trung tâm | Điểm tiềm tàng của sự cố (tính toán bảng định tuyến) | Điểm tiềm tàng của sự cố |
Kiến trúc thời gian chạy phân phối hiệu quả | Chủ yếu phân phối | Kiến trúc trung tâm và chi nhánh có thể dẫn đến điểm nghẽn. |
Không có điểm trung tâm về quản lý và báo cáo | Điểm trung tâm của quản lý, nhưng không báo cáo. | Điểm trung tâm của quản lý và báo cáo |
Một điểm trung tâm của kiểm soát và quản lý trạng thái cũng có thể đồng nghĩa với một điểm trung tâm của sự cố gắng hoặc một nút thắt về hiệu suất. Vì lý do này, hầu hết các triển khai Quản lý Quy trình cho phép lưu trữ trạng thái của các phiên bản quy trình trong một tệp hoặc trong một cơ sở dữ liệu. Triển khai có thể tận dụng các cơ chế lưu trữ dữ liệu dư thừa thường được triển khai trong các hệ thống cơ sở dữ liệu cấp doanh nghiệp. Thông thường, cũng có thể chạy nhiều Quản lý Quy trình song song. Việc phân tán các Quản lý Quy trình thường rất dễ dàng vì các phiên bản quy trình độc lập với nhau. Điều này cho phép chúng ta phân phối các phiên bản quy trình trên nhiều động cơ quy trình khác nhau. Nếu động cơ quy trình lưu trữ toàn bộ thông tin trạng thái trong một cơ sở dữ liệu chung, hệ thống có thể trở nên đủ mạnh mẽ để tồn tại sau khi một động cơ quy trình gặp sự cố - một động cơ khác có thể đơn giản tiếp tục từ nơi động cơ trước đó đã dừng lại. Nhược điểm của cách tiếp cận này là trạng thái của mỗi phiên bản quy trình phải được lưu trữ trong một cơ sở dữ liệu trung tâm sau mỗi bước xử lý. Điều này có thể dễ dàng biến cơ sở dữ liệu thành một nút thắt về hiệu suất mới. Như thường lệ, kiến trúc sư phải tìm ra sự cân bằng đúng giữa hiệu suất, độ bền, chi phí và khả năng bảo trì.
| Ví dụ: Nhân viên môi giới vay vốn Triển khai MSMQ của ví dụ Broker Cho Vay (xem "Triển khai không đồng bộ với MSMQ" trong Chương 9) triển khai một Quản lý Quy trình đơn giản. Ví dụ này tạo ra chức năng Quản lý Quy trình từ đầu bằng cách lập trình các lớp C# cho cả quản lý quy trình và các trường hợp quy trình. Triển khai TIBCO của cùng một ví dụ (xem "Triển khai không đồng bộ với TIBCO ActiveEnterprise" trong Chương 9) sử dụng một công cụ quản lý quy trình thương mại. |
| Ví dụ: Trình Quản Lý Điều Phối Microsoft BizTalk Hầu hết các công cụ EAI thương mại đều bao gồm khả năng thiết kế và thực thi quy trình. Ví dụ, Microsoft BizTalk cho phép người dùng thiết kế các định nghĩa quy trình thông qua công cụ Orchestration Designer được tích hợp vào môi trường lập trình Visual Studio .NET. Nhà thiết kế điều phối Microsoft BizTalk 2004
Ví dụ đơn giản về việc điều phối này nhận một tin nhắn đơn hàng và thực hiện hai hoạt động song song. Một hoạt động tạo ra một tin nhắn yêu cầu cho hệ thống tồn kho, và hoạt động còn lại tạo ra một tin nhắn yêu cầu cho hệ thống tín dụng. Khi cả hai phản hồi được nhận, quy trình sẽ tiếp tục. Ký hiệu hình ảnh giúp dễ dàng theo dõi định nghĩa quy trình. |
Nhiều mẫu trong chương này trình bày các cách để định tuyến tin nhắn đến đích thích hợp mà không cần ứng dụng nguồn biết được đích cuối cùng của tin nhắn. Hầu hết các mẫu tập trung vào các loại logic định tuyến cụ thể. Tuy nhiên, tổng hợp lại, những mẫu này giải quyết một vấn đề lớn hơn.
| Làm thế nào bạn có thể tách rời điểm đến của một thông điệp khỏi người gửi và duy trì kiểm soát trung tâm đối với dòng chảy của các thông điệp? |
Sử dụng một Kênh Tin nhắn đơn giản đã cung cấp một mức độ gián tiếp giữa người gửi và người nhận; người gửi chỉ biết về kênh mà không biết về người nhận. Tuy nhiên, nếu mỗi người nhận có kênh riêng của mình, mức độ gián tiếp này trở nên ít có ý nghĩa hơn. Thay vì biết địa chỉ của người nhận, người gửi phải biết tên kênh đúng mà liên kết với người nhận.
Hầu hết các giải pháp nhắn tin không tầm thường đều kết nối nhiều ứng dụng khác nhau. Nếu chúng ta tạo ra các kênh nhắn tin riêng biệt để kết nối từng ứng dụng với từng ứng dụng khác, số lượng kênh trong hệ thống sẽ nhanh chóng bùng nổ thành một số lượng không thể quản lý, dẫn đến tình trạng tích hợp rối beng.
Tích hợp mì Spaghetti như một kết quả của các kết nối điểm-đến-điểm

Biểu đồ này minh họa rằng các kênh trực tiếp giữa các ứng dụng riêng lẻ có thể dẫn đến sự bùng nổ về số lượng kênh và giảm bớt nhiều lợi ích của việc định tuyến thông điệp qua các kênh ngay từ đầu. Những loại kiến trúc tích hợp này thường là kết quả của một giải pháp phát triển theo thời gian. Đầu tiên, hệ thống chăm sóc khách hàng phải giao tiếp với hệ thống kế toán. Sau đó, hệ thống chăm sóc khách hàng cũng được kỳ vọng sẽ truy xuất thông tin từ hệ thống kho hàng, và hệ thống vận chuyển sẽ cập nhật hệ thống kế toán với các khoản phí vận chuyển. Rất dễ nhận thấy rằng "thêm một mảnh nữa" có thể nhanh chóng làm suy giảm tính toàn vẹn tổng thể của giải pháp.
Yêu cầu một ứng dụng phải giao tiếp rõ ràng với tất cả các ứng dụng khác có thể nhanh chóng ảnh hưởng đến khả năng bảo trì của hệ thống. Ví dụ, nếu địa chỉ khách hàng thay đổi trong hệ thống chăm sóc khách hàng, hệ thống này sẽ phải gửi tin nhắn đến tất cả các hệ thống duy trì bản sao của địa chỉ khách hàng. Mỗi khi một hệ thống mới được thêm vào, hệ thống chăm sóc khách hàng sẽ phải biết liệu hệ thống đó có sử dụng địa chỉ hay không và phải được thay đổi cho phù hợp.
Các Kênh Xuất Bản - Đăng Ký cung cấp một hình thức định tuyến cơ bản, trong đó tin nhắn được gửi đến từng ứng dụng đã đăng ký với kênh cụ thể đó. Điều này hoạt động trong các tình huống phát sóng đơn giản, nhưng các quy tắc định tuyến thường phức tạp hơn nhiều. Ví dụ, một tin nhắn đơn hàng đến có thể cần phải được định tuyến đến một hệ thống khác dựa trên kích thước hoặc bản chất của đơn hàng. Để tránh làm cho các ứng dụng chịu trách nhiệm xác định đích đến cuối cùng của một tin nhắn, phần mềm trung gian nên bao gồm một Bộ định tuyến Tin nhắn có thể định tuyến các tin nhắn đến đích đến thích hợp.
Các mẫu định tuyến tin nhắn cá nhân đã giúp chúng tôi tách rời người gửi khỏi người nhận. Ví dụ, Danh sách Người Nhận có thể giúp rút gọn kiến thức về tất cả người nhận ra khỏi người gửi và vào lớp phần mềm trung gian. Việc chuyển logic vào lớp phần mềm trung gian giúp chúng tôi theo hai cách. Thứ nhất, nhiều bộ phần mềm thương mại và bộ EAI cung cấp các công cụ và thư viện chuyên biệt để thực hiện những loại tác vụ này. Điều này đơn giản hóa nỗ lực lập trình vì chúng tôi không cần phải viết mã liên quan đến Điểm Kết Nối Tin Nhắn, chẳng hạn như Người Tiêu Thụ Dựa Trên Sự Kiện hoặc quản lý luồng. Ngoài ra, việc triển khai logic bên trong lớp phần mềm trung gian cho phép chúng tôi làm cho logic "thông minh" hơn so với việc thực hiện trong ứng dụng. Ví dụ, việc sử dụng Danh sách Người Nhận động có thể tránh các thay đổi mã khi các hệ thống mới được thêm vào giải pháp tích hợp.
Tuy nhiên, việc có một số lượng lớn các thành phần Máy định tuyến Tin nhắn có thể khó quản lý gần như bằng với tình trạng spaghetti tích hợp mà chúng ta đang cố gắng giải quyết.
| Sử dụng một Người trung gian Tin nhắn trung tâm có thể nhận tin nhắn từ nhiều điểm đến, xác định điểm đến chính xác và định tuyến tin nhắn đến kênh đúng. Triển khai các phần bên trong của Người trung gian Tin nhắn bằng cách sử dụng các bộ định tuyến tin nhắn khác.
|
Việc sử dụng một Trung tâm Giao tiếp Tin nhắn đôi khi được gọi là phong cách kiến trúc trung tâm và chóp, đây có vẻ là một tên gọi mô tả khi nhìn vào hình ảnh ở trên.
Mô hình Trung gian Tin nhắn có một phạm vi hơi khác so với hầu hết các mô hình khác được trình bày trong chương này. Đây là một mô hình kiến trúc trái ngược với mô hình thiết kế cá nhân. Do đó, nó có thể so sánh với phong cách kiến trúc Ống dẫn và Bộ lọc, điều này cung cấp cho chúng ta một cách cơ bản để kết nối các thành phần với nhau để tạo ra các luồng tin nhắn phức tạp hơn. Thay vì chỉ kết nối các thành phần riêng lẻ, Trung gian Tin nhắn quan tâm đến các giải pháp lớn hơn và giúp chúng ta đối phó với sự phức tạp không thể tránh khỏi khi quản lý một hệ thống như vậy.
Bộ trung gian tin nhắn không phải là một thành phần đơn nhất. Bên trong, nó sử dụng nhiều mẫu định tuyến tin nhắn được trình bày trong chương này. Vì vậy, khi bạn quyết định sử dụng Bộ trung gian tin nhắn như một mẫu kiến trúc, bạn có thể chọn các mẫu thiết kế Bộ định tuyến tin nhắn phù hợp để triển khai Bộ trung gian tin nhắn.
Lợi thế của việc bảo trì trung tâm của một Trình môi giới Tin nhắn cũng có thể trở thành một nhược điểm. Việc định tuyến tất cả các tin nhắn qua một Trình môi giới Tin nhắn duy nhất có thể biến Trình môi giới Tin nhắn thành một điểm nghẽn nghiêm trọng. Một số kỹ thuật có thể giúp chúng ta giảm bớt vấn đề này. Chẳng hạn, mẫu Trình môi giới Tin nhắn chỉ nói với chúng ta phát triển một thực thể duy nhất thực hiện việc định tuyến. Nó không quy định số lượng phiên bản của thực thể này mà chúng ta triển khai trong hệ thống tại thời điểm triển khai. Nếu thiết kế Trình môi giới Tin nhắn là không trạng thái (tức là, nếu nó chỉ được cấu thành từ các thành phần không trạng thái), chúng ta có thể dễ dàng triển khai nhiều phiên bản của trình môi giới để cải thiện thông lượng. Các thuộc tính của Kênh Điểm-đến-Điểm đảm bảo rằng chỉ một phiên bản của Trình môi giới Tin nhắn tiêu thụ bất kỳ tin nhắn nào đến. Cũng như trong hầu hết các tình huống thực tế, giải pháp cuối cùng thường là sự kết hợp của các mẫu. Tương tự, trong nhiều giải pháp tích hợp phức tạp, có thể hợp lý khi thiết kế nhiều thành phần Trình môi giới Tin nhắn, mỗi thành phần chuyên môn hóa trong một phần cụ thể của giải pháp. Điều này tránh việc tạo ra Trình môi giới Tin nhắn tổng hợp quá phức tạp đến mức không thể duy trì. Mặt đáng chú ý là chúng ta không còn có một điểm bảo trì duy nhất và có thể tạo ra một hình thức mới của Trình môi giới Tin nhắn phức tạp. Một phong cách kiến trúc tuyệt vời sử dụng sự kết hợp của các Trình môi giới Tin nhắn là một hệ thống phân cấp Trình môi giới Tin nhắn. Cấu hình này giống như một cấu hình mạng được tạo thành từ các mạng con riêng lẻ. Nếu một tin nhắn chỉ cần di chuyển giữa hai ứng dụng bên trong một mạng con, Trình môi giới Tin nhắn địa phương có thể quản lý việc định tuyến của tin nhắn. Nếu tin nhắn định hướng đến một mạng con khác, Trình môi giới Tin nhắn địa phương có thể chuyển tin nhắn đến Trình môi giới Tin nhắn trung tâm, sau đó quyết định điểm đến cuối cùng. Trình môi giới Tin nhắn trung tâm thực hiện các chức năng tương tự như Trình môi giới Tin nhắn địa phương, nhưng thay vì tách rời các ứng dụng riêng lẻ, nó tách rời toàn bộ hệ thống con bao gồm nhiều ứng dụng.
"Một Hệ Thống Các Người Trung Gian Tin Nhắn Cung Cấp Sự Tách Biệt Trong Khi Tránh Xa Đại Trung Gian"

Bởi vì mục đích của Broker Tin nhắn là giảm sự kết nối giữa các ứng dụng riêng lẻ, nó thường phải xử lý việc chuyển đổi định dạng dữ liệu tin nhắn giữa các ứng dụng. Có một Broker Tin nhắn trừu tượng hoá việc định tuyến tin nhắn không giúp được ứng dụng gửi nếu nó phải định dạng tin nhắn theo định dạng tin nhắn của (được cho là ẩn giấu) điểm đến. Chương tiếp theo giới thiệu một loạt các mẫu chuyển đổi tin nhắn để giải quyết những vấn đề này. Trong nhiều trường hợp, một Broker Tin nhắn sử dụng Mô hình Dữ liệu Chính bên trong để tránh vấn đề N-bình phương (số lượng bộ chuyển đổi cần thiết để chuyển đổi giữa từng người nhận trong một hệ thống tăng lên theo bình phương số lượng người tham gia).
| Ví dụ: Công cụ EAI thương mại Hầu hết các bộ công cụ EAI thương mại cung cấp các công cụ để đơn giản hóa việc tạo ra các thành phần Bộ trung gian Tin nhắn cho các giải pháp tích hợp. Các bộ công cụ này thường cung cấp một số tính năng hỗ trợ cho việc phát triển và triển khai các Bộ trung gian Tin nhắn:
|
Giới thiệu
Bọc phong bì
Người làm phong phú nội dung
Bộ lọc nội dung
Phiếu giữ đồ
Bộ chuẩn hóa
Mô hình dữ liệu chuẩn
Như đã mô tả trong Bộ chuyển đổi tin nhắn, các ứng dụng cần được tích hợp qua một hệ thống nhắn tin hiếm khi đồng ý về một định dạng dữ liệu chung. Ví dụ, một hệ thống kế toán sẽ có khái niệm khác về đối tượng Khách hàng so với một hệ thống quản lý quan hệ khách hàng. Thêm vào đó, một hệ thống có thể lưu trữ dữ liệu theo mô hình quan hệ, trong khi một ứng dụng khác sử dụng tệp phẳng hoặc tài liệu XML. Việc tích hợp các ứng dụng hiện có thường có nghĩa là chúng ta không có khả năng thay đổi các ứng dụng để làm cho chúng hoạt động dễ dàng hơn với các hệ thống khác. Thay vào đó, giải pháp tích hợp phải thích ứng và giải quyết sự khác biệt giữa các hệ thống khác nhau. Mẫu Bộ chuyển đổi tin nhắn cung cấp một giải pháp chung cho những sự khác biệt về định dạng dữ liệu. Chương này khám phá các biến thể cụ thể của Bộ chuyển đổi tin nhắn.
Hầu hết các hệ thống nhắn tin đặt ra các yêu cầu cụ thể về định dạng và nội dung của tiêu đề tin nhắn. Chúng tôi bọc dữ liệu tải của tin nhắn vào một Bao Bì (Envelope Wrapper) phù hợp với các yêu cầu của cơ sở hạ tầng nhắn tin. Nhiều Bao Bì có thể được kết hợp nếu một tin nhắn được chuyển qua các cơ sở hạ tầng nhắn tin khác nhau.
Một Bộ Làm Giàu Nội Dung là cần thiết nếu hệ thống mục tiêu yêu cầu các trường dữ liệu mà hệ thống gốc không thể cung cấp. Nó có khả năng tra cứu thông tin thiếu hoặc tính toán nó từ dữ liệu có sẵn. Bộ Lọc Nội Dung thì làm điều ngược lại, loại bỏ dữ liệu không mong muốn khỏi một thông điệp. Kiểm Tra Yêu Cầu cũng loại bỏ dữ liệu khỏi một thông điệp nhưng lưu trữ nó để truy xuất sau. Bộ Chuẩn Hóa dịch các thông điệp đến dưới nhiều định dạng khác nhau thành một định dạng chung.
Biến đổi tin nhắn là một chủ đề sâu sắc trong tích hợp. Các Kênh Tin nhắn và Bộ định tuyến Tin nhắn có thể loại bỏ các phụ thuộc cơ bản giữa các ứng dụng bằng cách xóa bỏ nhu cầu một ứng dụng phải biết vị trí của ứng dụng khác.
Một ứng dụng có thể gửi một tin nhắn đến kênh tin nhắn mà không cần lo lắng về ứng dụng nào sẽ tiếp nhận nó. Tuy nhiên, định dạng tin nhắn lại tạo ra một bộ phụ thuộc khác. Nếu một ứng dụng phải định dạng tin nhắn theo định dạng dữ liệu của một ứng dụng khác, thì việc tách rời theo hình thức của kênh tin nhắn thực sự chỉ là một ảo tưởng. Bất kỳ thay đổi nào đối với ứng dụng nhận hoặc việc chuyển đổi từ một ứng dụng nhận sang một ứng dụng khác vẫn cần thay đổi ở ứng dụng gửi. Các bộ dịch tin nhắn giúp loại bỏ sự phụ thuộc này.
Việc chuyển đổi tin nhắn từ định dạng này sang định dạng khác yêu cầu chúng ta phải xử lý siêu dữ liệu mô tả định dạng của dữ liệu thực tế. Trong khi một tin nhắn từ một ứng dụng này sang ứng dụng khác có thể cho chúng ta biết rằng khách hàng với ID 123 đã chuyển từ San Francisco, California, đến Raleigh, North Carolina, siêu dữ liệu liên quan có thể cho chúng ta biết rằng tin nhắn Thay Đổi Địa Chỉ này sử dụng một trường ID khách hàng dạng số và lưu trữ tên và họ của khách hàng trong hai trường văn bản tối đa 40 ký tự mỗi trường.
Siêu dữ liệu đóng vai trò rất quan trọng trong việc tích hợp đến mức chúng ta có thể xem hầu hết các giải pháp tích hợp như sự tương tác giữa hai hệ thống song song. Một hệ thống xử lý dữ liệu tin nhắn thực tế, trong khi hệ thống còn lại xử lý siêu dữ liệu. Nhiều mẫu thiết kế được sử dụng để điều phối dòng dữ liệu tin nhắn cũng có thể được áp dụng để quản lý dòng siêu dữ liệu. Ví dụ, một Bộ chuyển đổi Kênh không chỉ có thể di chuyển tin nhắn vào và ra khỏi một hệ thống, mà còn có thể trích xuất siêu dữ liệu từ các ứng dụng bên ngoài và tải nó vào một kho lưu trữ siêu dữ liệu trung tâm. Bằng cách sử dụng kho lưu trữ này, các nhà phát triển tích hợp có thể định nghĩa các chuyển đổi giữa siêu dữ liệu ứng dụng và Mô hình Dữ liệu Canonical.
Tích hợp siêu dữ liệu

Ví dụ, hình ảnh trước mô tả sự tích hợp giữa hai ứng dụng cần trao đổi thông tin khách hàng. Mỗi hệ thống có định nghĩa hơi khác nhau về dữ liệu khách hàng. Ứng dụng A lưu trữ họ và tên trong hai trường riêng biệt, trong khi Ứng dụng B lưu trữ chúng trong một trường. Tương tự, Ứng dụng A lưu mã ZIP của khách hàng mà không lưu trạng thái, trong khi Ứng dụng B chỉ lưu viết tắt của trạng thái. Các tin nhắn từ Ứng dụng A đến Ứng dụng B phải trải qua một quá trình biến đổi để Ứng dụng B có thể nhận dữ liệu ở định dạng yêu cầu. Việc tạo ra quá trình biến đổi sẽ trở nên đơn giản hơn nhiều nếu các Bộ chuyển giao Kênh cũng có thể trích xuất siêu dữ liệu (ví dụ: dữ liệu mô tả định dạng tin nhắn). Siêu dữ liệu này sau đó có thể được nạp vào một kho lưu trữ, giúp đơn giản hóa rất nhiều việc cấu hình và xác thực của Bộ phiên dịch Tin nhắn. Siêu dữ liệu có thể được lưu trữ dưới nhiều định dạng khác nhau. Một định dạng phổ biến được sử dụng cho các tin nhắn XML là XSDeXtentible Schema Definition. Các công cụ EAI khác thực hiện các định dạng siêu dữ liệu độc quyền nhưng cho phép người quản trị nhập và xuất siêu dữ liệu sang các định dạng khác nhau.
Nhiều nguyên tắc được tích hợp trong các mẫu biến đổi này có thể áp dụng ngoài tích hợp dựa trên thông điệp. Ví dụ, Chuyển File phải thực hiện các chức năng biến đổi giữa các hệ thống. Tương tự, Gọi Thủ Tục Từ Xa phải thực hiện các yêu cầu theo định dạng dữ liệu được chỉ định bởi dịch vụ cần được gọi, ngay cả khi định dạng nội bộ của ứng dụng là khác. Điều này thường yêu cầu ứng dụng gọi phải thực hiện một biến đổi dữ liệu. Một số công cụ biến đổi tinh vi nhất được tích hợp vào các công cụ ETL (trích xuất, biến đổi, tải), chẳng hạn như Informatica hoặc DataMirror. Những công cụ này thường biến đổi một tập hợp lớn dữ liệu cùng một lúc thay vì biến đổi các thông điệp cá nhân.
Chương này tập trung vào các biến thể của mẫu Trình Dịch Tin Nhắn cơ bản. Nó không đi sâu vào chi tiết của các chuyển đổi cấu trúc giữa các thực thể (ví dụ: cách chuyển đổi giữa hai mẫu dữ liệu nếu một mẫu hỗ trợ các mối quan hệ nhiều-nhiều giữa khách hàng và địa chỉ nhưng mẫu kia lại bao gồm các trường địa chỉ trên bản ghi khách hàng). Một trong những cuốn sách lâu đời và vẫn còn rất liên quan về chủ đề trình bày dữ liệu và các mối quan hệ là [Kent].
Hầu hết các hệ thống nhắn tin chia dữ liệu tin nhắn thành phần tiêu đề và phần nội dung (xem Tin nhắn). Phần tiêu đề chứa các trường được hệ thống hạ tầng nhắn tin sử dụng để quản lý luồng tin nhắn. Tuy nhiên, hầu hết các hệ thống điểm cuối tham gia vào giải pháp tích hợp thường không nhận thức được các yếu tố dữ liệu bổ sung này. Trong một số trường hợp, các hệ thống có thể coi các trường này là sai do chúng không khớp với định dạng tin nhắn được sử dụng bởi ứng dụng. Mặt khác, các thành phần nhắn tin điều phối các tin nhắn giữa các ứng dụng có thể yêu cầu các trường tiêu đề và sẽ coi một tin nhắn là không hợp lệ nếu nó không chứa các trường tiêu đề thích hợp.
| Các hệ thống hiện tại có thể tham gia vào một cuộc trao đổi tin nhắn như thế nào khi có các yêu cầu cụ thể, chẳng hạn như các trường tiêu đề tin nhắn hoặc mã hóa, đối với định dạng tin nhắn? |
Ví dụ, giả sử hệ thống nhắn tin đang sử dụng một cơ chế bảo mật độc quyền. Một tin nhắn hợp lệ phải chứa thông tin xác thực để tin nhắn được chấp nhận để xử lý bởi các thành phần nhắn tin khác. Cơ chế này hữu ích để ngăn chặn người dùng trái phép gửi tin nhắn vào hệ thống. Thêm vào đó, nội dung tin nhắn có thể được mã hóa để ngăn chặn việc nghe lén bởi những người nghe không được phép, điều này đặc biệt quan trọng với các cơ chế xuất bản - đăng ký. Tuy nhiên, các ứng dụng hiện có đang được tích hợp thông qua các hệ thống nhắn tin có thể không nhận thức được các khái niệm về danh tính người dùng hoặc mã hóa tin nhắn. Do đó, các tin nhắn "thô" cần được chuyển đổi thành các tin nhắn tuân theo các quy tắc của hệ thống nhắn tin.
Một số doanh nghiệp lớn sử dụng nhiều hạ tầng nhắn tin khác nhau. Do đó, một tin nhắn có thể cần phải được định tuyến qua các hệ thống nhắn tin sử dụng Cầu nhắn tin. Mỗi hệ thống nhắn tin có thể có các yêu cầu khác nhau về định dạng của nội dung tin nhắn cũng như tiêu đề. Tình huống này là một trường hợp khác mà chúng ta có thể học hỏi bằng cách nhìn vào các giao thức mạng dựa trên TCP/IP hiện có. Trong nhiều trường hợp, kết nối với một hệ thống khác bị hạn chế chỉ cho một giao thức cụ thể, chẳng hạn như Telnet hoặc Secure Shell (ssh). Để cho phép giao tiếp sử dụng một giao thức khác (ví dụ, FTP), định dạng của giao thức đó phải được đóng gói vào các gói dữ liệu phù hợp với giao thức được hỗ trợ. Ở đầu kia, tải trọng gói có thể được trích xuất. Quá trình này được gọi là tunneling.
Khi một định dạng tin nhắn được bao bọc bên trong một định dạng khác, hệ thống có thể mất quyền truy cập vào thông tin bên trong tải dữ liệu. Hầu hết các hệ thống nhắn tin cho phép các thành phần (ví dụ: Bộ định tuyến tin nhắn) chỉ truy cập vào các trường dữ liệu là một phần của tiêu đề tin nhắn đã được định nghĩa. Nếu một tin nhắn được đóng gói vào một trường dữ liệu bên trong một tin nhắn khác, thành phần có thể không thể sử dụng các trường từ tin nhắn gốc để thực hiện các chức năng định tuyến hoặc biến đổi. Do đó, một số trường dữ liệu có thể cần phải được nâng lên từ tin nhắn gốc vào tiêu đề tin nhắn của định dạng tin nhắn mới.
| Sử dụng một bao bì phong bì để bọc dữ liệu ứng dụng bên trong một phong bì phù hợp với hạ tầng nhắn tin. Mở phong bì khi tin nhắn đến đích.
|
Quy trình bao bọc và mở bao một thông điệp bao gồm năm bước:
Nguồn tin nhắn phát hành một tin nhắn ở định dạng thô. Định dạng này thường được xác định bởi bản chất của ứng dụng và không tuân thủ các yêu cầu của hạ tầng nhắn tin.
Bộ bọc nhận thông điệp thô và chuyển đổi nó thành định dạng thông điệp phù hợp với hệ thống nhắn tin. Điều này có thể bao gồm việc thêm các trường tiêu đề thông điệp, mã hóa thông điệp, thêm thông tin xác thực bảo mật, và như vậy.
Hệ thống nhắn tin vận chuyển các tin nhắn tuân thủ.
Một thông điệp kết quả được gửi đến gói bỏ. Gói bỏ sẽ đảo ngược bất kỳ thay đổi nào mà gói đã thực hiện. Điều này có thể bao gồm việc loại bỏ các trường tiêu đề, giải mã thông điệp, hoặc xác minh các thông tin bảo mật.
Người nhận tin nhắn nhận được một tin nhắn "dạng văn bản rõ".
Một phong bì thường bao bọc cả tiêu đề thông điệp và nội dung thông điệp, hoặc tải trọng. Chúng ta có thể nghĩ về tiêu đề như là thông tin bên ngoài của một phong bì bưu chính: Nó được sử dụng bởi hệ thống nhắn tin để định tuyến và theo dõi thông điệp. Nội dung của phong bì là tải trọng hoặc thân của thông điệp mà hạ tầng nhắn tin không quan tâm nhiều đến nó (trong những giới hạn nhất định) cho đến khi nó đến đích.
Điều này là điển hình cho các lớp bọc khi thêm thông tin vào thông điệp thô. Ví dụ, trước khi một thông điệp nội bộ có thể được gửi qua hệ thống bưu chính, mã ZIP phải được tra cứu. Theo nghĩa đó, các lớp bọc kết hợp một số khía cạnh của một Người Tăng Cường Nội Dung. Tuy nhiên, các lớp bọc không làm phong phú thêm nội dung thông tin thực tế, mà chỉ thêm thông tin cần thiết cho việc định tuyến, theo dõi và xử lý các thông điệp. Thông tin này có thể được tạo ra ngay lập tức (ví dụ, tạo một ID thông điệp độc nhất hoặc thêm dấu thời gian), nó có thể được trích xuất từ cơ sở hạ tầng (ví dụ, truy xuất một ngữ cảnh bảo mật), hoặc dữ liệu có thể được chứa trong nội dung thông điệp gốc và sau đó được lớp bọc tách ra thành tiêu đề thông điệp (ví dụ, một trường khóa nằm trong thông điệp thô). Tùy chọn cuối cùng này đôi khi được gọi là thăng cấp vì một trường cụ thể được "thăng cấp" từ việc ẩn bên trong nội dung thành việc hiển thị rõ ràng trong tiêu đề.
Thường xuyên, nhiều lớp bao bọc và giải bọc được xâu chuỗi lại với nhau (xem ví dụ về hệ thống bưu chính dưới đây), tận dụng lợi thế của mô hình giao thức theo lớp. Điều này dẫn đến một tình huống mà payload của một thông điệp chứa một phong bì mới, cái mà lại bao bọc một tiêu đề và một phần payload (xem hình).
Một chuỗi các lớp bọc tạo ra cấu trúc bao bì phân cấp.

| Ví dụ: Định dạng thông điệp SOAP Định dạng tin nhắn SOAP cơ bản [SOAP 1.1] tương đối đơn giản. Nó chỉ định một phong bì chứa tiêu đề tin nhắn và nội dung tin nhắn. Ví dụ sau đây minh họa cách mà nội dung có thể chứa một phong bì khác, mà lại chứa một tiêu đề và nội dung khác. Tin nhắn kết hợp được gửi đến một trung gian, người sẽ mở phong bì bên ngoài và chuyển tiếp tin nhắn bên trong. Việc nối chuỗi các trung gian này rất phổ biến khi vượt qua các ranh giới tin cậy. Chúng tôi có thể mã hóa tất cả các tin nhắn của mình và bọc chúng bên trong một tin nhắn khác để không trung gian nào có thể thấy nội dung hoặc tiêu đề của tin nhắn (ví dụ, địa chỉ của một tin nhắn có thể là bí mật). Người nhận sau đó mở phong bì của tin nhắn, giải mã payload, và truyền tin nhắn chưa mã hóa qua môi trường tin cậy. [View full width] <env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope"> <env:Header env:actor="http://example.org/xmlsec/Bob"> <n:forward xmlns:n="http://example.org/xmlsec/forwarding"> <n:window>120</n:window> </n:forward> </env:Header> <env:Body> <env:Envelope xmlns:env="http://www.w3.org/2001/06 |
| Ví dụ: TCP/IP Trong khi chúng ta thường sử dụng TCP/IP như một thuật ngữ, nó thực sự bao gồm hai giao thức. Giao thức IP cung cấp dịch vụ định địa chỉ và định tuyến cơ bản, trong khi TCP cung cấp một giao thức đáng tin cậy, có hướng kết nối, được xây dựng trên IP. Theo mô hình lớp OSI, TCP là một giao thức vận chuyển, trong khi IP là một giao thức mạng. Thông thường, dữ liệu TCP/IP được vận chuyển qua một mạng Ethernet, mạng này thực hiện lớp liên kết. Kết quả là, dữ liệu ứng dụng được bọc trong một bưu kiện TCP trước, sau đó được bọc trong một bưu kiện IP, và sau đó được bọc trong một bưu kiện Ethernet. Vì các mạng có tính chất hướng luồng, một bưu kiện có thể bao gồm cả phần đầu và phần đuôi, đánh dấu sự bắt đầu và kết thúc của luồng dữ liệu. Hình ảnh ở trang tiếp theo minh họa cấu trúc của dữ liệu ứng dụng di chuyển qua Ethernet. Dữ liệu ứng dụng được bọc bên trong nhiều lớp bao để được truyền qua mạng.
Bạn có thể thấy sự đóng gói liên tiếp của dữ liệu ứng dụng vào nhiều lớp bọc: TCP (lớp bọc truyền tải), IP (lớp bọc mạng), và Ethernet (lớp bọc liên kết). Lớp bọc TCP và IP chỉ bao gồm một tiêu đề, trong khi lớp bọc Ethernet thêm cả tiêu đề và đoạn cuối. Nếu bạn quan tâm đến chi tiết hơn về TCP/IP, [Stevens] chắc chắn sẽ làm thoả mãn cơn khát tri thức của bạn. |
| Ví dụ: Hệ thống bưu chính Mẫu bọc phong bì có thể được so sánh với hệ thống bưu chính (xem hình trên trang tiếp theo). Giả sử một nhân viên tạo một bản ghi nhớ nội bộ gửi tới một đồng nghiệp. Bất kỳ tờ giấy nào cũng sẽ là định dạng chấp nhận được cho nội dung tin nhắn này. Để bản ghi nhớ được giao, nó phải được "bọc" vào một phong bì nội bộ của công ty có tên và mã phòng ban của người nhận. Nếu người nhận làm việc tại một cơ sở riêng, tin nhắn nội bộ này sẽ được nhét vào một phong bì lớn và gửi qua Dịch vụ Bưu điện Hoa Kỳ. Để làm cho tin nhắn mới tuân thủ yêu cầu của USPS, nó cần phải có một phong bì mới với mã ZIP và bưu chính. USPS có thể quyết định vận chuyển phong bì này qua đường hàng không. Để làm như vậy, họ cho tất cả các phong bì cho một khu vực cụ thể vào một túi thư, được dán nhãn bằng một mã vạch có mã sân bay ba chữ cái cho sân bay đích. Khi túi thư đến sân bay đích, quy trình bọc sẽ được đảo ngược cho đến khi bản ghi nhớ gốc được nhận bởi đồng nghiệp. Ví dụ này minh họa thuật ngữ "tunneling": Thư bưu chính có thể được "tunnel" qua đường hàng không giống như các gói UDP multicast có thể được tunnel qua một kết nối TCP/IP để đến một phân đoạn WAN khác.
Hệ thống bưu chính là ví dụ minh họa cho thực hành phổ biến trong việc kết hợp các bước bao bọc và mở bọc sử dụng kiến trúc Ống và Bộ lọc. Các tin nhắn có thể được bao bọc bởi nhiều bước khác nhau và cần được mở bọc theo một chuỗi các bước mở bọc đối xứng. Như đã nêu trong Ống và Bộ lọc, việc giữ cho các bước riêng lẻ độc lập với nhau mang đến cho hạ tầng thông điệp tính linh hoạt để thêm hoặc loại bỏ các bước bao bọc và mở bọc. Ví dụ, việc mã hóa có thể không còn cần thiết vì tất cả lưu lượng truy cập được định tuyến qua VPN thay vì Internet công cộng. |
Khi gửi tin nhắn từ hệ thống này sang hệ thống khác, thường thì hệ thống nhận sẽ yêu cầu nhiều thông tin hơn những gì hệ thống gửi có thể cung cấp. Ví dụ, các tin nhắn địa chỉ đến có thể chỉ chứa mã ZIP vì các nhà thiết kế cho rằng việc lưu trữ thông tin thành phố và tiểu bang trùng lặp là không cần thiết. Có khả năng, một hệ thống khác sẽ muốn chỉ định thành phố và tiểu bang cũng như một trường mã ZIP. Hệ thống khác nữa có thể không sử dụng viết tắt tiểu bang, mà sẽ viết đầy đủ tên tiểu bang vì nó sử dụng địa chỉ tự do để hỗ trợ địa chỉ quốc tế. Tương tự, một hệ thống có thể cung cấp cho chúng ta một ID khách hàng, nhưng hệ thống nhận thực sự yêu cầu tên và địa chỉ khách hàng. Trong một tình huống khác, một tin nhắn Đơn hàng gửi bởi hệ thống quản lý đơn hàng có thể chỉ chứa một số đơn hàng, nhưng chúng ta cần tìm ID khách hàng liên quan đến đơn hàng đó để có thể truyền nó cho hệ thống quản lý khách hàng. Các kịch bản thì rất phong phú.
| Làm thế nào chúng ta có thể giao tiếp với một hệ thống khác nếu người gửi tin nhắn không có tất cả các mục dữ liệu cần thiết? |
Vấn đề này là một trường hợp đặc biệt của Trình dịch Thông điệp, vì vậy một số cân nhắc tương tự áp dụng. Tuy nhiên, vấn đề này hơi khác so với các ví dụ cơ bản được mô tả trong Trình dịch Thông điệp. Mô tả của Trình dịch Thông điệp giả định rằng dữ liệu cần thiết cho ứng dụng nhận đã tồn tại trong thông điệp đến, mặc dù ở định dạng sai. Trong trường hợp mới này, không chỉ đơn giản là sắp xếp lại các trường; chúng ta thực sự cần phải tiêm thông tin bổ sung vào thông điệp.
Hệ thống Kế toán yêu cầu nhiều thông tin hơn hệ thống Lịch trình có thể cung cấp.

Hãy xem xét ví dụ sau (xem hình). Hệ thống lập lịch bệnh viện công bố một thông điệp thông báo rằng bệnh nhân đã hoàn thành cuộc hẹn với bác sĩ. Thông điệp chứa tên bệnh nhân, mã số bệnh nhân của họ và ngày hẹn. Để cho hệ thống kế toán ghi lại cuộc hẹn này và thông báo cho công ty bảo hiểm, nó yêu cầu tên đầy đủ của bệnh nhân, công ty bảo hiểm và số an sinh xã hội của bệnh nhân. Tuy nhiên, hệ thống lập lịch không lưu trữ thông tin này; nó nằm trong hệ thống chăm sóc khách hàng. Những lựa chọn của chúng ta là gì?
Các Giải Pháp Có Thể Cho Vấn Đề Tăng Cường

Lựa chọn A: Chúng ta có thể sửa đổi hệ thống lập lịch để nó có thể lưu trữ thông tin bổ sung. Khi thông tin của khách hàng thay đổi trong hệ thống chăm sóc khách hàng (ví dụ: vì bệnh nhân chuyển đổi nhà cung cấp bảo hiểm), các thay đổi cần được sao chép vào hệ thống lập lịch. Hệ thống lập lịch bây giờ có thể gửi một tin nhắn bao gồm tất cả thông tin cần thiết. Không may, cách tiếp cận này có hai nhược điểm đáng kể. Thứ nhất, nó yêu cầu một sửa đổi đối với cấu trúc nội bộ của hệ thống lập lịch. Trong hầu hết các trường hợp, hệ thống lập lịch là một ứng dụng đóng gói và có thể không cho phép loại sửa đổi này. Thứ hai, ngay cả khi hệ thống lập lịch có thể tùy chỉnh, chúng ta cần xem xét rằng chúng ta đang thực hiện một thay đổi cho hệ thống dựa trên nhu cầu cụ thể của một hệ thống khác. Ví dụ, nếu chúng ta cũng muốn gửi một bức thư cho bệnh nhân xác nhận cuộc hẹn, chúng ta sẽ phải thay đổi hệ thống lập lịch một lần nữa để phù hợp với địa chỉ gửi thư của khách hàng. Giải pháp tích hợp sẽ dễ bảo trì hơn nhiều nếu chúng ta tách rời hệ thống lập lịch khỏi các chi tiết của các ứng dụng tiêu thụ thông điệp Cuộc hẹn Bác sĩ.
Tùy chọn B: Thay vì lưu trữ thông tin của khách hàng trong hệ thống lập lịch, hệ thống lập lịch có thể yêu cầu SSN và dữ liệu của nhà cung cấp từ hệ thống chăm sóc khách hàng ngay trước khi gửi tin nhắn Thăm Bác Sĩ. Điều này giải quyết vấn đề đầu tiên - chúng ta không cần phải sửa đổi việc lưu trữ của hệ thống lập lịch. Tuy nhiên, vấn đề thứ hai vẫn còn: Hệ thống lập lịch cần biết rằng thông tin SSN và nhà cung cấp là cần thiết để thông báo cho hệ thống kế toán. Do đó, ngữ nghĩa của tin nhắn có phần tương tự như Thông Báo Bảo Hiểm hơn là Thăm Bác Sĩ. Trong một hệ thống liên kết lỏng lẻo, chúng ta không muốn một hệ thống chỉ đạo hệ thống tiếp theo phải làm gì. Thay vào đó, chúng ta gửi một Tin Nhắn Sự Kiện và để các hệ thống khác tự quyết định hành động. Ngoài ra, giải pháp này khiến hệ thống lập lịch được liên kết chặt chẽ hơn với hệ thống chăm sóc khách hàng vì giờ đây hệ thống lập lịch cần biết nơi lấy dữ liệu thiếu. Điều này liên kết hệ thống lập lịch với cả hệ thống kế toán và hệ thống chăm sóc khách hàng. Loại liên kết này là không mong muốn vì nó dẫn đến các giải pháp tích hợp dễ gãy.
Tùy chọn C: Chúng ta có thể tránh một số phụ thuộc này nếu gửi tin nhắn đến hệ thống chăm sóc khách hàng trước, thay vì gửi đến hệ thống kế toán. Hệ thống chăm sóc khách hàng sau đó có thể lấy tất cả thông tin cần thiết và gửi một tin nhắn với tất cả dữ liệu cần thiết đến hệ thống kế toán. Điều này tách biệt hệ thống lập lịch một cách hiệu quả khỏi luồng tin nhắn tiếp theo. Tuy nhiên, bây giờ chúng ta thực hiện quy tắc kinh doanh rằng công ty bảo hiểm sẽ nhận được hóa đơn sau khi bệnh nhân thăm bác sĩ trong hệ thống chăm sóc khách hàng. Điều này yêu cầu chúng ta phải điều chỉnh logic bên trong hệ thống chăm sóc khách hàng. Nếu hệ thống chăm sóc khách hàng là một ứng dụng đã được đóng gói, việc điều chỉnh này có thể khó khăn hoặc không thể thực hiện. Ngay cả khi chúng ta có thể thực hiện điều chỉnh này, chúng ta hiện đang làm cho hệ thống chăm sóc khách hàng trở nên có trách nhiệm gián tiếp trong việc gửi tin nhắn hóa đơn. Điều này có thể không phải là vấn đề nếu tất cả các mục dữ liệu cần thiết bởi hệ thống kế toán đều có sẵn trong hệ thống chăm sóc khách hàng. Tuy nhiên, nếu một số trường phải được lấy từ các hệ thống khác, chúng ta sẽ rơi vào tình huống tương tự như khi chúng ta bắt đầu.
Tùy chọn D (không hiển thị): Chúng tôi cũng có thể điều chỉnh hệ thống kế toán để chỉ yêu cầu ID khách hàng và lấy thông tin SSN cùng nhà cung cấp từ hệ thống chăm sóc khách hàng. Cách tiếp cận này có hai nhược điểm. Thứ nhất, chúng tôi đã gắn hệ thống kế toán với hệ thống chăm sóc khách hàng. Thứ hai, tùy chọn này lại giả định rằng chúng tôi có quyền kiểm soát hệ thống kế toán. Trong hầu hết các trường hợp, hệ thống kế toán là một ứng dụng đóng gói với các tùy chọn tùy chỉnh hạn chế.
| Sử dụng một bộ chuyển đổi chuyên biệt, một Bộ làm giàu nội dung, để truy cập vào một nguồn dữ liệu bên ngoài nhằm bổ sung thông tin thiếu cho một thông điệp.
|
Bộ làm phong phú nội dung sử dụng thông tin bên trong tin nhắn đến (ví dụ: các trường khóa) để lấy dữ liệu từ nguồn bên ngoài. Sau khi Bộ làm phong phú nội dung lấy được dữ liệu cần thiết từ nguồn cung cấp, nó sẽ thêm dữ liệu vào tin nhắn. Thông tin gốc từ tin nhắn đến có thể được giữ lại trong tin nhắn kết quả hoặc có thể không còn cần thiết, tùy thuộc vào nhu cầu cụ thể của ứng dụng nhận.
Thông tin bổ sung được thêm vào bởi Bộ làm giàu nội dung phải có sẵn ở đâu đó trong hệ thống. Dưới đây là những nguồn phổ biến nhất cho dữ liệu mới:
Tính toán: Người làm phong phú nội dung có thể tính toán thông tin bị thiếu. Trong trường hợp này, thuật toán sẽ kết hợp thông tin bổ sung. Ví dụ, nếu hệ thống nhận yêu cầu một thành phố và viết tắt tiểu bang, nhưng tin nhắn đến chỉ chứa mã ZIP, thuật toán có thể cung cấp thông tin về thành phố và tiểu bang. Hoặc, một hệ thống nhận có thể yêu cầu một định dạng dữ liệu xác định kích thước tổng thể của tin nhắn. Người làm phong phú nội dung có thể cộng tổng độ dài của tất cả các trường trong tin nhắn và do đó tính toán kích thước của tin nhắn. Hình thức Người làm phong phú nội dung này rất giống với Người dịch tin nhắn cơ bản vì nó không cần nguồn dữ liệu bên ngoài.
Môi trường: Người làm phong phú nội dung có thể lấy dữ liệu bổ sung từ môi trường vận hành. Ví dụ phổ biến nhất là một dấu thời gian. Ví dụ, hệ thống nhận có thể yêu cầu mỗi tin nhắn mang theo một dấu thời gian. Nếu hệ thống gửi không bao gồm trường này, người làm phong phú nội dung có thể lấy thời gian hiện tại từ hệ điều hành và thêm vào tin nhắn.
Một Hệ Thống Khác: Tùy chọn này là tùy chọn phổ biến nhất. Người Làm Giàu Nội Dung phải lấy dữ liệu thiếu từ một hệ thống khác. Tài nguyên dữ liệu này có thể dưới nhiều hình thức khác nhau, bao gồm cơ sở dữ liệu, tệp tin, thư mục LDAP, ứng dụng hoặc người dùng nhập dữ liệu thiếu một cách thủ công.
Trong nhiều trường hợp, tài nguyên bên ngoài mà Bộ làm giàu Nội dung cần có thể nằm trên một hệ thống khác hoặc thậm chí bên ngoài doanh nghiệp. Do đó, sự giao tiếp giữa Bộ làm giàu Nội dung và tài nguyên có thể diễn ra qua Gửi tin nhắn hoặc qua bất kỳ cơ chế giao tiếp nào khác (xem Chương 2, "Các phong cách tích hợp"). Vì sự tương tác giữa Bộ làm giàu Nội dung và nguồn dữ liệu theo định nghĩa là đồng bộ (Bộ làm giàu Nội dung không thể gửi thông điệp đã được làm giàu cho đến khi nguồn dữ liệu trả lại dữ liệu được yêu cầu), một giao thức đồng bộ (ví dụ: HTTP hoặc kết nối ODBC tới cơ sở dữ liệu) có thể mang lại hiệu suất tốt hơn so với việc sử dụng gửi tin nhắn không đồng bộ. Bộ làm giàu Nội dung và nguồn dữ liệu về cơ bản là được liên kết chặt chẽ với nhau, vì vậy việc đạt được sự liên kết lỏng qua Kênh Tin nhắn không quan trọng bằng.
Quay trở lại với ví dụ của chúng ta, chúng ta có thể chèn một Bộ làm phong phú nội dung để lấy dữ liệu bổ sung từ hệ thống chăm sóc khách hàng (xem hình). Bằng cách này, hệ thống lập lịch được tách rời một cách hợp lý khỏi việc phải xử lý thông tin bảo hiểm hoặc hệ thống chăm sóc khách hàng. Tất cả những gì nó cần làm là công bố tin nhắn Đến thăm Bác sĩ. Thành phần Bộ làm phong phú nội dung sẽ chịu trách nhiệm lấy dữ liệu cần thiết. Hệ thống kế toán cũng sẽ độc lập với hệ thống chăm sóc khách hàng.
Áp dụng Bộ làm phong phú cho Ví dụ Bệnh nhân

Bộ làm giàu nội dung được sử dụng trong nhiều trường hợp để giải quyết các tham chiếu có trong một thông điệp. Để giữ cho các thông điệp nhỏ và dễ quản lý, chúng tôi thường chọn cách truyền các tham chiếu đơn giản đến các đối tượng thay vì truyền một đối tượng hoàn chỉnh với tất cả các yếu tố dữ liệu. Những tham chiếu này thường có dạng khóa hoặc ID duy nhất. Khi thông điệp cần được xử lý bởi một hệ thống, chúng tôi cần truy xuất các mục dữ liệu cần thiết dựa trên các tham chiếu đối tượng có trong thông điệp gốc. Chúng tôi sử dụng một Bộ làm giàu nội dung để thực hiện nhiệm vụ này. Có một số đánh đổi rõ ràng liên quan. Việc sử dụng các tham chiếu làm giảm khối lượng dữ liệu trong các thông điệp gốc, nhưng yêu cầu tra cứu bổ sung trong tài nguyên. Việc sử dụng các tham chiếu có cải thiện hiệu suất hay không phụ thuộc vào số lượng thành phần có thể hoạt động đơn giản dựa trên các tham chiếu so với số lượng thành phần cần phải sử dụng một Bộ làm giàu nội dung để phục hồi một số nội dung của thông điệp gốc. Ví dụ, nếu một thông điệp đi qua một danh sách dài các trung gian trước khi đến tay người nhận cuối cùng, việc sử dụng một tham chiếu đối tượng có thể giảm đáng kể lưu lượng thông điệp. Chúng tôi có thể chèn một Bộ làm giàu nội dung như là bước cuối cùng trước người nhận cuối cùng để tải thông tin còn thiếu vào thông điệp. Nếu thông điệp đã chứa dữ liệu mà chúng tôi có thể không muốn mang theo, chúng tôi có thể sử dụng Kiểm tra yêu cầu để lưu trữ dữ liệu và nhận một tham chiếu đến nó.
| Ví dụ: Giao tiếp với các bên bên ngoài Một Bộ làm giàu nội dung thường được sử dụng khi giao tiếp với các bên bên ngoài yêu cầu các thông điệp tuân thủ một tiêu chuẩn thông điệp cụ thể (ví dụ: ebXML). Hầu hết các tiêu chuẩn này yêu cầu các thông điệp lớn với một danh sách dữ liệu dài. Chúng ta thường có thể đơn giản hóa đáng kể các hoạt động nội bộ nếu giữ cho các thông điệp nội bộ càng đơn giản càng tốt và sau đó sử dụng một Bộ làm giàu nội dung để thêm các trường còn thiếu mỗi khi chúng ta gửi một thông điệp ra ngoài tổ chức. Tương tự, chúng ta có thể sử dụng một Bộ lọc nội dung để loại bỏ thông tin không cần thiết từ các thông điệp đến. Sử dụng Cặp Tăng Cường Nội Dung/Lọc Nội Dung Khi Giao Tiếp với Các Bên Ngoài
|
Bộ làm giàu nội dung giúp chúng tôi trong những tình huống mà người nhận thông điệp cần nhiều hoặc các yếu tố dữ liệu khác so với những gì người tạo thông điệp cung cấp. Có khá nhiều tình huống ngược lại là điều mong muốn: loại bỏ các yếu tố dữ liệu khỏi một thông điệp.
| Làm thế nào để bạn đơn giản hóa việc xử lý một thông điệp lớn khi bạn chỉ quan tâm đến một vài mục dữ liệu? |
Tại sao chúng ta lại muốn loại bỏ các yếu tố dữ liệu quý giá khỏi một thông điệp? Một lý do phổ biến là bảo mật. Một ứng dụng yêu cầu dữ liệu từ một dịch vụ có thể không được phép xem tất cả các yếu tố dữ liệu mà thông điệp phản hồi chứa. Nhà cung cấp dịch vụ có thể không có kiến thức về một sơ đồ bảo mật và có thể luôn trả về tất cả các yếu tố dữ liệu mà không quan tâm đến danh tính người dùng. Chúng ta cần thêm một bước để loại bỏ dữ liệu nhạy cảm dựa trên danh tính đã được xác minh của người yêu cầu. Ví dụ, hệ thống quản lý lương có thể chỉ cung cấp một giao diện đơn giản trả về tất cả dữ liệu về một nhân viên. Dữ liệu này có thể bao gồm thông tin lương, số an sinh xã hội và các thông tin nhạy cảm khác. Nếu bạn đang cố gắng xây dựng một dịch vụ trả về ngày bắt đầu làm việc của một nhân viên trong công ty, bạn có thể muốn loại bỏ tất cả thông tin nhạy cảm khỏi thông điệp kết quả trước khi chuyển lại cho người yêu cầu.
Một lý do khác để loại bỏ các yếu tố dữ liệu là để đơn giản hóa việc xử lý thông điệp và giảm lưu lượng mạng. Trong nhiều trường hợp, các quy trình được khởi xướng bởi các thông điệp nhận được từ các đối tác kinh doanh. Với những lý do rõ ràng, việc dựa vào định dạng thông điệp tiêu chuẩn để giao tiếp với các bên thứ ba là điều mong muốn. Nhiều tổ chức tiêu chuẩn và ủy ban định nghĩa các định dạng dữ liệu XML tiêu chuẩn cho một số ngành công nghiệp và ứng dụng nhất định. Những ví dụ nổi tiếng là RosettaNet, ebXML, ACORD và nhiều hơn nữa. Trong khi các định dạng XML này hữu ích để thực hiện tương tác với các bên bên ngoài dựa trên tiêu chuẩn đã thỏa thuận, cách tiếp cận "thiết kế bởi ủy ban" thường dẫn đến việc tạo ra các tài liệu rất lớn. Nhiều tài liệu có hàng trăm trường, với nhiều cấp độ lồng nhau. Những tài liệu lớn như vậy rất khó làm việc cho việc trao đổi thông điệp nội bộ. Ví dụ, hầu hết các công cụ chuyển đổi hình ảnh (kiểu kéo-thả) trở nên không sử dụng được nếu các tài liệu cần ánh xạ có hàng trăm yếu tố. Ngoài ra, việc gỡ lỗi trở thành một cơn ác mộng lớn. Do đó, chúng tôi muốn đơn giản hóa các tài liệu đến chỉ bao gồm các yếu tố mà chúng tôi thực sự cần cho các bước xử lý nội bộ. Theo một cách nào đó, việc loại bỏ các yếu tố làm tăng tính hữu ích của một thông điệp như vậy, vì các trường dư thừa và không liên quan được loại bỏ, để lại một thông điệp có ý nghĩa hơn và ít khả năng xảy ra lỗi của nhà phát triển hơn.
| Sử dụng bộ lọc nội dung để loại bỏ các mục dữ liệu không quan trọng khỏi một tin nhắn, chỉ giữ lại những mục quan trọng.
|
Bộ lọc nội dung không chỉ đơn giản là loại bỏ các phần tử dữ liệu. Bộ lọc nội dung cũng hữu ích để đơn giản hóa cấu trúc của thông điệp. Thường thì, các thông điệp được biểu diễn dưới dạng cấu trúc cây. Nhiều thông điệp xuất phát từ các hệ thống bên ngoài hoặc ứng dụng đóng gói chứa nhiều cấp độ nhóm lặp lại lồng ghép vì chúng được mô hình hóa theo các cấu trúc cơ sở dữ liệu chuẩn hóa, tổng quát. Thường xuyên, những ràng buộc và giả định đã biết khiến mức độ lồng ghép này trở nên không cần thiết, và một Bộ lọc nội dung có thể được sử dụng để "làm phẳng" cấu trúc phân cấp thành một danh sách đơn giản các phần tử mà các hệ thống khác có thể dễ dàng hiểu và xử lý.
Làm phẳng một phân cấp thông điệp với bộ lọc nội dung

Nhiều bộ lọc nội dung có thể được sử dụng như một bộ chia tĩnh (xem Bộ chia) để chia một thông điệp phức tạp thành các thông điệp riêng lẻ, mỗi thông điệp xử lý một khía cạnh nhất định của thông điệp lớn (xem hình ở đầu trang tiếp theo).
Sử dụng nhiều bộ lọc nội dung như một bộ chia tĩnh

| Ví dụ: Bộ điều hợp cơ sở dữ liệu Nhiều bộ tích hợp cung cấp các Bộ điều hợp Kênh để kết nối với các hệ thống hiện có. Trong nhiều trường hợp, các bộ điều hợp này công bố các thông điệp có định dạng tương tự như cấu trúc nội bộ của ứng dụng. Ví dụ, giả sử chúng ta kết nối một bộ điều hợp cơ sở dữ liệu với một cơ sở dữ liệu có sơ đồ sau: "Một Ví Dụ Về Sơ Đồ Cơ Sở Dữ Liệu"
Việc có một lược đồ cơ sở dữ liệu vật lý lưu trữ các thực thể liên quan trong các bảng riêng biệt được liên kết bởi các khóa ngoại và bảng quan hệ (ví dụ, ACCOUNT_CONTACT liên kết các bảng ACCOUNT và CONTACT) là điều mong muốn. Nhiều bộ chuyển đổi cơ sở dữ liệu thương mại dịch các bảng liên quan này thành một cấu trúc thông điệp theo dạng phân cấp có thể chứa các trường bổ sung như khóa chính và khóa ngoại không liên quan đến người nhận thông điệp. Để làm cho việc xử lý một thông điệp trở nên dễ dàng hơn, chúng ta có thể sử dụng Bộ lọc Nội dung để làm phẳng cấu trúc thông điệp và trích xuất chỉ các trường liên quan. Ví dụ cho thấy việc triển khai Bộ lọc Nội dung bằng cách sử dụng công cụ chuyển đổi trực quan. Chúng ta có thể thấy cách giảm thông điệp từ hơn một tá trường trải rộng khắp nhiều cấp độ xuống còn một thông điệp đơn giản với năm trường. Việc làm việc với thông điệp đơn giản hóa sẽ dễ dàng hơn rất nhiều (và hiệu quả hơn) cho các thành phần khác. Đơn giản hóa một thông điệp được xuất bản bởi một bộ điều hợp cơ sở dữ liệu
Bộ lọc nội dung không phải là giải pháp duy nhất cho vấn đề cụ thể này. Ví dụ, chúng ta có thể cấu hình một chế độ xem trong cơ sở dữ liệu để giải quyết các mối quan hệ bảng và trả về một tập hợp kết quả đơn giản. Điều này có thể là một lựa chọn đơn giản nếu chúng ta có khả năng thêm các chế độ xem vào cơ sở dữ liệu. Trong nhiều tình huống, tích hợp doanh nghiệp có mục tiêu là ít gây ảnh hưởng nhất có thể và nguyên tắc này có thể bao gồm việc không thêm các chế độ xem vào cơ sở dữ liệu. |
Trình làm phong phú nội dung cho chúng ta biết cách xử lý các tình huống mà thông điệp của chúng ta thiếu các mục dữ liệu cần thiết. Để đạt được hiệu ứng ngược lại, bộ lọc nội dung cho phép chúng ta loại bỏ các mục dữ liệu không thú vị khỏi một thông điệp. Tuy nhiên, chúng ta có thể chỉ muốn loại bỏ các trường tạm thời. Ví dụ, một thông điệp có thể chứa một tập hợp các mục dữ liệu cần thiết sau này trong quy trình xử lý thông điệp nhưng không cần thiết cho tất cả các bước xử lý trung gian. Chúng ta có thể không muốn mang tất cả thông tin này qua từng bước xử lý, vì điều đó có thể gây giảm hiệu suất, và làm cho việc gỡ lỗi trở nên khó khăn hơn do chúng ta mang theo quá nhiều dữ liệu dư thừa.
| Làm thế nào chúng ta có thể giảm khối lượng dữ liệu của một thông điệp được gửi qua hệ thống mà không hy sinh nội dung thông tin? |
Việc chuyển dữ liệu lớn qua các tin nhắn có thể không hiệu quả. Một số hệ thống nhắn tin thậm chí có giới hạn nghiêm ngặt về kích thước của tin nhắn. Các hệ thống nhắn tin khác sử dụng biểu diễn XML của dữ liệu, điều này có thể làm tăng kích thước của một tin nhắn gấp bậc hoặc nhiều hơn. Vì vậy, mặc dù nhắn tin cung cấp cách truyền tải thông tin đáng tin cậy và nhanh nhạy nhất, nhưng nó có thể không phải là phương pháp hiệu quả nhất.
Ngoài ra, việc mang theo ít dữ liệu trong một thông điệp giúp các hệ thống trung gian không phụ thuộc vào thông tin không được dành cho chúng. Ví dụ, nếu chúng ta gửi thông tin địa chỉ từ hệ thống này sang hệ thống khác qua một loạt các trung gian, các trung gian có thể bắt đầu đưa ra những giả định về dữ liệu địa chỉ và do đó trở nên phụ thuộc vào định dạng dữ liệu của thông điệp. Việc làm cho các thông điệp nhỏ nhất có thể giúp giảm khả năng tạo ra những giả định ẩn giấu như vậy.
Một bộ lọc nội dung đơn giản giúp chúng ta giảm khối lượng dữ liệu nhưng không đảm bảo rằng chúng ta có thể khôi phục nội dung tin nhắn sau này. Do đó, chúng ta cần lưu trữ toàn bộ thông tin tin nhắn theo cách mà chúng ta có thể truy xuất lại sau.
Bởi vì chúng ta cần lưu trữ dữ liệu cho mỗi tin nhắn, chúng ta cần một khóa để truy xuất các mục dữ liệu đúng liên quan đến một tin nhắn. Chúng ta có thể sử dụng ID tin nhắn làm khóa, nhưng điều đó sẽ không cho phép các thành phần tiếp theo chuyển tiếp khóa, vì ID tin nhắn thay đổi với mỗi tin nhắn.
| Lưu trữ dữ liệu tin nhắn trong một kho lưu trữ bền vững và chuyển một Giấy chứng nhận (Claim Check) cho các thành phần tiếp theo. Các thành phần này có thể sử dụng Giấy chứng nhận để truy xuất thông tin đã được lưu trữ.
|
Mẫu biên nhận bao gồm các bước sau:
Một thông điệp chứa dữ liệu đến.
Thành phần Kiểm tra Hành lý tạo ra một khóa duy nhất cho thông tin. Khóa này sẽ được sử dụng sau đó như biên nhận yêu cầu.
Thành phần Kiểm tra Hành lý trích xuất dữ liệu từ thông điệp và lưu trữ nó trong một kho lưu trữ bền vững, chẳng hạn như tệp hoặc cơ sở dữ liệu. Nó liên kết dữ liệu đã lưu với khóa.
Nó loại bỏ dữ liệu đã được lưu trữ từ thông điệp và thêm Kiểm tra Đòi Hỏi.
Một thành phần khác có thể sử dụng một Bộ làm giàu nội dung để lấy dữ liệu dựa trên Kiểm tra Khiếu nại.
Quá trình này tương tự như việc kiểm tra hành lý tại sân bay. Nếu bạn không muốn mang tất cả hành lý của mình, bạn chỉ cần gửi nó tại quầy hàng không. Đổi lại, bạn sẽ nhận được một nhãn dán trên vé của mình có số tham chiếu duy nhất xác định mỗi món hành lý bạn đã gửi. Khi bạn đến điểm đến cuối cùng, bạn có thể nhận lại hành lý của mình.
Như hình minh họa, dữ liệu chứa trong thông điệp gốc vẫn cần được "di chuyển" đến đích cuối cùng. Vậy chúng ta có thu được gì không? Có, vì việc vận chuyển dữ liệu qua hệ thống nhắn tin có thể kém hiệu quả hơn so với việc lưu trữ trong một kho dữ liệu trung tâm. Ví dụ, thông điệp có thể trải qua nhiều bước định tuyến mà không cần lượng dữ liệu lớn. Sử dụng hệ thống nhắn tin, dữ liệu thông điệp sẽ được tập hợp và giải tập hợp, có thể được mã hóa và giải mã, ở mỗi bước. Loại hoạt động này có thể tốn rất nhiều tài nguyên CPU và sẽ hoàn toàn không cần thiết cho dữ liệu mà không cần cho bất kỳ bước trung gian nào mà chỉ cần cho đích cuối cùng. Kiểm tra Yêu cầu cũng hoạt động tốt trong một kịch bản mà thông điệp di chuyển qua một số thành phần và trở về với người gửi. Trong trường hợp này, thành phần Kiểm tra Hành lý và Bộ làm phong phú Nội dung là cục bộ trong cùng một thành phần, và dữ liệu không bao giờ phải di chuyển qua mạng.
Dữ liệu có thể được lưu trữ và truy xuất cục bộ.

Chúng ta nên chọn một khóa cho dữ liệu như thế nào? Một số lựa chọn hiện ra trong đầu:
Một khóa kinh doanh, chẳng hạn như ID khách hàng, có thể đã được chứa trong thân tin nhắn.
Thông điệp có thể chứa một ID thông điệp có thể được sử dụng để liên kết dữ liệu trong kho dữ liệu với thông điệp.
Chúng tôi có thể tạo ra một ID duy nhất.
Việc sử dụng một khóa kinh doanh hiện có dường như là sự lựa chọn dễ nhất. Nếu chúng ta cần lưu trữ một số thông tin khách hàng, chúng ta có thể tham khảo sau đó bằng cách sử dụng ID khách hàng. Khi chúng ta chuyển khóa này đến các thành phần khác, chúng ta cần quyết định xem chúng ta có muốn các thành phần này biết rằng khóa này là ID khách hàng hay chỉ là một khóa trừu tượng. Việc đại diện cho khóa dưới dạng khóa trừu tượng có lợi thế là chúng ta có thể xử lý tất cả các khóa theo cùng một cách và có thể tạo ra một cơ chế chung để truy xuất dữ liệu từ kho dữ liệu dựa trên một khóa trừu tượng.
Sử dụng ID tin nhắn làm khóa có vẻ thuận tiện nhưng thường không phải là ý tưởng tốt. Sử dụng ID tin nhắn làm khóa để truy xuất dữ liệu dẫn đến việc gán hai nghĩa vào một phần dữ liệu duy nhất và có thể gây ra xung đột. Ví dụ, giả sử chúng ta cần chuyển tham chiếu Check Khiếu nại sang một tin nhắn khác. Tin nhắn mới được dự kiến sẽ được gán một ID mới, duy nhất, nhưng sau đó chúng ta không thể sử dụng ID mới đó để truy xuất dữ liệu từ kho dữ liệu. Việc sử dụng ID tin nhắn chỉ có thể có ý nghĩa trong trường hợp chúng ta muốn dữ liệu chỉ có thể truy cập trong phạm vi của một tin nhắn duy nhất. Do đó, nhìn chung, tốt hơn là gán một phần tử mới để giữ khóa và tránh hình thức "sử dụng lại phần tử" không tốt này.
Dữ liệu chỉ có thể được lưu trữ tạm thời trong kho dữ liệu. Làm thế nào chúng ta có thể xóa dữ liệu không sử dụng? Chúng ta có thể điều chỉnh ngữ nghĩa của việc truy xuất dữ liệu từ kho dữ liệu để xóa dữ liệu khi nó được đọc. Trong trường hợp này, chúng ta chỉ có thể truy xuất dữ liệu một lần, điều này có thể thực sự là điều mong muốn trong một số trường hợp vì lý do bảo mật. Tuy nhiên, điều này không cho phép nhiều thành phần truy cập cùng một dữ liệu. Một cách thay thế, chúng ta có thể gán một ngày hết hạn cho dữ liệu và định nghĩa một quy trình thu gom rác mà định kỳ xóa tất cả dữ liệu qua một độ tuổi nhất định. Là một sự lựa chọn thứ ba, có thể chúng ta không muốn xóa bất kỳ dữ liệu nào. Điều này có thể xảy ra vì chúng ta sử dụng một hệ thống kinh doanh làm kho dữ liệu (ví dụ: một hệ thống kế toán) và cần duy trì tất cả dữ liệu trong hệ thống đó.
Việc triển khai một kho dữ liệu có thể có nhiều hình thức khác nhau. Cơ sở dữ liệu là một lựa chọn hiển nhiên, nhưng một tập hợp các tệp XML hoặc một kho tin nhắn trong bộ nhớ cũng có thể phục vụ như một kho dữ liệu. Đôi khi, chúng ta có thể sử dụng một ứng dụng làm kho dữ liệu. Điều quan trọng là kho dữ liệu phải có thể truy cập được bởi các thành phần ở các phần khác của giải pháp tích hợp để các phần này có thể tái tạo lại thông điệp gốc.
Trong khi mục đích ban đầu của Chứng Nhận Khiếu Nại là để tránh việc gửi đi khối lượng dữ liệu lớn, nó cũng có thể phục vụ cho những mục đích khác. Thường thì, chúng ta muốn loại bỏ dữ liệu nhạy cảm trước khi gửi tin nhắn cho một bên ngoài (xem hình). Điều này có nghĩa là các bên ngoài chỉ nhận dữ liệu trên cơ sở cần biết. Ví dụ, khi chúng ta gửi dữ liệu nhân viên cho một bên bên ngoài, chúng ta có thể thích tham chiếu nhân viên bằng một ID duy nhất nào đó và loại bỏ các trường như số an sinh xã hội. Sau khi bên ngoài hoàn thành quá trình yêu cầu, chúng ta tái cấu trúc tin nhắn hoàn chỉnh bằng cách gộp dữ liệu từ kho dữ liệu và tin nhắn trả về từ bên ngoài. Chúng ta thậm chí có thể tạo ra các khóa duy nhất đặc biệt cho những tin nhắn này để hạn chế các hành động mà bên ngoài có thể thực hiện dựa trên khóa mà họ đang sở hữu. Điều này sẽ hạn chế bên ngoài khỏi việc cố ý đưa vào hệ thống của chúng ta những tin nhắn xấu. Những tin nhắn chứa khóa không hợp lệ (hoặc đã hết hạn hoặc đã được sử dụng) sẽ bị Chương Trình Làm Giàu Nội Dung chặn lại khi cố gắng truy xuất dữ liệu tin nhắn bằng khóa xấu.
Loại bỏ dữ liệu tin nhắn nhạy cảm ra ngoài ranh giới quy trình đáng tin cậy.

Nếu chúng ta tương tác với nhiều bên bên ngoài, một Người Quản Lý Quy Trình có thể cung cấp chức năng của một Phiếu Nhận. Người Quản Lý Quy Trình tạo ra các thể hiện quy trình (thỉnh thoảng được gọi là nhiệm vụ hoặc công việc) khi một thông điệp đến. Người Quản Lý Quy Trình cho phép dữ liệu bổ sung được liên kết với từng thể hiện quy trình cá nhân. Thực tế, động cơ quy trình giờ đây đóng vai trò là kho lưu trữ dữ liệu, lưu trữ dữ liệu thông điệp của chúng ta. Điều này cho phép Người Quản Lý Quy Trình gửi thông điệp đến các bên bên ngoài chỉ chứa dữ liệu liên quan đến bên đó. Các thông điệp không cần phải mang tất cả thông tin có trong thông điệp gốc, vì thông tin đó được giữ lại với kho dữ liệu của quy trình. Khi Người Quản Lý Quy Trình nhận được một thông điệp phản hồi từ một bên bên ngoài, nó kết hợp dữ liệu mới với dữ liệu đã được lưu trữ bởi thể hiện quy trình.
Lưu trữ dữ liệu bên trong một Trình quản lý quy trình

Trong một kịch bản tích hợp doanh nghiệp-đến-doanh nghiệp (B2B), việc một doanh nghiệp nhận tin nhắn từ nhiều đối tác kinh doanh khác nhau là điều khá phổ biến. Những tin nhắn này có thể mang cùng một ý nghĩa nhưng theo các định dạng khác nhau, tùy thuộc vào hệ thống và sở thích nội bộ của các đối tác. Ví dụ, tại ThoughtWorks, chúng tôi đã xây dựng một giải pháp cho một nhà cung cấp trả tiền theo lượt xem, phải tiếp nhận và xử lý thông tin về lượt xem từ hơn 1.700 chi nhánh, hầu hết trong số đó không tuân theo một định dạng tiêu chuẩn.
| Bạn xử lý các thông điệp có nghĩa tương đương nhưng đến dưới định dạng khác như thế nào? |
Giải pháp dễ nhất từ góc độ kỹ thuật có thể dường như là quy định một định dạng đồng nhất cho tất cả các bên tham gia. Điều này có thể hiệu quả nếu doanh nghiệp là một tập đoàn lớn và kiểm soát được nền tảng B2B hoặc kênh cung ứng. Ví dụ, nếu General Motors muốn nhận cập nhật trạng thái đơn hàng từ các nhà cung cấp của mình theo một định dạng tin nhắn chung, chúng ta có thể chắc chắn rằng doanh nghiệp của Joe sẽ tuân thủ các hướng dẫn của GM. Tuy nhiên, trong nhiều tình huống khác, một doanh nghiệp sẽ không có được sự xa xỉ như vậy. Ngược lại, nhiều mô hình kinh doanh định vị người nhận tin nhắn như một "tổng hợp" thông tin, và một phần của thỏa thuận với các bên tham gia là yêu cầu tối thiểu về sự thay đổi trong hạ tầng hệ thống của họ. Do đó, bạn sẽ thấy người tổng hợp sẵn sàng xử lý thông tin đến bằng bất kỳ định dạng dữ liệu nào từ các bản ghi EDI hoặc tệp phân tách bằng dấu phẩy đến các tài liệu XML hoặc bảng tính Excel nhận được qua email.
Một điều quan trọng cần xem xét khi làm việc với nhiều đối tác là tốc độ thay đổi. Không chỉ mỗi bên tham gia có thể thích một định dạng dữ liệu khác nhau ngay từ đầu, mà định dạng ưa thích cũng có thể thay đổi theo thời gian. Thêm vào đó, những đối tác mới có thể tham gia trong khi những đối tác khác rút lui. Ngay cả khi một đối tác cụ thể chỉ thay đổi định dạng dữ liệu một lần mỗi vài năm, việc làm việc với vài chục đối tác có thể nhanh chóng dẫn đến những thay đổi hàng tháng hoặc hàng tuần. Việc tách biệt những thay đổi này ra khỏi phần còn lại của quá trình càng nhiều càng tốt là rất quan trọng để tránh "hiệu ứng gợn sóng" của những thay đổi lan rộng trong toàn bộ hệ thống.
Để tách phần còn lại của hệ thống khỏi nhiều định dạng tin nhắn đến khác nhau, bạn cần chuyển đổi các tin nhắn đến thành một định dạng chung. Vì các tin nhắn đến có nhiều loại khác nhau, bạn cần một Trình Dịch Tin Nhắn khác nhau cho mỗi định dạng dữ liệu tin nhắn. Cách đơn giản nhất để thực hiện điều này là sử dụng một bộ Kênh Dữ Liệu, mỗi kênh cho mỗi loại tin nhắn. Mỗi Kênh Dữ Liệu sau đó được kết nối với một Trình Dịch Tin Nhắn khác nhau. Nhược điểm của phương pháp này là một số lượng lớn định dạng tin nhắn sẽ chuyển thành một số lượng Kênh Tin Nhắn tương ứng lớn.
| Sử dụng một Bộ chuẩn hóa để định tuyến từng loại tin nhắn qua một Bộ biên dịch tùy chỉnh để các tin nhắn kết quả khớp với một định dạng chung.
|
Bộ chuẩn hóa có một Bộ dịch tin nhắn cho mỗi định dạng tin nhắn và chuyển hướng tin nhắn đến Bộ dịch tin nhắn đúng thông qua Bộ định tuyến tin nhắn.
Việc định tuyến tin nhắn đến Bộ dịch tin nhắn đúng đòi hỏi Bộ định tuyến tin nhắn có thể phát hiện loại của tin nhắn đến. Nhiều hệ thống nhắn tin trang bị cho mỗi tin nhắn một trường xác định loại trong tiêu đề tin nhắn để thực hiện công việc này một cách đơn giản. Tuy nhiên, trong nhiều kịch bản B2B, các tin nhắn không đến dưới dạng tin nhắn tuân thủ hệ thống nhắn tin nội bộ của doanh nghiệp, mà ở nhiều định dạng khác nhau như tệp phân cách bằng dấu phẩy hoặc tài liệu XML mà không có lược đồ kèm theo. Mặc dù việc trang bị cho bất kỳ định dạng dữ liệu nào đến một trường xác định loại là thực tiễn tốt nhất, nhưng chúng ta cũng biết rằng thế giới rất xa rời sự hoàn hảo. Do đó, chúng ta cần nghĩ đến những cách chung hơn để xác định định dạng của tin nhắn đến. Một cách phổ biến đối với các tài liệu XML không có lược đồ là sử dụng tên của phần tử gốc để giả định loại chính xác. Nếu nhiều định dạng dữ liệu sử dụng cùng một phần tử gốc, bạn có thể sử dụng biểu thức XPath để xác định sự hiện diện của các nút con cụ thể. Các tệp phân cách bằng dấu phẩy có thể yêu cầu một chút sáng tạo hơn. Đôi khi bạn có thể xác định loại dựa trên số lượng trường và loại dữ liệu (ví dụ: số phân biệt với chuỗi). Nếu dữ liệu đến dưới dạng tệp, cách dễ nhất có thể là sử dụng tên tệp hoặc cấu trúc thư mục tệp như một Kênh Nhóm Dữ liệu ủy nhiệm. Mỗi đối tác kinh doanh có thể đặt tên tệp theo quy tắc đặt tên độc nhất. Bộ định tuyến tin nhắn sau đó có thể sử dụng tên tệp để định tuyến tin nhắn đến Bộ dịch tin nhắn thích hợp.
Việc sử dụng một Bộ định tuyến Thông điệp cũng cho phép việc biến đổi giống hệt được sử dụng cho nhiều đối tác kinh doanh. Điều này có thể hữu ích nếu nhiều đối tác kinh doanh sử dụng cùng một định dạng hoặc nếu một biến đổi đủ chung chung để thích ứng với nhiều định dạng thông điệp khác nhau. Ví dụ, các biểu thức XPath rất tuyệt vời trong việc chọn các yếu tố từ tài liệu XML ngay cả khi các tài liệu có sự khác biệt về định dạng.
Vì Bộ chuẩn hóa là một trường hợp phổ biến trong các giải pháp nhắn tin, chúng tôi đã tạo một biểu tượng viết tắt cho nó:
Người chuẩn hóa đang hoạt động

Chúng tôi đang thiết kế một số ứng dụng để làm việc cùng nhau thông qua Nhắn tin. Mỗi ứng dụng có định dạng dữ liệu nội bộ riêng.
| Làm thế nào bạn có thể giảm thiểu sự phụ thuộc khi tích hợp các ứng dụng sử dụng các định dạng dữ liệu khác nhau? |
Các ứng dụng phát triển độc lập thường sử dụng các định dạng dữ liệu khác nhau vì mỗi định dạng được thiết kế với chỉ ứng dụng đó trong tâm trí. Khi một ứng dụng được thiết kế để gửi tin nhắn đến hoặc nhận tin nhắn từ một ứng dụng không xác định nào đó, ứng dụng sẽ tự nhiên sử dụng định dạng tin nhắn mà nó thấy thuận tiện nhất. Tương tự, các bộ chuyển đổi thương mại được sử dụng để tích hợp các ứng dụng đã đóng gói thường công bố và tiêu thụ các tin nhắn ở định dạng dữ liệu tương tự như cấu trúc dữ liệu nội bộ của ứng dụng.
"Trình Dịch Tin Nhắn giải quyết sự khác biệt trong định dạng tin nhắn mà không thay đổi các ứng dụng hoặc làm cho các ứng dụng biết đến định dạng dữ liệu của nhau. Tuy nhiên, nếu có một số lượng lớn các ứng dụng giao tiếp với nhau, có thể cần một Trình Dịch Tin Nhắn giữa mỗi cặp ứng dụng giao tiếp (xem hình)."
Số lượng kết nối bùng nổ với số lượng hệ thống ngày càng tăng.

Cách tiếp cận này yêu cầu một số lượng lớn Bộ dịch Tin nhắn, đặc biệt khi xem xét rằng mỗi ứng dụng tích hợp có thể xuất bản hoặc tiêu thụ nhiều loại tin nhắn khác nhau. Số lượng Bộ dịch Tin nhắn cần thiết tăng theo cấp số nhân với số lượng ứng dụng tích hợp, điều này nhanh chóng trở nên không thể quản lý được.
Trong khi Bộ dịch Tin nhắn cung cấp một sự gián tiếp giữa các định dạng tin nhắn được sử dụng bởi hai ứng dụng giao tiếp, nó vẫn phụ thuộc vào các định dạng tin nhắn được sử dụng bởi từng ứng dụng. Kết quả là, nếu định dạng dữ liệu của một ứng dụng thay đổi, tất cả các Bộ dịch Tin nhắn giữa ứng dụng đang thay đổi và tất cả các ứng dụng khác mà nó giao tiếp đều phải thay đổi. Tương tự, nếu một ứng dụng mới được thêm vào giải pháp, cần phải tạo ra các Bộ dịch Tin nhắn mới từ mỗi ứng dụng hiện có đến ứng dụng mới để có thể trao đổi tin nhắn. Tình huống này tạo ra một cơn ác mộng trong việc phải duy trì tất cả các Bộ dịch Tin nhắn.
Chúng ta cũng cần nhớ rằng mỗi bước biến đổi bổ sung được tiêm vào dòng thông điệp có thể làm tăng độ trễ và giảm thông lượng thông điệp.
| Thiết kế một Mô hình Dữ liệu Chuẩn độc lập với bất kỳ ứng dụng cụ thể nào. Yêu cầu mỗi ứng dụng phải sản xuất và tiêu thụ các thông điệp theo định dạng chung này.
|
Mô hình Dữ liệu Canonical cung cấp một mức độ gián tiếp bổ sung giữa các định dạng dữ liệu riêng lẻ của các ứng dụng. Nếu một ứng dụng mới được thêm vào giải pháp tích hợp, chỉ cần tạo một phép biến đổi giữa Mô hình Dữ liệu Canonical, bất kể số lượng ứng dụng đã tham gia là bao nhiêu.
Việc sử dụng Mô hình Dữ liệu Chuẩn có thể trông quá phức tạp nếu chỉ có một số ít ứng dụng tham gia vào giải pháp tích hợp. Tuy nhiên, giải pháp này nhanh chóng mang lại lợi ích khi số lượng ứng dụng tăng lên. Nếu chúng ta giả định rằng mỗi ứng dụng gửi và nhận tin nhắn từ các ứng dụng khác, một giải pháp gồm hai ứng dụng sẽ chỉ yêu cầu hai Bộ chuyển đổi Tin nhắn nếu chúng ta dịch giữa các định dạng dữ liệu của ứng dụng một cách trực tiếp, trong khi đó Mô hình Dữ liệu Chuẩn yêu cầu bốn Bộ chuyển đổi Tin nhắn. Một giải pháp gồm ba ứng dụng yêu cầu sáu Bộ chuyển đổi Tin nhắn với cả hai cách tiếp cận. Tuy nhiên, một giải pháp gồm sáu ứng dụng sẽ yêu cầu 30 Bộ chuyển đổi Tin nhắn mà không có Mô hình Dữ liệu Chuẩn và chỉ 12 Bộ chuyển đổi Tin nhắn khi sử dụng Mô hình Dữ liệu Chuẩn.
Mô hình Dữ liệu chuẩn cũng có thể rất hữu ích nếu một ứng dụng hiện có có khả năng bị thay thế bởi một ứng dụng khác trong tương lai. Chẳng hạn, nếu một số ứng dụng giao tiếp với một hệ thống kế thừa có khả năng bị thay thế bởi một hệ thống mới trong tương lai, nỗ lực chuyển đổi từ ứng dụng này sang ứng dụng khác sẽ giảm đi rất nhiều nếu khái niệm Mô hình Dữ liệu chuẩn được tích hợp vào giải pháp gốc.
Làm thế nào để bạn làm cho các ứng dụng tuân theo định dạng chung? Bạn có ba lựa chọn cơ bản:
Thay đổi định dạng dữ liệu nội bộ của các ứng dụng. Điều này có thể khả thi trong lý thuyết, nhưng khó có thể xảy ra trong một kịch bản thực tế phức tạp. Nếu dễ dàng để mỗi ứng dụng sử dụng cùng một định dạng dữ liệu một cách tự nhiên, thì chúng ta sẽ tốt hơn nếu sử dụng Cơ sở Dữ liệu Chia sẻ thay vì Tin nhắn.
Triển khai một Trình ánh xạ Tin nhắn bên trong ứng dụng. Các ứng dụng tùy chỉnh có thể sử dụng một trình ánh xạ để tạo ra định dạng dữ liệu mong muốn.
Sử dụng một Trình Dịch Tin Nhắn bên ngoài. Bạn có thể sử dụng Trình Dịch Tin Nhắn bên ngoài để dịch từ định dạng tin nhắn cụ thể của ứng dụng sang định dạng được chỉ định bởi Mô Hình Dữ Liệu Canonical. Đây có thể là tùy chọn duy nhất của bạn để chuyển đổi dữ liệu của một ứng dụng đóng gói.
Việc sử dụng một Trình ánh xạ tin nhắn hay một Bộ biên dịch tin nhắn bên ngoài phụ thuộc vào độ phức tạp của việc chuyển đổi và khả năng bảo trì của ứng dụng. Các ứng dụng đã được đóng gói thường loại bỏ việc sử dụng Trình ánh xạ tin nhắn vì mã nguồn không có sẵn. Đối với các ứng dụng tùy chỉnh, sự lựa chọn phụ thuộc vào độ phức tạp của việc chuyển đổi. Nhiều bộ công cụ tích hợp cung cấp các trình chỉnh sửa chuyển đổi trực quan cho phép xây dựng quy tắc ánh xạ nhanh hơn. Tuy nhiên, những công cụ trực quan này có thể trở nên khó khăn nếu các chuyển đổi phức tạp.
Khi sử dụng một Trình Dịch Tin Nhắn bên ngoài, chúng ta cần phân biệt giữa các tin nhắn công (theo chuẩn) và tin nhắn riêng (cụ thể cho ứng dụng). Các tin nhắn giữa một ứng dụng và Trình Dịch Tin Nhắn liên quan của nó được coi là riêng tư vì không có ứng dụng nào khác nên sử dụng những tin nhắn này. Khi Trình Dịch Tin Nhắn chuyển đổi tin nhắn sang định dạng tuân thủ Mô Hình Dữ Liệu Chuẩn, tin nhắn đó được coi là công khai và có thể được sử dụng bởi các hệ thống khác.
Việc sử dụng Mô hình Dữ liệu Canonical sẽ tạo ra một mức độ chi phí nhất định trong dòng chảy của thông điệp. Mỗi thông điệp bây giờ phải trải qua hai bước dịch thay vì một: một bước dịch từ định dạng của ứng dụng nguồn sang định dạng chung và một bước từ định dạng chung sang định dạng của ứng dụng đích. Vì lý do này, việc sử dụng Mô hình Dữ liệu Canonical đôi khi được gọi là dịch kép (việc chuyển đổi trực tiếp từ định dạng của ứng dụng này sang ứng dụng khác được gọi là dịch trực tiếp). Mỗi bước dịch gây ra độ trễ bổ sung trong dòng chảy của thông điệp. Do đó, đối với các hệ thống có thông lượng rất cao, dịch trực tiếp có thể là lựa chọn duy nhất. Sự cân nhắc giữa khả năng bảo trì và hiệu suất là điều phổ biến. Lời khuyên tốt nhất là sử dụng giải pháp dễ bảo trì hơn (tức là Mô hình Dữ liệu Canonical) trừ khi yêu cầu về hiệu suất không cho phép. Một yếu tố giảm nhẹ có thể là nhiều bước dịch không duy trì trạng thái và do đó dễ dàng thực hiện cân bằng tải với nhiều Bộ dịch Thông điệp thực thi song song.
Việc thiết kế một Mô hình Dữ liệu Chuẩn có thể rất khó khăn; hầu hết các doanh nghiệp đều có ít nhất một nỗ lực "mô hình dữ liệu doanh nghiệp" không thành công trong lịch sử của mình. Để đạt được một mô hình cân bằng, các nhà thiết kế nên cố gắng khiến mô hình thống nhất hoạt động tốt như nhau cho tất cả các ứng dụng đang được tích hợp. Thật không may, trong thực tế, lý tưởng này khó có thể đạt được. Khả năng thành công trong việc thiết kế một Mô hình Dữ liệu Chuẩn tăng lên khi xem xét rằng Mô hình Dữ liệu Chuẩn không cần phải mô hình hóa toàn bộ tập dữ liệu được sử dụng trong tất cả các ứng dụng, mà chỉ cần mô hình hóa phần tham gia vào việc nhắn tin (xem hình). Điều này có thể giảm đáng kể độ phức tạp trong việc tạo ra Mô hình Dữ liệu Chuẩn.
Chỉ Mô Hình Hóa Dữ Liệu Liên Quan

Việc sử dụng Mô hình Dữ liệu Chính thống cũng có thể mang lại lợi thế chính trị. Sử dụng Mô hình Dữ liệu Chính thống cho phép các nhà phát triển và người dùng doanh nghiệp thảo luận về giải pháp tích hợp theo các khái niệm trong lĩnh vực kinh doanh của công ty, không phải theo một việc triển khai gói cụ thể. Ví dụ, các ứng dụng gói có thể đại diện cho khái niệm chung về một khách hàng dưới nhiều định dạng nội bộ khác nhau, chẳng hạn như "tài khoản," "người thanh toán," và "liên hệ." Định nghĩa một Mô hình Dữ liệu Chính thống thường là bước đầu tiên để giải quyết các trường hợp bất hòa ngữ nghĩa giữa các ứng dụng.
Hình ảnh ở đầu mẫu này cho thấy số lượng lớn các bộ chuyển đổi cần thiết để chuyển đổi giữa từng ứng dụng trông thật sự giống với hình ảnh được trình bày trong Message Broker. Điều này nhắc nhở chúng ta rằng các phụ thuộc giữa các ứng dụng có thể tồn tại ở nhiều cấp độ khác nhau. Việc sử dụng Kênh Tin Nhắn cung cấp một lớp vận chuyển chung giữa các ứng dụng và loại bỏ các phụ thuộc giữa các giao thức vận chuyển riêng lẻ của các ứng dụng. Bộ Định Tuyến Tin Nhắn có thể cung cấp sự độc lập về vị trí để ứng dụng gửi không phải phụ thuộc vào vị trí của ứng dụng nhận. Việc sử dụng một đại diện dữ liệu chung như XML loại bỏ các phụ thuộc vào bất kỳ kiểu dữ liệu cụ thể của ứng dụng nào. Cuối cùng, Mô Hình Dữ Liệu Canonical giải quyết các phụ thuộc về định dạng và ngữ nghĩa dữ liệu được các ứng dụng sử dụng.
Như thường lệ, điều duy nhất không thay đổi là sự thay đổi. Do đó, các thông điệp tuân theo Mô hình Dữ liệu Chính thức nên chỉ định một Chỉ thị Định dạng.
| Ví dụ: WSDL Khi truy cập một dịch vụ bên ngoài từ ứng dụng của bạn, dịch vụ có thể đã chỉ định một Mô hình Dữ liệu Chuẩn (Canonical Data Model) để sử dụng. Trong thế giới dịch vụ web XML, định dạng dữ liệu được chỉ định bởi tài liệu WSDL (Ngôn ngữ Định nghĩa Dịch vụ Web; xem [WSDL 1.1]). WSDL chỉ định cấu trúc của các thông điệp yêu cầu và phản hồi mà dịch vụ có thể tiêu thụ và tạo ra. Trong hầu hết các trường hợp, định dạng dữ liệu được chỉ định trong WSDL khác với định dạng nội bộ của ứng dụng cung cấp dịch vụ. Thực tế, WSDL chỉ định một Mô hình Dữ liệu Chuẩn để được cả hai bên tham gia vào cuộc trò chuyện sử dụng. Việc dịch đôi bao gồm một Bộ ánh xạ Tin nhắn (Messaging Mapper) hoặc một Cổng Tin nhắn (Messaging Gateway) ở bên tiêu thụ dịch vụ và một Giao diện Từ xa (Remote Facade) [EAA] ở bên cung cấp dịch vụ. |
| Ví dụ: TIBCO ActiveEnterprise Nhiều bộ công cụ EAI cung cấp một bộ công cụ hoàn chỉnh để định nghĩa và mô tả Mô hình Dữ liệu Chuẩn. Ví dụ, bộ TIBCO ActiveEnterprise cung cấp TIB/Designer cho phép người dùng kiểm tra tất cả các định nghĩa thông điệp chung. Các định nghĩa thông điệp có thể được nhập từ hoặc xuất sang các định nghĩa lược đồ XML. Khi triển khai Trình dịch Thông điệp bằng cách sử dụng bộ công cụ trực quan tích hợp sẵn, công cụ này cung cấp cho nhà thiết kế cả định dạng dữ liệu cụ thể cho ứng dụng và Mô hình Dữ liệu Chuẩn được lưu trữ trong kho dữ liệu trung tâm. Điều này đơn giản hóa việc cấu hình Trình dịch Thông điệp giữa hai định dạng dữ liệu. Công cụ TIBCO Designer: Một công cụ GUI để duy trì mô hình dữ liệu chuẩn
|
Ví dụ về Nhân viên Môi giới Vay vốn
Triển khai đồng bộ sử dụng dịch vụ web
"Triển khai không đồng bộ với MSMQ"
Triển khai không đồng bộ với TIBCO ActiveEnterprise
Chương này trình bày cách phối hợp các mẫu định tuyến và biến đổi thành một giải pháp lớn hơn. Là một kịch bản ví dụ, chúng tôi đã chọn mô hình hóa quá trình một người tiêu dùng nhận báo giá cho một khoản vay từ nhiều ngân hàng. Chúng tôi đã giản lược quy trình kinh doanh một chút để có thể tập trung vào việc thảo luận về các mẫu tích hợp thay vì tổ chức một bài giảng về dịch vụ tài chính cho người tiêu dùng. Dựa trên các mẫu mà chúng tôi định nghĩa, chúng tôi thảo luận và tạo ra ba triển khai thay thế cho quá trình này, sử dụng các ngôn ngữ lập trình, công nghệ và mô hình nhắn tin khác nhau.
Khi mua sắm một khoản vay, khách hàng thường gọi điện cho vài ngân hàng để tìm kiếm gói vay với lãi suất tốt nhất có thể. Mỗi ngân hàng đều yêu cầu khách hàng cung cấp số an sinh xã hội, số tiền vay và thời gian vay mong muốn (tức là số tháng cho đến khi khoản vay phải được trả hết). Sau đó, mỗi ngân hàng sẽ điều tra hồ sơ tín dụng của khách hàng, thường bằng cách liên hệ với một cơ quan tín dụng. Dựa trên các điều kiện được yêu cầu và lịch sử tín dụng của khách hàng, ngân hàng sẽ phản hồi với một báo giá lãi suất cho người tiêu dùng (hoặc từ chối một cách lịch thiệp). Khi khách hàng đã nhận được báo giá từ tất cả các ngân hàng, họ có thể chọn gói vay tốt nhất với lãi suất thấp nhất.
Một người tiêu dùng nói chuyện với ngân hàng để nhận báo giá vay.

Vì việc liên hệ với nhiều ngân hàng để yêu cầu báo giá vay là một công việc tẻ nhạt, các môi giới vay tiền cung cấp dịch vụ này cho người tiêu dùng. Một môi giới vay tiền thường không liên kết với bất kỳ ngân hàng nào nhưng có quyền truy cập vào nhiều tổ chức cho vay. Môi giới thu thập dữ liệu khách hàng một lần và liên hệ với cơ quan tín dụng để lấy lịch sử tín dụng của khách hàng. Dựa trên điểm tín dụng và lịch sử, môi giới trình bày yêu cầu đến một số ngân hàng phù hợp nhất để đáp ứng tiêu chí của khách hàng. Môi giới thu thập các báo giá nhận được từ các ngân hàng và chọn đề nghị tốt nhất để chuyển lại cho người tiêu dùng.
Một người môi giới vay tiền hoạt động như trung gian

Chúng tôi muốn thiết kế một hệ thống môi giới vay vốn sử dụng các mẫu tích hợp đã thảo luận trong các chương trước. Để làm điều này, trước tiên hãy liệt kê các nhiệm vụ cá nhân mà môi giới vay vốn cần thực hiện.
Nhận yêu cầu báo giá khoản vay của người tiêu dùng.
Nhận điểm tín dụng và lịch sử tín dụng từ cơ quan tín dụng.
Xác định những ngân hàng thích hợp nhất để liên hệ.
Gửi yêu cầu đến từng ngân hàng đã chọn.
Thu thập phản hồi từ mỗi ngân hàng đã chọn.
Xác định phản hồi tốt nhất.
Trả kết quả lại cho người tiêu dùng.
Hãy xem những mẫu nào có thể giúp chúng ta thiết kế và triển khai dịch vụ môi giới vay. Bước đầu tiên mô tả cách mà môi giới nhận yêu cầu đến. Chúng tôi sẽ đề cập đến chủ đề này chi tiết hơn trong Chương 10, "Điểm cuối nhắn tin," vì vậy bây giờ, hãy bỏ qua bước này và giả định rằng tin nhắn đã được môi giới nhận bằng một cách nào đó. Tiếp theo, môi giới cần lấy thêm thông tin: điểm tín dụng của khách hàng. Một Người làm giàu Nội dung có vẻ là lựa chọn lý tưởng cho nhiệm vụ này. Khi môi giới có đầy đủ thông tin, môi giới phải xác định các ngân hàng phù hợp để chuyển yêu cầu tin nhắn tới. Chúng tôi có thể thực hiện điều này bằng một Người làm giàu Nội dung khác, tính toán danh sách người nhận cho yêu cầu. Gửi một tin nhắn yêu cầu tới nhiều người nhận và kết hợp lại các phản hồi thành một tin nhắn duy nhất là sở trường của Mô hình Rải-Rộc. Mô hình Rải-Rộc có thể sử dụng Kênh Đăng ký-Công bố hoặc Danh sách Người nhận để gửi yêu cầu tới các ngân hàng. Khi các ngân hàng phản hồi với các báo giá lãi suất của họ, Mô hình Rải-Rộc tổng hợp các báo giá lãi suất cá nhân thành một báo giá duy nhất cho người tiêu dùng bằng cách sử dụng một Người tổng hợp. Nếu chúng ta mô hình hóa luồng tin nhắn bằng các mẫu này, chúng ta sẽ có được thiết kế sau:
Thiết kế Môi giới Vay đơn giản

Chúng tôi chưa tính đến khả năng mà mỗi ngân hàng có thể sử dụng một định dạng thông điệp hơi khác nhau cho yêu cầu và phản hồi vay. Bởi vì chúng tôi muốn tách biệt logic định tuyến và tổng hợp khỏi các định dạng độc quyền của ngân hàng, chúng tôi cần chèn các Bộ biên dịch Thông điệp vào các dòng giao tiếp giữa nhà môi giới và các ngân hàng. Chúng tôi có thể sử dụng một Bộ chuẩn hóa để dịch các phản hồi cá nhân thành một định dạng chung.
Thiết kế Môi giới Vay Hoàn Chỉnh

Cho đến nay, chúng tôi đã mô tả quy trình của các thông điệp và các mẫu định tuyến và biến đổi mà chúng tôi có thể sử dụng để mô tả thiết kế của thành phần trung gian cho vay. Chúng tôi vẫn chưa thảo luận về thời gian hoạt động của trung gian. Chúng tôi có hai lựa chọn chính:
Đồng bộ (Tuần tự): Người môi giới yêu cầu một ngân hàng báo giá và chờ phản hồi trước khi liên hệ với ngân hàng tiếp theo.
Bất đồng bộ (Song song): Người môi giới gửi tất cả các yêu cầu báo giá cùng một lúc và chờ đợi các câu trả lời trở về.
Chúng ta có thể sử dụng biểu đồ tuần tự UML để minh họa cho hai tùy chọn. Tùy chọn đồng bộ ngụ ý một quy trình xử lý tuần tự tất cả các yêu cầu vay (xem hình bên dưới). Giải pháp này có ưu điểm là dễ quản lý hơn vì chúng ta không phải đối mặt với bất kỳ vấn đề đồng thời nào hoặc các luồng. Tuy nhiên, đây là một giải pháp kém hiệu quả vì chúng ta không tận dụng được thực tế là mỗi ngân hàng có khả năng xử lý độc lập và có thể thực hiện các yêu cầu đồng thời. Kết quả là, người tiêu dùng có thể phải chờ đợi một thời gian dài để nhận được câu trả lời.
Xử lý đơn vay một cách đồng bộ và tuần tự

Giải pháp bất đồng bộ phát hành tất cả các yêu cầu ngay lập tức để mỗi ngân hàng có thể bắt đầu xử lý. Khi các ngân hàng hoàn thành việc tính toán, họ sẽ trả lại kết quả cho môi giới cho vay. Giải pháp này cho phép có phản hồi nhanh hơn nhiều. Ví dụ, nếu tất cả các ngân hàng mất một khoảng thời gian tương tự để tạo ra một báo giá vay, giải pháp này nhanh hơn gần n lần, trong đó n là số lượng ngân hàng mà chúng ta đang xử lý. Môi giới cho vay bây giờ phải có khả năng chấp nhận các tin nhắn phản hồi báo giá vay theo bất kỳ thứ tự nào, vì không có đảm bảo rằng các phản hồi đến theo cùng một thứ tự mà các yêu cầu đã được thực hiện. Sơ đồ tuần tự dưới đây minh họa tùy chọn này. Mũi tên mở trên yêu cầu báo giá vay chỉ ra một cuộc gọi bất đồng bộ.
Xử lý yêu cầu vay đồng thời và bất đồng bộ

Một lợi thế đáng kể khác của việc sử dụng gọi không đồng bộ thông qua hàng đợi tin nhắn là khả năng tạo ra nhiều hơn một thể hiện của nhà cung cấp dịch vụ. Ví dụ, nếu hóa ra rằng cơ quan tín dụng là một điểm nghẽn, chúng ta có thể quyết định chạy hai thể hiện của thành phần đó. Bởi vì nhà môi giới khoản vay gửi tin nhắn yêu cầu vào một hàng đợi thay vì trực tiếp đến thành phần cơ quan tín dụng, nên không quan trọng thể hiện thành phần nào xử lý tin nhắn miễn là phản hồi được đưa trở lại kênh phản hồi.
Sử dụng phương pháp Scatter-Gather để có được báo giá tốt nhất cho phép chúng ta lựa chọn giữa hai cơ chế địa chỉ, đó là Danh sách Người Nhận hoặc Kênh Đăng ký - Đăng ký. Quyết định chủ yếu phụ thuộc vào mức độ kiểm soát mà chúng ta muốn có đối với các ngân hàng được phép tham gia vào một yêu cầu vay cụ thể. Một lần nữa, chúng ta có một số lựa chọn:
Đã sửa: Danh sách các ngân hàng được lập trình cứng. Mỗi yêu cầu vay tiền đều gửi đến cùng một tập hợp ngân hàng.
Phân phối: Nhà môi giới duy trì các tiêu chí để xác định ngân hàng nào phù hợp với một yêu cầu cụ thể. Ví dụ, họ sẽ không gửi yêu cầu báo giá cho một khách hàng có lịch sử tín dụng kém đến một ngân hàng chuyên phục vụ khách hàng cao cấp.
Đấu giá: Người môi giới phát sóng yêu cầu thông qua kênh Xuất bản-Đăng ký. Bất kỳ ngân hàng nào quan tâm đều được phép đăng ký theo kênh và "đấu thầu" trên yêu cầu. Các ngân hàng có thể tự do đăng ký hoặc hủy đăng ký. Mỗi ngân hàng vẫn có thể áp dụng tiêu chí riêng của mình để quyết định có nên đưa ra một đề nghị giá hay không.

Lựa chọn nào là tốt nhất cho kịch bản của chúng ta? Như thường lệ, không có câu trả lời đơn giản "và câu trả lời là...," nhưng sự lựa chọn được điều chỉnh bởi cả sở thích và ràng buộc về kinh doanh cũng như kỹ thuật. Lựa chọn đầu tiên đơn giản và cho phép bên môi giới kiểm soát danh sách các ngân hàng. Tuy nhiên, nếu có nhiều ngân hàng mới đến và ra đi thường xuyên, giải pháp này có thể gây ra gánh nặng hành chính. Hơn nữa, ngân hàng có thể không hài lòng khi nhận được nhiều yêu cầu không liên quan, vì mỗi yêu cầu đều phát sinh một chi phí nội bộ nhất định cho ngân hàng. Ngoài ra, để duy trì sự đơn giản của phương pháp này, chiến lược tổng hợp có khả năng yêu cầu tất cả các ngân hàng phải gửi phản hồi. Các ngân hàng có thể muốn giữ quyền từ chối tham gia vào đấu thầu.
Cách tiếp cận phân phối (sử dụng Danh sách Người nhận) cho phép môi giới có nhiều quyền kiểm soát hơn đối với ngân hàng nào được liên quan trong mỗi yêu cầu vay. Điều này giúp môi giới hiệu quả hơn bằng cách giảm số lượng yêu cầu. Nó cũng cho phép môi giới ưa chuộng một số ngân hàng dựa trên mối quan hệ kinh doanh. Mặt trái là nó yêu cầu thêm logic kinh doanh được triển khai và duy trì bên trong thành phần môi giới cho vay. Cả hai cách tiếp cận phân phối và cố định đều yêu cầu một Kênh Tin nhắn riêng biệt cho từng người tham gia để kiểm soát luồng tin nhắn.
Sử dụng Kênh Xuất-Biên chế phát sóng yêu cầu vay đến tất cả các ngân hàng đang đăng ký và cho phép mỗi ngân hàng xác định yêu cầu nào sẽ được phục vụ. Mỗi ngân hàng có thể sử dụng Bộ Lọc Tin Nhắn hoặc triển khai Người Tiêu Thụ Lựa Chọn để lọc ra những yêu cầu vay không mong muốn. Phương pháp này làm cho người môi giới vay gần như không cần bảo trì trong trường hợp thêm hoặc xóa ngân hàng, nhưng nó yêu cầu nhiều công việc hơn từ phía các ngân hàng. Giải pháp này chỉ yêu cầu một Kênh Tin Nhắn duy nhất, nhưng nó phải được triển khai dưới dạng Kênh Xuất-Biên. Nhiều sơ đồ phát-báo hiệu quả sử dụng IP Đa hướng, thường không được định tuyến qua các mạng rộng hoặc Internet. Các triển khai khác mô phỏng Kênh Xuất-Biên bằng cách sử dụng một loạt các Kênh Điểm-đến-Điểm và Danh Sách Người Nhận. Phương pháp này bảo tồn ngữ nghĩa đơn giản của Kênh Xuất-Biên nhưng kém hiệu quả hơn trong việc sử dụng kênh và băng thông mạng. Để biết thêm về các thỏa hiệp giữa định tuyến và phát-báo cộng với lọc, hãy xem mô tả của Bộ Lọc Tin Nhắn.
Khi nhận báo giá vay từ ngân hàng, chúng ta có những lựa chọn thiết kế tương tự. Chúng ta có thể yêu cầu tất cả các ngân hàng gửi phản hồi của họ đến một kênh phản hồi duy nhất, hoặc chúng ta có thể có một kênh phản hồi riêng biệt cho từng ngân hàng. Sử dụng một kênh duy nhất làm giảm gánh nặng bảo trì việc thiết lập một kênh riêng cho từng ngân hàng tham gia nhưng yêu cầu mỗi thông điệp trả lời của ngân hàng phải bao gồm một trường xác định ngân hàng đã phát hành báo giá. Nếu chúng ta sử dụng một kênh phản hồi duy nhất, Người Tổng Hợp có thể không biết có bao nhiêu thông điệp phản hồi mong đợi trừ khi Danh Sách Người Nhận cung cấp thông tin này cho Người Tổng Hợp (chúng tôi gọi đây là Người Tổng Hợp đã được khởi tạo). Nếu chúng ta sử dụng Kênh Xuất Bản-Đăng Ký theo kiểu đấu giá, số lượng phản hồi có thể có là không xác định đối với môi giới vay, vì vậy Người Tổng Hợp phải áp dụng một điều kiện hoàn chỉnh không phụ thuộc vào tổng số người tham gia. Ví dụ, Người Tổng Hợp có thể đơn giản là chờ cho đến khi nhận được tối thiểu ba phản hồi. Nhưng ngay cả điều đó cũng sẽ rất rủi ro nếu tạm thời chỉ có hai ngân hàng tham gia. Trong trường hợp đó, Người Tổng Hợp có thể hết thời gian chờ và báo cáo rằng nó đã nhận được số lượng phản hồi không đủ.
Một dịch vụ như môi giới cho vay nên có khả năng xử lý nhiều khách hàng muốn sử dụng dịch vụ đồng thời. Ví dụ, nếu chúng ta công khai chức năng môi giới cho vay như một dịch vụ Web hoặc kết nối nó với một trang Web công cộng, chúng ta thực sự không kiểm soát được số lượng khách hàng và có thể nhận được hàng trăm hoặc hàng ngàn yêu cầu đồng thời. Chúng ta có thể cho phép môi giới cho vay xử lý nhiều yêu cầu đồng thời bằng hai chiến lược khác nhau:
Thực hiện nhiều phiên bản.
Một实例 dựa trên sự kiện.
Tùy chọn đầu tiên duy trì nhiều phiên bản song song của thành phần môi giới khoản vay. Chúng ta có thể khởi động một phiên bản mới cho mỗi yêu cầu đến hoặc duy trì một "bể" các tiến trình môi giới khoản vay đang hoạt động và phân bổ các yêu cầu đến tiến trình tiếp theo có sẵn (sử dụng Trình phân phối tin nhắn). Nếu không có tiến trình nào có sẵn, chúng ta sẽ xếp hàng các yêu cầu cho đến khi có một tiến trình trở nên có sẵn. Bể tiến trình có ưu điểm là chúng ta có thể phân bổ tài nguyên hệ thống một cách có thể dự đoán. Ví dụ, chúng ta có thể quyết định thực hiện tối đa 20 phiên bản môi giới khoản vay. Ngược lại, nếu chúng ta khởi động một tiến trình mới cho mỗi yêu cầu, chúng ta có thể nhanh chóng làm nghẹt máy tính nếu có đợt tăng đột biến về yêu cầu đồng thời. Ngoài ra, việc duy trì một bể các tiến trình đang chạy cho phép chúng ta tái sử dụng một tiến trình hiện có cho nhiều yêu cầu, giúp tiết kiệm thời gian cho việc khởi tạo và khởi động tiến trình.
Bởi vì phần lớn quy trình được yêu cầu bởi môi giới cho vay là chờ đợi phản hồi từ các bên bên ngoài (cơ quan tín dụng và các ngân hàng), việc chạy nhiều quy trình song song có thể không phải là cách sử dụng tài nguyên hệ thống hợp lý. Thay vào đó, chúng ta có thể chạy một phiên bản quy trình duy nhất phản ứng với các sự kiện tin nhắn đến khi chúng xuất hiện. Xử lý một tin nhắn riêng lẻ (ví dụ, báo giá từ ngân hàng) là một nhiệm vụ tương đối đơn giản, vì vậy một quy trình duy nhất có thể phục vụ nhiều yêu cầu đồng thời. Cách tiếp cận này sử dụng tài nguyên hệ thống hiệu quả hơn và đơn giản hóa việc quản lý giải pháp, vì chúng ta chỉ cần theo dõi một phiên bản quy trình duy nhất. Nhược điểm tiềm năng là khả năng mở rộng hạn chế vì chúng ta bị ràng buộc với một quy trình. Nhiều ứng dụng quy mô lớn sử dụng sự kết hợp của hai kỹ thuật, thực hiện nhiều quy trình song song, mỗi quy trình có thể xử lý nhiều yêu cầu đồng thời.
Việc thực hiện nhiều yêu cầu đồng thời đòi hỏi chúng ta phải liên kết mỗi thông điệp trong hệ thống với đúng phiên xử lý. Ví dụ, có thể thuận tiện nhất cho một ngân hàng khi gửi tất cả các thông điệp phản hồi đến một kênh cố định. Điều này có nghĩa là kênh phản hồi có thể chứa các thông điệp liên quan đến các yêu cầu báo giá đồng thời của những khách hàng khác nhau. Do đó, chúng ta cần trang bị mỗi thông điệp với một Mã nhận diện Tương quan để xác định yêu cầu của khách hàng mà ngân hàng đang phản hồi.
Để thực hiện ví dụ về môi giới vay, chúng ta cần đưa ra ba quyết định thiết kế chính: Chúng ta phải chọn một sơ đồ định trình cho các yêu cầu, chọn một sơ đồ địa chỉ cho các ngân hàng và xác định một chiến lược tổng hợp. Ngoài ra, chúng ta cũng phải chọn một ngôn ngữ lập trình và một cơ sở hạ tầng nhắn tin. Tổng hợp lại, những lựa chọn cá nhân này dẫn đến một số lượng lớn các lựa chọn triển khai tiềm năng. Chúng tôi đã chọn triển khai ba giải pháp đại diện để làm nổi bật những thỏa hiệp chính giữa các lựa chọn triển khai khác nhau. Như với tất cả các ví dụ trong cuốn sách này, việc lựa chọn công nghệ cụ thể có phần tùy ý và không chỉ ra sự vượt trội của công nghệ của một nhà cung cấp cụ thể. Bảng dưới đây làm nổi bật các đặc điểm của mỗi giải pháp:
Triển khai | Sắp xếp trình tự | Giải quyết | Tập hợp | Loại kênh | Công nghệ sản phẩm |
|---|---|---|---|---|---|
A | Đồng bộ | Phân phối | Kênh | Dịch vụ Web/SOAP | Java/Apache Axis trong tiếng Việt là "Java/Apache Axis". |
B | Asynchronous - Không đồng bộ | Phân phối | Mã tương quan | Hàng đợi tin nhắn | C#/Microsoft MSMQ |
C | Asynchronous in Vietnamese is "Không đồng bộ". | Đấu giá | ID tương quan | Cơ chế xuất bản-đăng ký | TIBCO Active-Enterprise |
Triển khai đầu tiên sử dụng dịch vụ Web đồng bộ được triển khai bằng Java và Apache Axis. Việc giao tiếp với từng ngân hàng diễn ra qua một kênh HTTP riêng biệt, phục vụ đồng thời như một kênh yêu cầu và kênh trả lời. Do đó, chiến lược tổng hợp dựa trên các kênh trả lời riêng lẻ và không yêu cầu sự tương quan. Triển khai thứ hai sử dụng cách tiếp cận không đồng bộ với hàng đợi tin nhắn. Chúng tôi thực hiện bằng MSMQ của Microsoft, nhưng một triển khai sử dụng JMS hoặc IBM WebSphere MQ có thể trông rất giống. Triển khai cuối cùng sử dụng cách tiếp cận Auction và tận dụng hạ tầng xuất bản-đăng ký của TIBCO cùng với công cụ TIB/IntegrationManager thực hiện mẫu Quản lý Quy trình. Trong tùy chọn B và C, tất cả các tin nhắn trả lời đến trên một kênh duy nhất và các triển khai sử dụng Các Nhận diện Tương quan để liên kết các tin nhắn trả lời với các yêu cầu báo giá khoản vay của khách hàng.
bởi Conrad F. D'Cruz
Phần này mô tả việc triển khai ví dụ về môi giới cho vay bằng cách sử dụng Java và dịch vụ Web XML. Chúng tôi sử dụng bộ công cụ mã nguồn mở Apache Axis để xử lý các cơ chế dịch vụ Web cho chúng tôi. Chúng tôi không muốn đây trở thành một bài tập về phát triển Java, vì vậy chúng tôi đã chọn bộ công cụ này để trừu tượng hóa những phức tạp trong việc triển khai giao diện dịch vụ Web đồng bộ. Thay vào đó, cuộc thảo luận trong phần này tập trung vào các quyết định thiết kế mà chúng tôi đưa ra khi thiết kế một giải pháp nhắn tin đồng bộ.
Kiến trúc giải pháp dịch vụ web

Hình này cho thấy kiến trúc tổng thể của việc triển khai dịch vụ Web dự đoán đồng bộ của ví dụ môi giới cho vay. Có bảy giao diện quan trọng giữa môi giới cho vay và phần còn lại của giải pháp. Như đã chỉ ra, SOAP qua HTTP được sử dụng để giao tiếp giữa mỗi cặp bên tham gia.
Giao diện đầu tiên là điểm truy cập vào môi giới cho vay mà ứng dụng khách sử dụng để truyền thông điệp chứa thông tin đơn vay. Ứng dụng khách nhận được kết quả truy vấn từ môi giới cho vay qua cùng một giao diện. Mặc dù máy chủ Axis không được hiển thị trong sơ đồ này, nó nhận thông điệp từ ứng dụng khách và thực hiện Bộ kích hoạt dịch vụ.
Giao diện thứ hai là giữa người môi giới vay và cơ quan tín dụng. Cơ quan tín dụng là một tổ chức bên ngoài và cung cấp một giao diện dịch vụ web để người môi giới vay có thể thu thập thêm dữ liệu khách hàng cần thiết cho các ngân hàng. Người môi giới vay làm phong phú yêu cầu đến bằng dữ liệu từ cơ quan tín dụng, thực hiện việc làm phong phú nội dung.
Năm giao diện tiếp theo là giữa môi giới cho vay và năm ngân hàng. Mỗi giao diện được sử dụng để nhận báo giá lãi suất cho một khoản vay từ ngân hàng cụ thể đó. Mỗi giao diện ngân hàng cung cấp chức năng giống nhau (nhận báo giá) nhưng có thể quy định định dạng khác nhau cho các thông điệp SOAP liên quan. Do đó, môi giới cho vay phải chuyển đổi thông điệp yêu cầu báo giá sang định dạng yêu cầu của mỗi ngân hàng trước khi tiến hành truy vấn ngân hàng.
Người môi giới khoản vay liên hệ trực tiếp với từng ngân hàng bằng cách sử dụng định tuyến dự đoán; tức là, danh sách các ngân hàng tham gia vào việc thu thập báo giá được biết ngay trước khi họ được gọi để báo giá. Trong giai đoạn này, ứng dụng môi giới khoản vay gửi yêu cầu đến các ngân hàng đã được chọn bằng cách sử dụng mẫu Danh sách Người Nhận. Bởi vì mỗi ngân hàng có thể sử dụng định dạng khác nhau cho yêu cầu, người môi giới khoản vay cần sử dụng một mảng các Bộ chuyển đổi Tin nhắn để chuyển đổi yêu cầu thành định dạng mà mỗi ngân hàng yêu cầu.
Tương tự, mỗi tin nhắn phản hồi cần được chuyển đổi sang định dạng chung bằng cách sử dụng một Bộ chuẩn hóa, để tất cả các phản hồi có thể được tổng hợp thành báo giá tốt nhất duy nhất. Các tin nhắn yêu cầu và phản hồi được truyền đồng bộ; tức là, khách hàng và nhà môi giới cho vay bị chặn cho đến khi mỗi ngân hàng phản hồi hoặc hết thời gian chờ. Nhà môi giới cho vay tổng hợp tất cả các phản hồi thành báo giá tốt nhất và gửi phản hồi báo giá tốt nhất trở lại cho khách hàng.
Gửi tin nhắn đồng bộ rất hữu ích trong một số lĩnh vực vấn đề nơi mà một giải pháp đơn giản là cần thiết. Bằng cách sử dụng gửi tin nhắn đồng bộ, chúng ta không phải lo lắng về việc xử lý các sự kiện không đồng bộ, an toàn luồng, hoặc hạ tầng cần thiết để hỗ trợ chúng. Khách hàng gọi dịch vụ Web của môi giới cho vay và sau đó chờ đợi phản hồi từ máy chủ. Có nhiều thành phần trong giải pháp này, và mỗi thành phần thực hiện một cuộc gọi đồng bộ tới thành phần tiếp theo và chờ đợi phản hồi.
Các dịch vụ Web XML dựa trên Giao thức Truy cập Đối tượng Đơn giản (SOAP). Đặc tả SOAP đã được gửi đến W3C và định nghĩa một giao thức dựa trên XML nhằm mục đích trao đổi thông điệp giữa các hệ thống phi tập trung và phân tán. Để biết thêm chi tiết về SOAP, xin vui lòng tham khảo các tài liệu tại trang web của Tổ chức W3 (www.w3.org/TR/SOAP).
Thật không may, chữ S trong SOAP không còn hợp lệ nữa. Chúng tôi đã đùa rằng SOAP nên được đổi tên thành Giao thức Truy cập Từ xa Phức tạp - bạn hãy tìm ra từ viết tắt. Nghiêm túc mà nói, thiết kế một giao diện dịch vụ web vững chắc yêu cầu chúng ta phải đi sâu vào một số thuật ngữ và những cân nhắc thiết kế liên quan. Trong khi cuốn sách này không phải là một sự giới thiệu về dịch vụ web, chúng tôi cảm thấy quan trọng để thảo luận ngắn gọn về những cân nhắc thiết kế sau đây:
Giao thức vận chuyển
Thông điệp không đồng bộ so với thông điệp đồng bộ
Phong cách mã hóa (mã hóa SOAP so với tài liệu/literal)
Phong cách liên kết (RPC so với phong cách tài liệu)
Độ tin cậy và an ninh
Đặc tả SOAP được tạo ra để cho phép các ứng dụng thực hiện các cuộc gọi RPC đồng bộ tới một dịch vụ qua mạng theo cách không phụ thuộc vào công nghệ. Đặc tả SOAP thực sự định nghĩa một thông điệp yêu cầu và phản hồi riêng biệt cho mỗi lệnh gọi tới dịch vụ Web (như được định nghĩa trong tài liệu WSDL mô tả dịch vụ). Mặc dù SOAP được phát triển với tâm trí nhắn tin, đa số các ứng dụng dịch vụ Web sử dụng HTTP làm giao thức truyền tải. HTTP là một lựa chọn tự nhiên vì nó là giao thức được sử dụng phổ biến nhất trên Web và có thể xuyên qua các tường lửa. Tuy nhiên, HTTP là Giao thức Truyền Tải Siêu Văn bản được thiết kế để cho phép người dùng với các trình duyệt Web lấy tài liệu qua Internet, không phải để các ứng dụng giao tiếp với nhau. HTTP vốn không đáng tin cậy và được thiết kế cho việc lấy tài liệu đồng bộ - ứng dụng máy khách sử dụng cùng một kết nối để gửi yêu cầu tới máy chủ và nhận phản hồi. Do đó, các dịch vụ Web sử dụng HTTP sẽ không tránh khỏi việc sử dụng nhắn tin yêu cầu/ phản hồi đồng bộ vì nhắn tin không đồng bộ qua một kênh không đáng tin cậy gần như vô dụng như việc thả một chai xuống đại dương.
Trong việc triển khai đồng bộ của một dịch vụ Web, kết nối của khách hàng sẽ duy trì mở từ thời điểm yêu cầu được gửi đến máy chủ. Khách hàng sẽ chờ đợi cho đến khi máy chủ gửi lại thông điệp phản hồi. Ưu điểm của việc sử dụng giao tiếp RPC đồng bộ là ứng dụng khách hàng biết trạng thái của hoạt động dịch vụ Web trong một khoảng thời gian rất ngắn (hoặc nhận được phản hồi hoặc hết thời gian chờ). Một hạn chế nghiêm trọng của việc sử dụng nhắn tin đồng bộ là máy chủ có thể phải xử lý một số lượng lớn kết nối đồng thời vì mỗi khách hàng đồng thời duy trì một kết nối mở trong khi chờ đợi kết quả. Điều này khiến ứng dụng máy chủ trở nên ngày càng phức tạp. Nếu một trong những lần gọi đến một nhà cung cấp dịch vụ đồng bộ thất bại, ứng dụng máy chủ phải cung cấp cơ chế để bắt lỗi và phục hồi, chuyển hướng xử lý hoặc đánh dấu lỗi trước khi tiếp tục với các lần gọi đồng bộ khác.
Hiện tại, hầu hết các bộ công cụ dịch vụ Web chỉ hỗ trợ việc nhắn tin đồng bộ theo mặc định. Tuy nhiên, bằng cách sử dụng các tiêu chuẩn và công cụ hiện có như các khung hàng đợi tin nhắn không đồng bộ, một số nhà cung cấp đã bắt chước việc nhắn tin không đồng bộ cho các dịch vụ Web. Nhiều tổ chức, công ty và các nhóm làm việc về dịch vụ Web đã nhận ra nhu cầu hỗ trợ nhắn tin không đồng bộ và đang tiến tới việc định nghĩa các tiêu chuẩn (ví dụ: WS-ReliableMessaging). Để biết thông tin mới nhất về các tiêu chuẩn dịch vụ Web, vui lòng tham khảo trang web của Tổ chức W3 tại http://www.w3.org/ và xem Chương 14, "Những nhận xét kết luận."
Khái niệm mã hóa SOAP đã dẫn đến một lượng lớn tranh luận và nhầm lẫn. Đặc tả SOAP định nghĩa một chế độ gọi là kiểu mã hóa được chỉ định bởi thuộc tính encodingStyle. Chế độ này có thể nhận hai giá trị: mã hóa (bằng cách đặt giá trị thuộc tính thành http://schemas.xmlsoap.org/soap/encoding/) và văn bản (bằng cách chỉ định giá trị thuộc tính khác hoặc không có giá trị nào). Chế độ này xác định cách các đối tượng và tham số ứng dụng được đại diện trong XML "trên đường truyền". Mã hóa (còn được gọi là mã hóa SOAP) đề cập đến Phần 5 của đặc tả SOAP, định nghĩa một cơ chế nguyên thủy để ánh xạ các loại ngôn ngữ lập trình sang XML. Văn bản (còn được gọi là doc/literal) có nghĩa là không làm điều đó. Thay vào đó, thông tin loại được cung cấp bởi một cơ chế bên ngoài, nhiều khả năng là một tài liệu WSDL (Ngôn ngữ Mô tả Dịch vụ Web) sử dụng sơ đồ XML để định nghĩa chính xác các loại nào được sử dụng trong thông điệp SOAP.
Điều này xảy ra vì đặc tả SOAP được viết trước khi chấp nhận đặc tả W3C XML Schema Definition (XSD). Do đó, đặc tả SOAP ban đầu phải cung cấp một cách để mã hóa thông tin kiểu cùng với các tham số được gửi cho các cuộc gọi phương thức vì không có cách nào được chấp nhận để chỉ định điều đó. Nơi điều này thực sự phát huy tác dụng là với các kiểu dữ liệu phức tạp như Mảng. Phần 5.4.2 của đặc tả SOAP định nghĩa một cơ chế cụ thể để đại diện cho mảng ngôn ngữ lập trình trong XML sử dụng một loại sơ đồ đặc biệt SOAPEnc:Array.
Tuy nhiên, kể từ khi áp dụng kiến trúc XML schema (xem http://www.w3.org/TR/xmlschema-0/), hầu hết các ngôn ngữ đã làm cho việc cần thiết cho việc mã hóa SOAP trở nên lỗi thời bằng cách xác định các ánh xạ (hoặc quy tắc tuần tự hóa) riêng của chúng từ XML schema đến các loại ngôn ngữ lập trình. Ví dụ, đặc tả JAX-RPC xác định một cách độc nhất cách mà các kiểu Java được ánh xạ đến các phần tử trong XML schema, và ngược lại. Điều này loại bỏ sự cần thiết của thông tin mã hóa thêm trong XML. Do đó, mã hóa SOAP không còn được ưa chuộng và đã bị thay thế bởi mã hóa theo hình thức với các ánh xạ được xác định bên ngoài bởi một tài liệu XML schema, thường ở dạng tài liệu WSDL.
Bản đặc tả WSDL chỉ định hai kiểu ràng buộc khác nhau trong ràng buộc SOAP của nó. Các giá trị của thuộc tính kiểu ràng buộc là RPC và Tài liệu. Điều này có nghĩa là nếu một tài liệu WSDL chỉ định một thao tác có thuộc tính kiểu ràng buộc được đặt thành RPC, thì người nhận phải giải thích tin nhắn đó theo các quy tắc được tìm thấy trong Mục 7 của đặc tả SOAP. Điều này có nghĩa, ví dụ, rằng phần tử XML bên trong thân SOAP (gọi là phần tử bọc) phải có tên giống hệt với tên của thao tác ngôn ngữ lập trình tương ứng mà sẽ được gọi, rằng mỗi phần của tin nhắn bên trong phần tử đó phải tương ứng chính xác (về tên và thứ tự) với một tham số của thao tác ngôn ngữ lập trình đó, và rằng phải chỉ có một phần tử duy nhất được trả về (phần tử này phải được đặt tên là XXXResponse, trong đó XXX là tên của thao tác tương ứng trong ngôn ngữ) mà bên trong nó chứa chính xác một phần tử, đó là giá trị trả về của thao tác.
Phong cách ràng buộc Tài liệu (Document binding style) lỏng lẻo hơn nhiều. Một thông điệp trong phong cách ràng buộc Tài liệu chỉ cần được tạo thành từ XML hợp lệ. Cách mà SOAP engine nhận được thông điệp này sẽ được giải thích như thế nào là tùy thuộc vào nó. Nói như vậy, nhiều công cụ (như của Microsoft) thường sử dụng phong cách ràng buộc Tài liệu và mã hóa Literal để thể hiện ngữ nghĩa RPC. Dù phong cách Tài liệu được sử dụng, thông điệp được gửi đại diện cho một Thông điệp Lệnh (Command Message), với thao tác cần được gọi và các tham số cần được truyền được mã hóa trong Tài liệu.
Trong Chương 14, "Những Nhận Xét Kết Thúc," Sean Neville mô tả những tiêu chuẩn đang phát triển nhằm giải quyết các vấn đề về độ tin cậy và an ninh cho các dịch vụ Web.
Giải pháp của chúng tôi sử dụng sự kết hợp cơ bản nhất và có lẽ vẫn là phổ biến nhất trong những lựa chọn thiết kế này. Triển khai môi giới cho vay sử dụng SOAP qua HTTP với giao tiếp đồng bộ, mã hóa thông điệp bằng kiểu mã hóa SOAP mặc định và liên kết RPC. Điều này khiến dịch vụ Web hoạt động rất giống như một Lời gọi Thủ tục Từ xa. Chúng tôi đã đi theo con đường này để không bị mắc kẹt trong việc tranh luận về các chi tiết nội bộ của dịch vụ Web (thực ra, không nhiều hơn những gì chúng tôi đã làm), mà có thể tập trung vào việc so sánh triển khai dịch vụ Web đồng bộ với các triển khai khác.
Phần này cung cấp mô tả ngắn gọn về kiến trúc Axis để giúp làm sáng tỏ những điểm quan trọng trong thiết kế của chúng tôi. Để biết thêm chi tiết về Axis, vui lòng tham khảo trang web Apache Axis tại http://ws.apache.org/axis.
Chương 3, "Hệ Thống Nhắn Tin," định nghĩa một Điểm Kết Nối Tin Nhắn là cơ chế mà một ứng dụng sử dụng để kết nối với một kênh nhắn tin nhằm gửi và nhận tin nhắn. Trong ứng dụng môi giới khoản vay của chúng tôi, chính khung công tác Axis đại diện cho kênh nhắn tin, và chức năng chính của nó là xử lý các tin nhắn thay mặt cho ứng dụng người dùng.
Máy chủ Axis triển khai mẫu Kích hoạt Dịch vụ. Chương 10, "Điểm cuối Giao tiếp," mô tả cách mà một Kích hoạt Dịch vụ kết nối một Kênh Tin nhắn với một dịch vụ đồng bộ trong một ứng dụng, để khi một tin nhắn được nhận, dịch vụ sẽ được gọi.
Trình Kích Hoạt Dịch Vụ được triển khai trong máy chủ Axis để nhà phát triển không cần phải bận tâm đến chức năng này. Do đó, mã ứng dụng chỉ chứa logic kinh doanh cho ứng dụng, và máy chủ Axis sẽ đảm nhận tất cả các dịch vụ xử lý tin nhắn.
Mô hình lập trình khách hàng của Axis cung cấp các thành phần cho ứng dụng khách hàng để gọi đến một URL điểm cuối và sau đó nhận tin nhắn phản hồi từ máy chủ. Khách hàng môi giới cho vay trong ứng dụng này là một khách hàng đồng bộ sử dụng mô hình lập trình khách hàng của Axis. Trong máy chủ có một bộ lắng nghe cho mỗi giao thức truyền tải được hỗ trợ bởi máy chủ. Khi khách hàng gửi một tin nhắn đến điểm cuối, một bộ lắng nghe truyền tải trong khung Axis tạo ra một đối tượng ngữ cảnh tin nhắn và truyền nó qua một chuỗi yêu cầu trong khung. Ngữ cảnh tin nhắn chứa tin nhắn thực tế nhận được từ khách hàng cùng với các thuộc tính liên quan được thêm bởi khách hàng truyền tải.
Khung kệ trục được cấu thành từ một loạt các Xử lý viên, được gọi theo một thứ tự nhất định tùy thuộc vào cấu hình triển khai và liệu khách hàng hay máy chủ đang gọi khung kệ. Các Xử lý viên là một phần của hệ thống phụ Lưu lượng Tin nhắn và được nhóm lại với nhau và gọi là Chuỗi. Các tin nhắn yêu cầu được xử lý bởi một chuỗi các Xử lý viên yêu cầu trong một Chuỗi. Bất kỳ tin nhắn phản hồi nào đều được gửi trở lại qua Chuỗi phản hồi tương ứng thông qua một chuỗi các Xử lý viên phản hồi.

Hình trên cho thấy một biểu diễn tổng quan về nội bộ của khung Axis. Một cuộc thảo luận chi tiết về kiến trúc của Axis có thể được tìm thấy tại http://ws.apache.org/axis.
Trục bao gồm nhiều hệ thống con hoạt động cùng nhau để cung cấp chức năng của một Kênh Tin nhắn. Khung này có sẵn để cả ứng dụng khách và máy chủ sử dụng.
Các hệ thống con của Trục liên quan đến ví dụ của chúng ta như sau:
Mô hình thông điệp định nghĩa cú pháp XML của các thông điệp SOAP.
Hệ thống con Luồng Tin nhắn định nghĩa Các Bộ xử lý và Các Chuỗi để truyền các tin nhắn.
Hệ thống con dịch vụ xác định trình xử lý dịch vụ (SOAP, XML-RPC).
Hệ thống vận chuyển cung cấp các lựa chọn thay thế cho việc vận chuyển tin nhắn (ví dụ: HTTP, JMS, SMTP).
Hệ thống phụ cung cấp xác định các nhà cung cấp cho các loại lớp khác nhau (ví dụ: java:RPC, EJB, MDB).
Như đã đề cập trước đó, nhà phát triển chỉ cần tập trung vào việc tạo ra một ứng dụng thực hiện logic kinh doanh, sau đó có thể triển khai trên máy chủ Axis. Có ba kỹ thuật để triển khai một lớp Java như một dịch vụ Web và làm cho nó có sẵn như một dịch vụ điểm kết; chúng tôi đã đặt tên cho chúng như sau:
Triển khai tự động
Sử dụng mô tả triển khai dịch vụ web
Tạo proxy từ tài liệu WSDL hiện có
Cách đầu tiên và đơn giản nhất là viết lớp chứa logic kinh doanh dưới dạng tệp Java Web Service (JWS) (đây là một tệp nguồn Java với phần mở rộng *.jws). Các phương thức của lớp này chứa logic kinh doanh. Tệp JWS không cần phải được biên dịch và có thể được triển khai ngay lập tức bằng cách sao chép tệp nguồn vào thư mục webapps trên máy chủ. Mỗi phương thức công khai giờ đây có thể truy cập được như một dịch vụ Web. Tên của tệp JWS này tạo thành một phần của điểm cuối mà máy chủ Axis cung cấp như một dịch vụ Web, như được trình bày trong URL sau:
http://hostname:portnumber/axis/LoanBroker.jws
Axis 1.1 tự động tạo ra tài liệu WSDL từ các dịch vụ đã được triển khai trong máy chủ. WSDL là định dạng XML mô tả giao diện công cộng của một dịch vụ Web (tức là, các phương thức có sẵn thông qua giao diện) cũng như vị trí của dịch vụ (tức là, URL). Việc tự động tạo ra WSDL cho phép các ứng dụng khác kiểm tra giao diện từ xa mà lớp dịch vụ Web cung cấp. Nó cũng có thể được sử dụng để tự động tạo ra các lớp stub khách hàng mà bao bọc lời gọi dịch vụ Web bên trong một lớp Java thông thường. Nhược điểm của phương pháp này là nhà phát triển không thể kiểm soát các tham số triển khai.
Kỹ thuật thứ hai triển khai một lớp đã biên dịch sử dụng WSDD (Descriptor Triển khai Dịch vụ Web), cho phép nhà phát triển kiểm soát các tham số triển khai, chẳng hạn như phạm vi lớp. Theo mặc định, một lớp được triển khai trong phạm vi yêu cầu; tức là, một thể hiện mới của lớp sẽ được khởi tạo cho mỗi yêu cầu được nhận. Khi quá trình xử lý hoàn tất, thể hiện đó sẽ bị hủy. Nếu lớp cần tồn tại trong suốt phiên làm việc để phục vụ nhiều yêu cầu từ cùng một khách hàng trong một khoảng thời gian, chúng ta cần định nghĩa lớp trong phạm vi phiên. Đối với một số ứng dụng, chúng ta cần tất cả khách hàng truy cập vào một lớp singleton; tức là, lớp phải được khởi tạo và có sẵn trong suốt thời gian ứng dụng hoạt động, và do đó, dịch vụ Web được định nghĩa trong phạm vi ứng dụng.
Kỹ thuật cuối cùng phức tạp hơn hai kỹ thuật trước nhưng cho phép tạo ra các proxy và khung từ một tài liệu WSDL hiện có (sử dụng công cụ wsdl2java). Các proxy và khung bao encapsulate tất cả mã liên quan đến SOAP để nhà phát triển không phải viết bất kỳ mã nào liên quan đến SOAP (hoặc liên quan đến Axis), mà có thể chèn logic kinh doanh ngay vào các thân phương thức của khung được tạo ra.
Chúng tôi đã chọn triển khai tất cả các dịch vụ Web của mình bằng cách sử dụng kỹ thuật Triển khai Tự động, sử dụng các tệp JWS, nhằm giữ cho các yêu cầu thiết kế và triển khai đơn giản nhất có thể. Ở phía khách hàng, việc mã hóa tay cuộc gọi tới dịch vụ Web dễ hơn rất nhiều. Chúng tôi có thể đã sử dụng công cụ wsdl2java để tạo ra các stub, sau đó sẽ được gọi bởi mã của khách hàng; tuy nhiên, chúng tôi đã cố gắng giảm thiểu lượng mã được tạo ra vì điều này có thể khiến việc đi qua một giải pháp ví dụ trở nên khó khăn.
Trước khi chúng ta tiến hành thảo luận về ứng dụng môi giới cho vay, chúng ta cần mô tả một vài bước chung mà chúng tôi tuân theo khi triển khai giải pháp để giúp tạo ra một ứng dụng dễ triển khai. Để gọi một dịch vụ Web được triển khai trên một máy chủ, bất kỳ ứng dụng khách nào cũng cần biết URL điểm cuối. Trong mô hình dịch vụ Web, một ứng dụng tìm kiếm vị trí của một dịch vụ Web mà nó muốn truy cập từ một registry dịch vụ chung.
UDDI (Mô tả, Khám phá và Tích hợp Toàn cầu) là một chuẩn cho kho lưu trữ như vậy. Cuộc thảo luận về UDDI nằm ngoài phạm vi của phần này; bạn có thể tìm thêm thông tin tại http://www.uddi.org. Trong ví dụ của chúng tôi, chúng tôi đã mã cứng các URL điểm cuối trong chính ứng dụng. Tuy nhiên, để dễ dàng triển khai mã ví dụ, chúng tôi tạo các tệp thuộc tính cho cả ứng dụng máy chủ và máy khách. Tệp thuộc tính có các cặp tên-giá trị cho tham số tên máy chủ và số cổng, khớp với các tham số của cài đặt máy chủ Axis của bạn. Điều này mang lại cho bạn một số linh hoạt trong việc triển khai ứng dụng môi giới cho vay trong môi trường của bạn. Chúng tôi cung cấp một phương thức tiện ích, readProps(), trong một số lớp Java. Phương thức này dùng để đọc các tệp chứa các tham số triển khai của máy chủ Axis. Phương thức readProps() không được bất kỳ khía cạnh chức năng nào của ứng dụng môi giới cho vay sử dụng.
Trong bất kỳ khuôn khổ tính toán phân tán nào, cho dù đó là Java RMI, CORBA hay dịch vụ Web SOAP, chúng ta cần định nghĩa các tham số của các cuộc gọi phương thức trên các đối tượng từ xa dưới dạng kiểu dữ liệu nguyên thủy hoặc các đối tượng có thể được tuần tự hóa để truyền qua mạng. Những tham số này là các thuộc tính của các đối tượng tin nhắn được gửi từ phía khách hàng đến máy chủ. Để giữ cho giải pháp môi giới cho vay đơn giản, chúng ta sử dụng một đối tượng String trong Java để trả về phản hồi từ môi giới cho vay đến phía khách hàng. Nếu các tham số được gọi là kiểu dữ liệu nguyên thủy (ví dụ: int, double, v.v.), chúng phải được bọc trong các đối tượng bọc định nghĩa trước gọi là bọc kiểu (ví dụ: Integer, Double, v.v.).
Hình bên dưới cho thấy sơ đồ lớp của thành phần môi giới cho vay. Logic kinh doanh cốt lõi của môi giới cho vay được đóng gói bên trong lớp LoanBrokerWS. Lớp này kế thừa từ một lớp được cung cấp bởi framework Axis, đã triển khai một Service Activator để gọi một phương thức trong lớp LoanBrokerWS khi một yêu cầu SOAP đến. LoanBrokerWS tham chiếu đến một tập hợp các lớp gateway thực hiện chi tiết việc giao tiếp với các thực thể bên ngoài, chẳng hạn như cơ quan tín dụng và các ngân hàng. Logic này được đóng gói bên trong các lớp CreditAgencyGateway, LenderGateway và BankQuoteGateway.
Biểu đồ lớp môi giới cho vay

Giao diện dịch vụ duy nhất từ môi giới cho vay đến thế giới bên ngoài là điểm cuối tin nhắn để khách hàng truy cập dịch vụ môi giới cho vay. Không cần thiết phải định nghĩa một Cổng thông tin Nhắn, vì khung Axis hoạt động như một cổng thay mặt cho ứng dụng.
Sơ đồ tuần tự sau đây minh họa sự tương tác giữa các thành phần trong ví dụ dịch vụ Web dự đoán đồng bộ. Người môi giới cho vay đầu tiên gọi đến thành phần cổng thông tin của cơ quan tín dụng, mà làm phong phú dữ liệu tối thiểu được cung cấp bằng cách bổ sung điểm tín dụng và thời gian lịch sử tín dụng của khách hàng. Người môi giới cho vay sử dụng dữ liệu đã được làm phong phú để gọi đến cổng thông tin của nhà cho vay. Thành phần này thực hiện Danh sách Người Nhận, sử dụng tất cả dữ liệu được cung cấp để chọn bộ các nhà cho vay có thể phục vụ yêu cầu vay.
Người môi giới cho vay sau đó gọi đến cổng thông tin ngân hàng. Thành phần này thực hiện thao tác định tuyến dự đoán bằng cách gọi từng ngân hàng một. Các thành phần ngân hàng mô hình hóa giao diện cho một hoạt động ngân hàng thực tế. Ví dụ, lớp Bank1 là giao diện cho dịch vụ Web Bank1WS.jws mô hình hóa hoạt động ngân hàng. Khi có một yêu cầu vay vốn đến, sẽ có một số công việc giấy tờ được thực hiện trước khi tạo ra báo giá lãi suất dựa trên tất cả các tham số. Trong ví dụ này, báo giá lãi suất được tạo ra bởi một dịch vụ Web ngân hàng "giả" .
Cổng thông tin ngân hàng tổng hợp các phản hồi từ các ngân hàng và lựa chọn báo giá tốt nhất từ tất cả các báo giá đã nhận. Phản hồi được gửi trở lại cho người môi giới vay, người sẽ định dạng dữ liệu từ báo giá tốt nhất và trả lại báo cáo cho khách hàng.
Biểu đồ tuần tự trung gian cho vay

Chúng tôi chỉ hiển thị hai trong số năm ngân hàng trong sơ đồ tuần tự để giữ cho hình ảnh dễ quản lý. Dựa trên danh sách người nhận được tạo ra cho một yêu cầu cụ thể, người môi giới cho vay có thể liên lạc với đúng một ngân hàng hoặc tất cả năm ngân hàng để phục vụ yêu cầu của khách hàng.
Biểu đồ làm nổi bật quá trình xử lý tuần tự các yêu cầu báo giá đến từng ngân hàng. Việc xử lý tuần tự có một số lợi thế vì chúng ta có thể chạy ứng dụng trong một luồng đơn, gọi từng ngân hàng theo thứ tự. Ứng dụng không cần phải tạo ra các luồng để yêu cầu báo giá từ mỗi ngân hàng, vì vậy chúng ta không phải lo lắng về các vấn đề đồng thời. Tuy nhiên, thời gian tổng để nhận báo giá phản hồi là cao, vì nhà môi giới cho vay phải chờ phản hồi từ mỗi ngân hàng trước khi gửi yêu cầu đến ngân hàng tiếp theo trong danh sách người cho vay. Kết quả cuối cùng là khách hàng sẽ phải chờ một thời gian dài để nhận lại báo giá sau khi gửi yêu cầu.
Chúng tôi bắt đầu thiết kế các khía cạnh chức năng của ứng dụng môi giới cho vay. Như đã đề cập trước đó, khung Axis có thể hỗ trợ cả ứng dụng khách và máy chủ. Điều này cho phép một khách hàng từ xa truy cập vào điểm cuối được công bố qua mạng. Một ứng dụng máy chủ cũng có thể cần hoạt động như một khách hàng và truy cập vào một điểm cuối dịch vụ Web khác, bất kể điểm cuối đó nằm trên cùng một máy chủ hay một máy chủ từ xa. Chúng tôi minh họa điều này bằng cách mô hình hóa các thành phần chính của giải pháp của chúng tôi dưới dạng dịch vụ Web, mặc dù đang chạy trên cùng một phiên bản của máy chủ của chúng tôi.
Giải pháp môi giới cho vay phải thực hiện các chức năng sau:
Chấp nhận yêu cầu của khách hàng
Lấy dữ liệu từ cơ quan tín dụng
Triển khai Dịch vụ Cơ quan Tín dụng
Nhận báo giá
Triển khai các hoạt động ngân hàng
Nhà môi giới cho vay được thực hiện trong một tệp JWS có tên là LoanBrokerWS.jws. Nó cung cấp một phương thức công khai duy nhất dưới dạng dịch vụ web: GetLoanQuote. Nhà môi giới cho vay cần ba thông tin từ khách hàng để bắt đầu xử lý yêu cầu vay: số an sinh xã hội (SSN) đóng vai trò là số định danh khách hàng, số tiền vay và thời gian vay tính bằng tháng.
public String getLoanQuote(int ssn, double loanamount, int loanduration) { String results = ""; results = results + "Client with ssn= " + ssn + " requests a loan of amount= " + loanamount + " for " + loanduration + " months" + "\n\n"; results = results + this.getLoanQuotesWithScores(ssn,loanamount,loanduration); return results; } Bước duy nhất trong phương pháp này là gọi đến phương thức getLoanQuotesWithScores. Phương thức này trả về một chuỗi, được gửi lại cho khách hàng qua một chuỗi phản hồi trong khuôn khổ Axis. Ở cuối chuỗi, bộ lắng nghe vận chuyển nhận yêu cầu chấp nhận thông điệp phản hồi từ bên trong khuôn khổ Axis và gửi lại cho khách hàng qua mạng.
Như đã mô tả trước đó, vì chúng tôi sử dụng việc Triển khai Tự động của tệp JWS cho thành phần môi giới cho vay, Axis sẽ tạo ra tệp WSDL cho dịch vụ LoanBrokerWS. Tệp WSDL cho tệp LoanBrokerWS.jws sẽ được hiển thị tiếp theo.
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:message name="getLoanQuoteRequest"> <wsdl:part name="ssn" type="xsd:int"/> <wsdl:part name="loanamount" type="xsd:double"/> <wsdl:part name="loanduration" type="xsd:int"/> </wsdl:message> <wsdl:message name="getLoanQuoteResponse"> <wsdl:part name="getLoanQuoteReturn" type="xsd:string"/> </wsdl:message> <wsdl:portType name="LoanBrokerWS"> <wsdl:operation name="getLoanQuote" parameterOrder="ssn loanamount loanduration"> <wsdl:input message="intf:getLoanQuoteRequest" name="getLoanQuoteRequest"/> <wsdl:output message="intf:getLoanQuoteResponse" name="getLoanQuoteResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="LoanBrokerWSSoapBinding" type="intf:LoanBrokerWS"> <wsdlsoap:binding transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getLoanQuote"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getLoanQuoteRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="..." use="encoded"/> </wsdl:input> <wsdl:output name="getLoanQuoteResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="..." use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="LoanBrokerWSService"> <wsdl:port binding="intf:LoanBrokerWSSoapBinding" name="LoanBrokerWS"> <wsdlsoap:address location="http://192.168.1.25:8080/axis/LoanBrokerWS.jws"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
Vì lợi ích của không gian, chúng tôi đã tóm gọn tài liệu WSDL để làm nổi bật các phần tử quan trọng nhất. Phần tử <wsdl:service> ở cuối tài liệu định nghĩa tên dịch vụ (LoanBrokerWSService) và vị trí điểm cuối. Phần tử <wsdl:operation> định nghĩa tên phương thức (hoạt động) cùng với các tham số cần thiết để khách hàng truy cập dịch vụ Web LoanBrokerWS. Hai thông điệp được định nghĩa trong các thẻ <wsdl:message> xác định các thông điệp yêu cầu và phản hồi cho hoạt động getLoanQuote: getLoanQuoteRequest và getLoanQuoteResponse với các tham số thích hợp mà chúng gửi hoặc nhận từ dịch vụ Web. Phần tử <wsdlsoap:binding> xác nhận rằng chúng tôi đang sử dụng kiểu liên kết RPC mà chúng tôi đã thảo luận ở đầu chương này, trong khi <wsdlsoap:body> tiết lộ rằng chúng tôi đang sử dụng mã hóa SOAP (trái ngược với doc/literal).
Nếu bạn muốn xem tệp WSDL từ máy chủ của bạn, bạn có thể nhập URL sau vào cửa sổ trình duyệt của mình, trong đó tên máy chủ và số cổng được thay thế bằng các giá trị thích hợp của cài đặt máy chủ của bạn:
http://hostname:portnumber/axis/LoanBrokerWS.jws?wsdl
Một yêu cầu khác đối với nhà môi giới vay là thu thập thêm dữ liệu về khách hàng để hoàn thiện đơn xin vay. Giai đoạn tiếp theo của LoanBrokerWS triển khai Content Enricher, như trình bày dưới đây.
private String getLoanQuotesWithScores (int de_ssn, double de_loanamount, int de_duration) { String qws_results = "Additional data for customer: credit score and length of credit history\n"; int ssn = de_ssn; double loanamount = de_loanamount; int loanduration = de_duration; int credit_score = 0; int credit_history_length = 0; CreditProfile creditprofile = CreditAgencyGateway.getCustomerCreditProfile(ssn); credit_score = creditprofile.getCreditScore(); credit_history_length = creditprofile.getCreditHistoryLength(); qws_results = qws_results + "Credit Score= " + credit_score + " Credit History Length= " + credit_history_length; qws_results = qws_results + "\n\n"; qws_results = qws_results + "The details of the best quote from all banks that responded are shown below: \n\n"; qws_results = qws_results + getResultsFromLoanClearingHouse (ssn,loanamount,loanduration,credit_history_length,credit_score); qws_results = qws_results + "\n\n"; return qws_results; } Chúng tôi hiện đang thiết kế hoạt động của cơ quan tín dụng, đó là lĩnh vực hợp lý tiếp theo của ứng dụng trung gian cho vay. Để giữ mã SOAP ra khỏi ứng dụng trung gian cho vay và giảm thiểu sự phụ thuộc giữa trung gian cho vay và cơ quan tín dụng, chúng tôi sử dụng mẫu Cổng (Gateway pattern) [EAA], điều này mang lại hai lợi thế chính: Thứ nhất, nó trừu tượng hóa các chi tiết kỹ thuật của giao tiếp ra khỏi ứng dụng. Thứ hai, nếu chúng tôi chọn tách biệt interface cổng khỏi việc triển khai cổng, chúng tôi có thể thay thế dịch vụ bên ngoài thực tế bằng một Stub Dịch vụ [EAA] để thử nghiệm.
Cổng thông tin Cơ quan Tín dụng của chúng tôi tóm tắt các chi tiết kỹ thuật của việc liên lạc giữa Cổng thông tin Cơ quan Tín dụng và dịch vụ Web của cơ quan tín dụng (CreditAgencyWS). Chúng tôi có thể thay thế dịch vụ Web bằng một mô-đun thử nghiệm nếu cần. Cổng thông tin nhận số định danh khách hàng (SSN) và thu thập dữ liệu bổ sung từ cơ quan tín dụng. Hai thông tin được trả lại bởi cơ quan tín dụng là điểm tín dụng và thời gian lịch sử tín dụng của khách hàng, cả hai đều cần thiết để hoàn thành đơn xin vay. Cổng thông tin này chứa toàn bộ mã phía khách hàng để truy cập vào CreditAgencyWS được triển khai trong tệp CreditAgencyWS.jws.
public static CreditProfile getCustomerCreditProfile(int ssn){ int credit_score = 0; int credit_history_length = 0; CreditProfile creditprofile = null; try{ CreditAgencyGateway.readProps(); creditprofile = new CreditProfile(); String creditagency_ep = "http://" + hostname + ":" + portnum + "/axis/CreditAgencyWS.jws"; Integer i1 = new Integer(ssn); Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(creditagency_ep) ); call.setOperationName("getCreditHistoryLength"); call.addParameter( "op1", XMLType.XSD_INT, ParameterMode.IN ); call.setReturnType( XMLType.XSD_INT ); Integer ret1 = (Integer) call.invoke( new Object [] {i1}); credit_history_length = ret1.intValue(); call.setOperationName("getCreditScore"); Integer ret2 = (Integer) call.invoke( new Object [] {i1}); credit_score = ret2.intValue(); creditprofile.setCreditScore(credit_score); creditprofile.setCreditHistoryLength(credit_history_length); Thread.sleep(credit_score); }catch(Exception ex){ System.out.println("Error accessing the CreditAgency Webservice"); } return creditprofile; } } Mục đích của việc sử dụng Cổng này là để cho thấy cách mà một ứng dụng máy chủ sử dụng framework khách Axis để truy cập một dịch vụ Web khác, hoặc trên cùng một máy chủ hoặc trên một máy chủ từ xa.
Dịch vụ web của tổ chức tín dụng được mã hóa trong CreditAgencyWS.jws, như được trình bày bên dưới. Hai thông tin quan trọng cần thiết để hoàn thành đơn xin vay là điểm tín dụng của khách hàng và thời gian lịch sử tín dụng của khách hàng. Tổ chức tín dụng có dữ liệu này cho mỗi khách hàng có lịch sử tín dụng, và nó có thể được truy cập bằng số nhận dạng khách hàng.
public int getCreditScore(int de_ssn) throws Exception { int credit_score; credit_score = (int)(Math.random()*600+300); return credit_score; } public int getCreditHistoryLength(int de_ssn) throws Exception { int credit_history_length; credit_history_length = (int)(Math.random()*19+1); return credit_history_length; } Mã sau đây hiển thị tệp WSDL cho tệp CreditAgencyWS.jws. Tệp này được tự động sinh ra bởi máy chủ Axis.
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"> <wsdl:message name="getCreditScoreResponse"> <wsdl:part name="getCreditScoreReturn" type="xsd:int"/> </wsdl:message> <wsdl:message name="getCreditHistoryLengthRequest"> <wsdl:part name="de_ssn" type="xsd:int"/> </wsdl:message> <wsdl:message name="getCreditScoreRequest"> <wsdl:part name="de_ssn" type="xsd:int"/> </wsdl:message> <wsdl:message name="getCreditHistoryLengthResponse"> <wsdl:part name="getCreditHistoryLengthReturn" type="xsd:int"/> </wsdl:message> <wsdl:portType name="CreditAgencyWS"> <wsdl:operation name="getCreditHistoryLength" parameterOrder="de_ssn"> <wsdl:input message="intf:getCreditHistoryLengthRequest" name="getCreditHistoryLengthRequest"/> <wsdl:output message="intf:getCreditHistoryLengthResponse" name="getCreditHistoryLengthResponse"/> </wsdl:operation> <wsdl:operation name="getCreditScore" parameterOrder="de_ssn"> <wsdl:input message="intf:getCreditScoreRequest" name="getCreditScoreRequest"/> <wsdl:output message="intf:getCreditScoreResponse" name="getCreditScoreResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="CreditAgencyWSSoapBinding" type="intf:CreditAgencyWS"> ... </wsdl:binding> <wsdl:service name="CreditAgencyWSService"> <wsdl:port binding="intf:CreditAgencyWSSoapBinding" name="CreditAgencyWS"> <wsdlsoap:address location="http://192.168.1.25:8080/axis/CreditAgencyWS.jws"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
Phần tử <wsdl:service> định nghĩa dịch vụ CreditAgencyWSService và công khai điểm cuối sẽ được truy cập bởi khách hàng, trong trường hợp này là nhà môi giới cho vay. Các phần tử <wsdl:operation> định nghĩa hai phương thức công khai được định nghĩa trong tệp CreditAgencyWS.jws, getCreditScore và getCreditHistoryLength. Đối với mỗi phương thức này, một cặp tin nhắn yêu cầu-phản hồi được định nghĩa, như có thể thấy trong các phần tử <wsdl:message>. Những tin nhắn này là getCreditScoreRequest, getCreditScoreResponse, getCreditHistoryLengthRequest và getCreditHistoryLengthResponse.
Một lần nữa, vì lý do tiết kiệm không gian, chúng tôi đã thu gọn hầu hết các phần của tệp WSDL để phù hợp với định dạng của phần này. Nếu bạn quan tâm đến việc xem toàn bộ tệp, nó có thể được truy cập trên máy chủ của bạn bằng cách sử dụng URL sau, nơi hostname và portnumber là các giá trị cho cài đặt máy chủ của bạn:
http://hostname:portnumber/axis/CreditAgencyWS.jws?wsdl
Dịch vụ web của cơ quan tín dụng trong ví dụ của chúng tôi không cung cấp chức năng thực tế. Thay vào đó, nó giả lập việc triển khai và trả về dữ liệu giả có thể được sử dụng bởi các phần khác của ứng dụng.
Sau khi đã làm giàu dữ liệu khách hàng, môi giới cho vay bây giờ gọi đến chức năng thanh toán cho vay, là một phần của chính môi giới cho vay. Như đã thấy trong cuộc gọi tiếp theo, thanh toán cho vay nhận tất cả dữ liệu cho đơn xin vay.
getResultsFromLoanClearingHouse(ssn, loanamount, loanduration, credit_history_length, credit_score);
Chức năng trung tâm thanh toán cho vay có thể được phân tách thêm thành đơn vị logic riêng nếu ứng dụng trở nên phức tạp hơn hoặc nếu các yêu cầu của nhà môi giới vay thay đổi để sử dụng một trung tâm thanh toán cho vay bên ngoài. Trong ví dụ của chúng tôi, chức năng của trung tâm thanh toán cho vay có thể được chia thành ba bước:
Lấy danh sách các nhà cho vay có thể phục vụ khoản vay của khách hàng.
Lấy báo giá tốt nhất từ tất cả các báo giá của từng ngân hàng trong danh sách người cho vay.
Định dạng dữ liệu từ báo giá tốt nhất và trả lại cho nhà môi giới vay.
Mã code hiển thị các bước này:
private String getResultsFromLoanClearingHouse(int ssn, double loanamount, int loanduration, int credit_history_length, int credit_score) { String lch_results="Results from Loan Clearing House "; ArrayList lenderlist = LenderGateway.getLenderList (loanamount, credit_history_length, credit_score); BankQuote bestquote = BankQuoteGateway.getBestQuote (lenderlist,ssn,loanamount,loanduration,credit_history_length,credit_score); lch_results = "Out of a total of " + lenderlist.size() + " quote(s), the best quote is from" + this.getLoanQuotesReport(bestquote); return lch_results; } Yêu cầu đầu tiên cho hệ thống thanh toán khoản vay là có được danh sách những nhà cho vay phù hợp có thể phục vụ đơn xin vay của khách hàng. Để trừu tượng hóa các chức năng của quá trình lựa chọn nhà cho vay khỏi môi giới vay, chúng tôi tạo ra lớp LenderGateway. Chúng tôi có thể làm cho giải pháp thú vị hơn bằng cách đóng gói chức năng này trong một dịch vụ Web. Tuy nhiên, các dịch vụ Web cần được thiết kế cẩn thận, và các tham số cùng với kiểu trả về cần được xem xét, vì các kiểu này phải có thể tuần tự hóa được từ và đến mạng. Để giữ mọi thứ đơn giản, chúng tôi tích hợp logic lựa chọn nhà cho vay trong một lớp Java đơn giản mà được gọi bởi môi giới vay.
Sẽ rất tiện lợi cho người môi giới vay nếu cổng thông tin cho người cho vay trả về một tập hợp các điểm cuối dịch vụ cho các ngân hàng. Nhược điểm của phương pháp này là việc xác định dịch vụ web của ngân hàng sẽ phải được mã hóa cứng trong cổng thông tin cho người cho vay. Điều này trở thành một cơn ác mộng về bảo trì trong thực tế, đặc biệt là vì các ngân hàng thường xuyên bị mua, bán hoặc sáp nhập hơn là các kiến trúc sư CNTT thay đổi công việc. Chúng tôi sẽ thảo luận về một giải pháp vững chắc cho ngân hàng và dịch vụ web của nó trong phần thảo luận về chủ đề BankQuoteGateway phía sau trong phần này.
Phương pháp getLenderList, được trình bày dưới đây, trả về tập hợp các nhà cho vay (tức là, các ngân hàng) có thể phục vụ yêu cầu cho vay.
public static ArrayList getLenderList(double loanamount, int credit_history_length, int credit_score){ ArrayList lenders = new ArrayList(); LenderGateway.readProps(); if ((loanamount >= (double)75000) && (credit_score >= 600) && (credit_history_length >= 8)) { lenders.add(new Bank1(hostname, portnum)); lenders.add(new Bank2(hostname, portnum)); } if (((loanamount >= (double)10000) && (loanamount <= (double)74999)) && (credit_score >= 400) && (credit_history_length >= 3)) { lenders.add(new Bank3(hostname, portnum)); lenders.add(new Bank4(hostname, portnum)); } lenders.add(new Bank5(hostname, portnum)); return lenders; } Phương pháp này triển khai mẫu Danh sách Người Nhận. Trong ví dụ của chúng ta, cơ sở quy tắc bao gồm những câu điều kiện rất đơn giản chọn một hoặc nhiều ngân hàng dựa trên một tập hợp các điều kiện đã được định nghĩa trước. Chúng tôi cũng đã đặt một sự lựa chọn mặc định cho mỗi yêu cầu của khách hàng để đảm bảo rằng mỗi yêu cầu của khách hàng sẽ có ít nhất một báo giá.
Nhà môi giới vay vốn giờ đây chuyển danh sách các nhà cho vay đến cổng báo giá ngân hàng để bắt đầu thu thập báo giá và thực hiện lựa chọn. Chúng tôi tạo ra một cổng khác, một lớp có tên là BankQuoteGateway để trừu tượng hóa cách hoạt động bên trong của giao diện ngân hàng. Tất cả những gì nhà môi giới vay vốn cần làm là yêu cầu báo giá tốt nhất từ BankQuoteGateway, như được trình bày trong lệnh gọi phương thức sau:
BankQuote bestquote = BankQuoteGateway.getBestQuote(lenderlist, ssn, loanamount, loanduration,credit_history_length,credit_score);
Ngân hàng Gateway phản hồi yêu cầu của môi giới vay bằng cách lấy báo giá từ tất cả các ngân hàng và sau đó chọn báo giá tốt nhất (tức là báo giá có lãi suất thấp nhất). Phương thức getBestQuote được hiển thị ở đây:
public static BankQuote getBestQuote(ArrayList lenders, int ssn, double loanamount, int loanduration, int credit_history_length, int credit_score){ BankQuote lowestquote = null; BankQuote currentquote = null; ArrayList bankquotes = BankQuoteGateway.getBankQuotes(lenders, ssn, loanamount, loanduration, credit_history_length, credit_score); Iterator allquotes = bankquotes.iterator(); while (allquotes.hasNext()){ if (lowestquote == null){ lowestquote = (BankQuote)allquotes.next(); } else{ currentquote = (BankQuote)allquotes.next(); if (currentquote.getInterestRate() < lowestquote.getInterestRate()){ lowestquote = currentquote; } } } return lowestquote; } Dòng quan trọng nhất trong mã trước là lệnh gọi đến getBankQuotes. Phương thức này không chỉ thực hiện phiên đấu giá có kiểm soát mà còn triển khai mẫu Tổng hợp. Đoạn mã dưới đây hiển thị phương thức getBankQuotes:
public static ArrayList getBankQuotes(ArrayList lenders, int ssn, double loanamount, int loanduration, int credit_history_length, int credit_score) { ArrayList bankquotes = new ArrayList(); BankQuote bankquote = null; Bank bank = null; Iterator banklist = lenders.iterator(); while (banklist.hasNext()){ bank = (Bank)banklist.next(); bankquote = bank.getBankQuote(ssn, loanamount, loanduration, credit_history_length, credit_score); bankquotes.add(bankquote); } return bankquotes; } Chức năng của một cuộc đấu giá có kiểm soát được thực hiện bởi vòng lặp while. Nó trích xuất từng ngân hàng từ danh sách người cho vay, và sau đó gọi phương thức để tạo ra một báo giá ngân hàng, như được làm nổi bật trong mã dưới đây. Hãy chú ý đặc biệt đến thứ tự của danh sách tham số trong lời gọi đến phương thức, và chúng tôi sẽ giải thích ý nghĩa khi bắt đầu thiết kế các ngân hàng và các dịch vụ Web liên quan.
bank.getBankQuote(ssn, loanamount, loanduration, credit_history_length, credit_score);
Phản hồi được tổng hợp sử dụng danh sách mảng bankquotes. Phương thức getBestQuote lặp qua bộ sưu tập các báo giá ngân hàng và chọn báo giá thấp nhất, báo giá này sẽ được gửi lại cho nhà môi giới vay.
Như đã đề cập trước đó, chúng tôi sẽ thiết kế ngân hàng và dịch vụ Web của ngân hàng để mô phỏng hoạt động của một ngân hàng thực tế và giữ chức năng của ngân hàng tách biệt, không liên kết chặt chẽ với chức năng của môi giới cho vay. Điều này sẽ giúp các lớp ngân hàng của chúng tôi có được lợi thế từ việc sử dụng mẫu Gateway như đã mô tả trước đó trong lớp CreditAgencyGateway.
Chúng tôi định nghĩa một lớp Ngân hàng trừu tượng như sau:
public abstract class Bank { String bankname; String endpoint = ""; double prime_rate; public Bank(String hostname, String portnum){ this.bankname = ""; this.prime_rate = 3.5; } public void setEndPoint(String endpt){this.endpoint = endpt;} public String getBankName(){return this.bankname;} public String getEndPoint(){return this.endpoint;} public double getPrimeRate(){return this.prime_rate;} public abstract BankQuote getBankQuote(int ssn, double loanamount, int loanduration, int credit_history_length, int credit_score); public void arbitraryWait(){ try{ Thread.sleep((int)(Math.random()*10)*100); }catch(java.lang.InterruptedException intex){ intex.printStackTrace(); } } } Trong ví dụ của chúng tôi, quy trình để nhận báo giá từ một ngân hàng được mô phỏng đại khái theo cách mà một ngân hàng thực tế hoạt động. Đầu tiên, một lượng công việc văn thư nhỏ được thực hiện, sau đó là việc truy cập vào hệ thống báo giá điện tử, và sau đó là công việc văn thư bổ sung được thực hiện trước khi báo giá được trả lại cho BankQuoteGateway.
Lớp trừu tượng Bank và các lớp ngân hàng con (Bank1 đến Bank5) mô phỏng hoạt động của một ngân hàng thông thường. Trong ví dụ của chúng ta, ngân hàng nhận yêu cầu vay và nhân viên văn phòng tiến hành nghiên cứu thẩm định trong khi xác minh rằng thông tin khách hàng là chính xác. Chúng tôi đã chọn mô phỏng công việc văn thư dưới dạng một phương thức chờ tùy ý được triển khai trong lớp trừu tượng Bank, như đã thể hiện, và được gọi trong phương thức getBankQuote. Để làm cho câu chuyện thêm thú vị, chúng tôi sử dụng dịch vụ Web để mô phỏng hệ thống báo giá lãi suất của ngân hàng nhằm lấy báo giá lãi suất. Đối với một ngân hàng cụ thể (ngân hàng n), hệ thống báo giá lãi suất được mô phỏng bằng BanknWS và được mã hóa trong một tệp tên là BanknWS.jws. Có năm lớp ngân hàng (Bank1 đến Bank5) và năm hệ thống báo giá lãi suất (Bank1WS đến Bank5WS). Mỗi hệ thống báo giá lãi suất sử dụng một định dạng khác nhau cho danh sách tham số trong cuộc gọi phương thức, giống như trong thực tế, các ngân hàng khác nhau có khả năng sử dụng các định dạng dữ liệu khác nhau. Điều này có nghĩa là lớp Bank cần sử dụng một Trình dịch Thông điệp để dịch định dạng của thông điệp trước khi gọi dịch vụ Web. Chúng tôi sẽ trình bày điều này sau khi thảo luận về các lớp Bank.
Lưu ý rằng phương thức getBankQuote trong lớp Bank trừu tượng là một phương thức trừu tượng và có các tham số được sắp xếp theo một định dạng cụ thể. Chúng ta bây giờ xem xét một trong những triển khai ngân hàng và, vì không có lý do cụ thể nào, chọn Bank1. Cấu trúc lớp của tất cả các ngân hàng sẽ giống nhau, và mỗi ngân hàng chỉ khác nhau ở các giá trị của các trường của nó (tên ngân hàng và địa chỉ điểm cuối), được thiết lập khi đối tượng ngân hàng được xây dựng.
public class Bank1 extends Bank { public Bank1(String hostname, String portnum){ super(hostname,portnum); bankname = "Exclusive Country Club Bankers\n"; String ep1 = "http://" + hostname + ":" + portnum + "/axis/Bank1WS.jws"; this.setEndPoint(ep1); } public void setEndPoint(String endpt){this.endpoint = endpt;} public String getBankName(){return this.bankname;} public String getEndPoint(){return this.endpoint;} public BankQuote getBankQuote(int ssn, double loanamount, int loanduration, int credit_history_length, int credit_score) { BankQuote bankquote = new BankQuote(); Integer i1 = new Integer(ssn); Double i2 = new Double(prime_rate); Double i3 = new Double(loanamount); Integer i4 = new Integer(loanduration); Integer i5 = new Integer(credit_history_length); Integer i6 = new Integer(credit_score); try{ Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName("getQuote"); call.addParameter( "op1", XMLType.XSD_INT, ParameterMode.IN ); call.addParameter( "op2", XMLType.XSD_DOUBLE, ParameterMode.IN ); call.addParameter( "op3", XMLType.XSD_DOUBLE, ParameterMode.IN ); call.addParameter( "op4", XMLType.XSD_INT, ParameterMode.IN ); call.addParameter( "op5", XMLType.XSD_INT, ParameterMode.IN ); call.addParameter( "op6", XMLType.XSD_INT, ParameterMode.IN ); call.setReturnType( XMLType.XSD_DOUBLE); Double interestrate = (Double) call.invoke( new Object [] {i1,i2,i3,i4,i5,i6}); bankquote.setBankName(bankname); bankquote.setInterestRate(interestrate.doubleValue()); }catch(Exception ex){ System.err.println("Error accessing the axis webservice from " + bankname); BankQuote badbq = new BankQuote(); badbq.setBankName("ERROR in WS"); return badbq; } arbitraryWait(); return bankquote; } } Như đã thấy trong mã trước đó, phương thức getBankQuote được cài đặt và có các tham số theo một thứ tự nhất định.
public BankQuote getBankQuote(int ssn, double loanamount, int loanduration, int credit_history_length, int credit_score)
Như đã mô tả trước đó, định dạng cho các tham số của hệ thống báo giá lãi suất cho mỗi ngân hàng là khác nhau. Điều này có nghĩa là phương thức getBankQuote của lớp Bank thực hiện mẫu Dịch giả Tin nhắn và phải chuyển đổi thứ tự của các tham số trước khi gọi dịch vụ Web của ngân hàng tương ứng. Chữ ký của phương thức getQuote cho mỗi dịch vụ Web ngân hàng được hiển thị dưới đây.
Ngân hàng1WS:
getQuote(int ssn, double prime_rate, double loanamount, int loanduration, int credit_history_length, int credit_score)
Ngân hàng2WS:
getQuote(double prime_rate, double loanamount, int loanduration, int credit_history_length, int credit_score, int ssn)
Ngân hàng3WS:
getQuote(double loanamount, int loanduration, int credit_history_length, int credit_score, int ssn, double prime_rate)
Ngân hàng4WS:
getQuote(int loanduration, int credit_history_length, int credit_score, int ssn, double prime_rate, double loanamount)
Ngân hàng5WS:
getQuote(int credit_history_length, int credit_score, int ssn, double prime_rate, double loanamount, int loanduration)
Việc triển khai thực tế của phương thức getQuote là một placeholder và trả về một báo giá tỷ lệ sử dụng một thuật toán đơn giản, như được chỉ ra dưới đây cho Bank1WS.jws.
public class Bank1WS { public double getQuote(int ssn, double prime_rate, double loanamount, int loanduration, int credit_history_length, int credit_score) { double ratepremium = 1.5; double int_rate = prime_rate + ratepremium + (double)(loanduration/12)/10 + (double)(Math.random()*10)/10; return int_rate; } } Trong một ứng dụng thực tế, công thức sẽ chi tiết và phức tạp hơn rất nhiều. Kiểu trả về của phương thức getQuote là một số chính xác kép đại diện cho tỷ lệ mà ngân hàng cung cấp cho khách hàng, dựa trên các tham số trong đơn xin vay.
Một lần nữa, máy chủ Axis tự động tạo ra một tệp WSDL cho mỗi tệp JWS của Ngân hàng (được phơi bày tại http://hostname:portnum/axis/Bank1WS.jws?wsdl). Các tệp WSDL cho các ngân hàng khác sẽ có định dạng tương tự nhưng sẽ khác nhau ở định nghĩa của các tham số. Tệp WSDL cho dịch vụ Web Bank1WS.jws được hiển thị bên dưới.
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"> <wsdl:message name="getQuoteRequest"> <wsdl:part name="ssn" type="xsd:int"/> <wsdl:part name="prime_rate" type="xsd:double"/> <wsdl:part name="loanamount" type="xsd:double"/> <wsdl:part name="loanduration" type="xsd:int"/> <wsdl:part name="credit_history_length" type="xsd:int"/> <wsdl:part name="credit_score" type="xsd:int"/> </wsdl:message> <wsdl:message name="getQuoteResponse"> <wsdl:part name="getQuoteReturn" type="xsd:double"/> </wsdl:message> <wsdl:portType name="Bank1WS"> <wsdl:operation name="getQuote" parameterOrder="ssn prime_rate loanamount loanduration credit_history_length credit_score"> <wsdl:input message="intf:getQuoteRequest" name="getQuoteRequest"/> <wsdl:output message="intf:getQuoteResponse" name="getQuoteResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="Bank1WSSoapBinding" type="intf:Bank1WS"> ... </wsdl:binding> <wsdl:service name="Bank1WSService"> <wsdl:port binding="intf:Bank1WSSoapBinding" name="Bank1WS"> <wsdlsoap:address location="http://192.168.1.25:8080/axis/Bank1WS.jws"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
Như chúng ta thấy, WSDL chứa một thao tác, getQuote, được định nghĩa trong phần tử <wsdl:operation>, mà Axis ánh xạ tới phương thức getQuote trong lớp Bank1WS.jws. Phần tử <wsdl:service> định nghĩa dịch vụ Web Bank1WS. Có một cặp tin nhắn yêu cầu-phản hồi, mỗi cái được định nghĩa trong một phần tử <wsdl:message>: getQuoteRequest và getQuoteResponse.
Tỷ lệ báo giá cho mỗi ngân hàng được thiết lập trong một bean báo giá ngân hàng (BankQuote), được thêm vào tập hợp được gửi về cho BankQuoteGateway. Bean này không cần định dạng, và các bean được trả lại bởi tất cả các ngân hàng trông về cơ bản là giống nhau. Điều này loại bỏ nhu cầu về một Normalizer để chuyển đổi các tin nhắn phản hồi sang định dạng chung.
Cổng thông tin BankQuoteGateway chọn báo giá thấp nhất từ bộ sưu tập các báo giá ngân hàng mà nó nhận lại và gửi một bean báo giá ngân hàng trở lại cho nhà môi giới cho vay. Nhà môi giới cho vay truy cập dữ liệu trong bean và định dạng một báo cáo để gửi lại cho ứng dụng khách. Phương thức định dạng báo cáo được hiển thị dưới đây.
private static String getLoanQuotesReport(BankQuote bestquote){ String bankname = bestquote.getBankName(); double bestrate = ((double)((long)(bestquote.getInterestRate()*1000))/(double)1000); String results = "\nBank Name: " + bankname + "Interest Rate: " + bestrate; return results; } Ứng dụng khách là giao diện của khách hàng tới ứng dụng môi giới cho vay. Yêu cầu chính của khách hàng là thu thập thông tin từ khách hàng trong một môi trường giao diện người dùng chức năng với kiểm tra lỗi đầy đủ. Ẩn sâu bên dưới và xa tầm mắt của khách hàng, ứng dụng khách chuẩn bị ba mảnh dữ liệu để chuyển đến điểm cuối của ứng dụng máy chủ. Để đơn giản, chúng tôi đã thiết kế ứng dụng khách trở thành một lớp Java với phương thức main nhận thông tin của khách hàng dưới dạng các đối số dòng lệnh. Trong thực tế, giao diện người dùng có thể được triển khai dưới dạng ứng dụng khách dày dựa trên cửa sổ hoặc ứng dụng khách mỏng dựa trên trình duyệt. Ứng dụng khách cũng có thể là một phần của một hệ thống kinh doanh khác mà mô hình lập trình ứng dụng khách đã được triển khai. Phần quan trọng nhất của ứng dụng khách liên quan đến việc gọi dịch vụ Web môi giới cho vay được trình bày ở đây:
Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName( "getLoanQuote" ); call.addParameter( "op1", XMLType.XSD_INT, ParameterMode.IN ); call.addParameter( "op2", XMLType.XSD_DOUBLE, ParameterMode.IN ); call.addParameter( "op3", XMLType.XSD_INT, ParameterMode.IN ); call.setReturnType( XMLType.XSD_STRING ); String ret = (String) call.invoke( new Object [] {ssn, loanamount, loanduration}); Các điểm nổi bật trong mã nguồn là các dòng xác định tên phương thức (getLoanQuotes) và các dòng thiết lập tham số cũng như kiểu dữ liệu trả về. Phương thức getLoanQuotes nhận vào một ID khách hàng, số tiền vay và thời gian vay. Giá trị trả về là một chuỗi.
Vì chúng tôi không sử dụng UDDI, dịch vụ tra cứu Web service, nên chúng tôi đã mã hóa cứng địa chỉ URL điểm cuối cho dịch vụ Web của mình. Do chúng tôi chọn triển khai ứng dụng môi giới cho vay dưới dạng tệp JWS, nên địa chỉ điểm cuối có định dạng chuẩn như được định nghĩa bởi API Axis cho JWS. Điểm cuối cho việc triển khai của chúng tôi được hiển thị trong URL sau, trong đó tên máy chủ và số cổng là các giá trị tương ứng với cài đặt máy chủ của bạn.
http://hostname:portnumber/axis/LoanBroker.jws
Ứng dụng khách, vốn bị chặn trong suốt thời gian chờ phản hồi, sẽ chấp nhận báo cáo được định dạng và hiển thị nó trong khu vực GUI đã được thiết lập cho nó. Ngoài ra, nó có thể được lưu hoặc gửi đến máy in.
Phần này giả định rằng bạn đã cài đặt Axis và ứng dụng môi giới vay. Bây giờ máy chủ cần được khởi động lại hoặc khởi động nếu nó chưa chạy. Hãy làm theo tài liệu trong các tệp trợ giúp của Tomcat để thực hiện các bước đúng để khởi động hoặc khởi động lại máy chủ. Bạn có thể xác minh rằng Tomcat và Apache Axis đang hoạt động bằng cách làm theo các bước sau:
Mở một shell hoặc cửa sổ lệnh trên máy khách và chạy ứng dụng như được hiển thị cho cả hệ điều hành UNIX/Linux hoặc Microsoft Windows:
java -classpath %CLASSPATH% LoanQueryClient [customerid] [loanamount] [loanduration in months]
hoặc
java -classpath $CLASSPATH LoanQueryClient [customerid] [loanamount] [loanduration in months]
Ví dụ,
java -classpath %CLASSPATH% LoanQueryClient 199 100000.00 29
Điều này kích hoạt dịch vụ Web môi giới vay và trả về các kết quả sau:
Calling the LoanBroker webservice at 1053292919270 ticks LoanBroker service replied at 1053292925860 ticks Total time to run the query = 6590 milliseconds The following reply was received from the Loan Clearing House Client with ssn= 199 requests a loan of amount= 100000.0 for 29 months Additional data for customer: credit score and length of credit history Credit Score= 756 Credit History Length= 12 The details of the best quote from all banks that responded are shown below: Out of a total of 3 quote(s), the best quote is from Bank Name: Exclusive Country Club Bankers Interest Rate: 6.197
Bạn có thể kiểm tra môi giới cho vay bằng cách nhập các khoản vay khác nhau khi chạy ứng dụng khách. Chúng ta sẽ phân tích kết quả đầu ra với một ứng dụng khách duy nhất. Sau đó, chúng ta sẽ khởi động nhiều ứng dụng khách.
Ứng dụng khách theo dõi thời gian khi nó gọi đến điểm cuối dịch vụ Web của môi giới cho vay trên máy chủ. Khách hàng cũng ghi lại thời gian khi máy chủ phản hồi với kết quả. Cả thời gian bắt đầu và thời gian kết thúc của cuộc gọi đến dịch vụ Web đều được báo cáo trong ứng dụng khách cùng với sự chênh lệch giữa hai thời gian đó.
Calling the LoanBroker webservice at 1053292919270 ticks LoanBroker service replied at 1053292925860 ticks Total time to run the query = 6590 milliseconds
Dịch vụ Web của Nhà thanh toán cho vay báo cáo mọi chi tiết liên quan đến yêu cầu của khách hàng được gửi qua mạng bởi ứng dụng của khách hàng.
Client with ssn= 199 requests a loan of amount= 100000.0 for 29 months
Nhà Thanh toán cho Vay cũng báo cáo thêm dữ liệu tín dụng được thu thập để hỗ trợ yêu cầu của khách hàng.
Additional data for customer: credit score and length of credit history Credit Score= 756 Credit History Length= 12
Nhà môi giới cho vay phân tích dữ liệu và chọn một tập hợp các ngân hàng phù hợp với tiêu chí yêu cầu vay của khách hàng. Nhà môi giới cho vay gửi dữ liệu khách hàng dưới định dạng yêu cầu của từng ngân hàng và chờ phản hồi từ mỗi ngân hàng. Vì đây là một ứng dụng đồng bộ, nhà môi giới cho vay sẽ bị chặn cho đến khi ngân hàng phản hồi hoặc yêu cầu hết thời gian chờ hoặc thất bại.
Người môi giới cho vay thu thập tất cả các phản hồi, phân tích các báo giá nhận được và chọn báo giá tốt nhất. Báo giá này được định dạng và gửi lại cho khách hàng cùng với bất kỳ dữ liệu liên quan nào. Dưới đây là chi tiết của báo giá tốt nhất từ tất cả các ngân hàng đã phản hồi:
Out of a total of 3 quote(s), the best quote is from Bank Name: Exclusive Country Club Bankers Interest Rate: 6.197
Từ đoạn mã trước đó, chúng ta thấy rằng LoanBroker báo cáo rằng ba ngân hàng đã phản hồi và nó đã chọn báo giá tốt nhất và trình bày báo giá đó cho người dùng.
Như đã giải thích khi chúng ta thảo luận về sơ đồ tuần tự trước đó trong chương này, tổng thời gian để nhận được báo giá phản hồi là rất quan trọng vì người môi giới cho khoản vay phải chờ phản hồi từ mỗi ngân hàng trước khi gửi yêu cầu đến ngân hàng tiếp theo trong danh sách cho vay. Do đó, khách hàng phải chờ rất lâu sau khi gửi yêu cầu để nhận lại báo giá kết quả. Chúng tôi đã thực hiện một số bài kiểm tra cơ bản với một khách hàng duy nhất đối với máy chủ và có được thời gian trung bình tổng thể để chạy truy vấn (khoảng 8 giây). Sau đó, chúng tôi đã khởi động bốn phiên bản của khách hàng trong các cửa sổ riêng biệt trên cùng một máy chủ khách và có được các thời gian trung bình sau:
Client 1: 12520 milliseconds Client 2: 12580 milliseconds Client 3: 15710 milliseconds Client 4: 13760 milliseconds
Trong khi những bài kiểm tra này không thể được coi là khoa học theo bất kỳ cách nào, bằng chứng thực nghiệm chỉ ra rằng hiệu suất bị ảnh hưởng rất nhiều khi nhiều khách hàng cố gắng truy cập đồng thời vào hệ thống môi giới vay của chúng tôi.
Để làm cho việc thảo luận về thiết kế của ví dụ môi giới vay dễ dàng hơn, chúng tôi chọn triển khai tất cả các dịch vụ Web dưới dạng tệp JWS. Điều này mang lại cho chúng tôi lợi thế về việc triển khai dịch vụ chỉ bằng cách sao chép nó lên máy chủ. Tuy nhiên, bất lợi là một thể hiện mới của lớp dịch vụ được khởi tạo cho mỗi yêu cầu và bị giải phóng ngay khi yêu cầu hoàn thành. Điều này có nghĩa là một phần thời gian trễ mà chúng tôi nhận thấy là kết quả của việc máy chủ tạo ra các thể hiện của lớp trước khi gọi dịch vụ.
Chúng tôi có thể đã chọn con đường phức tạp hơn và thiết kế một tệp lớp Java sẽ được triển khai bằng cách sử dụng tệp WSDD. Điều này sẽ mang lại cho chúng tôi sự linh hoạt trong việc xác định thời gian mà lớp được khởi tạo sẽ tồn tại: trong suốt phiên làm việc của khách hàng hoặc trong suốt thời gian ứng dụng chạy. Vấn đề về cách triển khai một dịch vụ Web là một vấn đề quan trọng khi thiết kế một ứng dụng thực tế. Nếu chúng tôi chọn bao gồm vấn đề triển khai, mô tả về ví dụ sẽ trở nên rất dài dòng và các chi tiết thiết kế sẽ trở nên phức tạp không cần thiết cho mục đích của chương này.
Trong phần này, chúng tôi đã bước qua việc triển khai ứng dụng môi giới vay vốn sử dụng dịch vụ Web SOAP/HTTP đồng bộ. Chúng tôi đã sử dụng định tuyến dự đoán để gửi yêu cầu vay của mình đến một tập hợp các ngân hàng. Chúng tôi đã nêu bật những điểm mạnh và điểm yếu của phương pháp này. Chúng tôi đã thực hiện một số sự thỏa hiệp trong thiết kế để quản lý cuộc thảo luận và tránh bị sa lầy trong việc mô tả các chi tiết triển khai. Ý định tổng thể là cung cấp một cuộc thảo luận về những ưu điểm và nhược điểm của phương pháp này. Chúng tôi cũng đã thấy việc sử dụng nhiều mẫu được mô tả trong cuốn sách này, điều sẽ giúp trong việc điều chỉnh phương pháp dự đoán đồng bộ cho các lĩnh vực kinh doanh khác.
Phần này mô tả cách triển khai ví dụ về môi giới cho vay (xem phần giới thiệu của chương này) sử dụng Microsoft .NET, C# và MSMQ. Khung công tác Microsoft .NET bao gồm không gian tên System.Messaging, cung cấp cho các chương trình .NET quyền truy cập vào Dịch vụ Xếp hàng Tin nhắn Microsoft có trong các phiên bản gần đây của hệ điều hành Windows (Windows 2000, Windows XP và Windows Server 2003). Ví dụ này đi qua nhiều quyết định thiết kế và cho thấy mã thực tế cần thiết để làm cho giải pháp này hoạt động. Càng nhiều càng tốt, chúng tôi tập trung vào các khía cạnh thiết kế của giải pháp để ví dụ này có giá trị ngay cả khi bạn không phải là một lập trình viên C# hardcore. Thực tế, phần lớn ứng dụng ngoài giao diện thực tế vào System.Messaging sẽ trông rất giống nhau nếu việc triển khai này được thực hiện bằng Java và JMS.
Một số chức năng được trình bày trong giải pháp này có thể được triển khai với ít công sức lập trình hơn bằng cách sử dụng công cụ tích hợp và hoặc điều phối như Microsoft BizTalk Server. Tôi đã cố tình tránh sử dụng các công cụ như vậy vì hai lý do. Thứ nhất, những công cụ này không miễn phí, và bạn sẽ phải mua một giấy phép chỉ để chạy ví dụ đơn giản này. Thứ hai, tôi muốn chứng minh việc triển khai rõ ràng tất cả các chức năng cần thiết.
Giải pháp được thiết lập dưới dạng nhiều file thực thi để các thành phần khác nhau có thể được phân phối trên nhiều máy tính. Để đơn giản hóa yêu cầu thiết lập và tránh phải cài đặt Active Directory, các thông điệp riêng tư nội bộ đã được sử dụng trong ví dụ này. Kết quả là, giải pháp "như hiện tại" phải hoạt động trên một máy đơn.
Triển khai ví dụ về môi giới vay này sử dụng messaging bất đồng bộ qua các hàng đợi tin nhắn. Như đã mô tả trong tổng quan ví dụ, điều này cho phép chúng tôi xử lý nhiều yêu cầu báo giá đồng thời nhưng cũng yêu cầu chúng tôi phải tương quan các tin nhắn khi chúng di chuyển qua hệ thống và cuối cùng tạo ra một tin nhắn phản hồi cho yêu cầu báo giá vay. Nhiều quyết định thiết kế của chúng tôi trong suốt ví dụ này được thúc đẩy bởi nhu cầu xử lý bất đồng bộ.
Ý tưởng tốt là bắt đầu hiểu thiết kế trung gian cho vay từ bên ngoài vào trong. Hãy bắt đầu bằng cách xem xét tất cả các giao diện bên ngoài mà trung gian cho vay cần hỗ trợ (xem hình). Bởi vì hàng đợi tin nhắn là một chiều, chúng ta cần một cặp hàng đợi để thiết lập giao tiếp yêu cầu-phản hồi với một thành phần khác (xem phần "Ví dụ Yêu cầu/Phản hồi .NET" trong Chương 6, "Giữa: Tin nhắn Đơn giản," cho một ví dụ đơn giản). Do đó, trung gian cho vay nhận các yêu cầu báo giá cho vay trên hàng đợi loanRequestQueue và phản hồi đến khách hàng thử nghiệm trên hàng đợi loanReplyQueue. Sự tương tác với tổ chức tín dụng diễn ra qua một cặp hàng đợi tương tự. Thay vì tạo một cặp hàng đợi cho mỗi ngân hàng, chúng tôi quyết định để tất cả các ngân hàng phản hồi về cùng một bankReplyQueue. Danh sách Người Nhận gửi tin nhắn yêu cầu đến mỗi hàng đợi của ngân hàng riêng lẻ, trong khi Bộ Tập hợp chọn báo giá tốt nhất từ các tin nhắn phản hồi đến trên loanReplyQueue. Cùng nhau, Danh sách Người Nhận và Bộ Tập hợp hoạt động như một kiểu phân phối Scatter-Gather. Để đơn giản, tất cả các ngân hàng trong ví dụ này sử dụng cùng một định dạng tin nhắn để không cần có một Bộ Chuẩn hóa. Nhưng vì định dạng tin nhắn chung của ngân hàng khác với định dạng mà người tiêu dùng mong đợi, chúng ta vẫn cần sử dụng một Bộ Dịch tin nhắn để chuyển đổi các tin nhắn phản hồi của ngân hàng thành một tin nhắn phản hồi của trung gian cho vay. Tôi đã quyết định thiết kế trung gian cho vay như một Trình Quản lý Quy trình. Thay vì triển khai các chức năng bên trong trung gian cho vay như các thành phần riêng lẻ được tách biệt bởi các hàng đợi tin nhắn, trung gian cho vay là một thành phần duy nhất thực hiện tất cả các chức năng bên trong. Cách tiếp cận này loại bỏ chi phí overhead mà sẽ xảy ra khi gửi tin nhắn qua các hàng đợi giữa các chức năng này, nhưng nó yêu cầu trung gian cho vay phải duy trì nhiều phiên xử lý đồng thời.
Nhà môi giới vay với giao diện hàng đợi tin nhắn

Phần này không nhằm mục đích làm một giới thiệu về không gian tên System.Messaging và MSMQ. Do đó, việc tách các chức năng cụ thể của MSMQ thành các lớp riêng biệt là hợp lý để mã ứng dụng không bị làm lộn xộn bởi các lệnh cụ thể của MSMQ. Mẫu Gateway [EAA] là một lựa chọn xuất sắc cho mục đích này và cung cấp hai lợi thế chính: Thứ nhất, nó trừu tượng hóa các chi tiết kỹ thuật của giao tiếp khỏi ứng dụng. Thứ hai, nếu chúng ta chọn tách giao diện gateway khỏi triển khai gateway, chúng ta có thể thay thế dịch vụ bên ngoài thực tế bằng một Service Stub [EAA] để kiểm thử.
Một cổng giúp giữ thông tin MSMQ ra ngoài ứng dụng và cải thiện khả năng kiểm thử.

Trong trường hợp của chúng tôi, chúng tôi định nghĩa hai giao diện trong Cổng Giao tiếp: IMessageSender và IMessageReceiver. Chúng tôi giữ cho các giao diện này gần như đơn giản một cách hiển nhiên. Tất cả những gì IMessageSender có thể làm là gửi một tin nhắn, và tất cả những gì IMessageReceiver có thể làm là (ngạc nhiên!) nhận một tin nhắn. Thêm vào đó, người nhận có một phương thức Begin để cho nó biết rằng nó có thể bắt đầu nhận tin nhắn. Giữ cho các giao diện này đơn giản như vậy giúp dễ dàng định nghĩa các lớp triển khai giao diện.
namespace MessageGateway { using System.Messaging; public interface IMessageSender { void Send(Message mess); } } namespace MessageGateway { using System.Messaging; public interface IMessageReceiver { OnMsgEvent OnMessage { get; set; } void Begin(); MessageQueue GetQueue(); } } Các triển khai thực tế nằm trong các lớp MessageSenderGateway và MessageReceiverGateway. Các lớp này đảm nhận việc cấu hình các thuộc tính của hàng đợi tin nhắn, chẳng hạn như bộ lọc thuộc tính MessageReadProperty hoặc cài đặt Bộ định dạng. MessageReceiverGateway sử dụng một Phương pháp Mẫu [GoF] cho sự kiện ReceiveCompleted của hàng đợi tin nhắn MSMQ để xử lý các chi tiết nhỏ nhưng quan trọng, chẳng hạn như gọi phương thức mq.BeginReceive sau khi xử lý tin nhắn. Thay vì đi sâu vào chi tiết của các tính năng này, chúng tôi xin giới thiệu bạn đến tài liệu trực tuyến trên MSDN [MSMQ].
Bởi vì chúng tôi đã định nghĩa các giao diện rất hẹp, nên cũng có thể cung cấp một triển khai mà thậm chí không sử dụng hàng đợi tin nhắn. MockQueue triển khai cả hai giao diện mà không cần tham chiếu đến một hàng đợi tin nhắn! Khi một ứng dụng gửi một tin nhắn, MockQueue ngay lập tức kích hoạt sự kiện OnMessage với chính tin nhắn đó. Điều này làm cho việc kiểm tra ứng dụng trong một không gian địa chỉ đơn giản hơn nhiều mà không phải lo lắng về các khía cạnh bất đồng bộ (Thông tin thêm về kiểm tra sẽ được đề cập sau).
Dòng OnMsgEvent OnMessage trong IMessageReceiver có thể cần một chút giải thích cho những ai mới làm quen với C#. Khung .NET cung cấp các tính năng ngôn ngữ cho mẫu Observer [GoF], được gọi là delegate và sự kiện. OnMsgEvent là một delegate được định nghĩa trong MessageReceiverGateway:
public delegate void OnMsgEvent(Message msg);
Một delegate cho phép các đối tượng đăng ký với một loại sự kiện nhất định. Khi sự kiện được gọi, .NET sẽ gọi tất cả các phương thức đã đăng ký. Một delegate có thể được gọi bằng nhiều cách, nhưng hình thức đơn giản nhất là gọi trực tiếp bằng cách sử dụng tên của delegate.
OnMsgEvent receiver; Message message; ... receiver(message);
Nếu điều này khiến bạn quan tâm hơn đến các delegate, hãy xem một cuốn sách tốt về .NET hoặc C#. Nếu bạn muốn biết chi tiết cụ thể về cách mà Common Language Runtime (CLR) thực hiện chúng, hãy tham khảo [Box].
Khi chúng ta nhìn vào thiết kế cấp cao, chúng ta nhanh chóng nhận ra rằng một số thành phần trong kịch bản môi giới cho vay có chức năng chung. Ví dụ, cả ngân hàng và cơ quan tín dụng đều hoạt động như một dịch vụ bằng cách nhận yêu cầu, xử lý yêu cầu và công bố kết quả lên một kênh khác. Nghe có vẻ dễ dàng. Nhưng vì chúng ta sống trong thế giới của việc nhắn tin không đồng bộ, chúng ta phải làm thêm một chút công việc để triển khai ngay cả một sơ đồ yêu cầu-đáp đơn giản. Đầu tiên, chúng ta muốn người gọi dịch vụ chỉ định một Địa chỉ Trả về cho phản hồi. Điều này cho phép các người gọi khác nhau sử dụng cùng một dịch vụ nhưng sử dụng các hàng đợi phản hồi khác nhau. Dịch vụ cũng nên hỗ trợ một Nhận diện Tương quan để người gọi có thể đối chiếu các tin nhắn phản hồi đến với các tin nhắn yêu cầu. Hơn nữa, nếu dịch vụ nhận được một tin nhắn ở định dạng không được công nhận, thì tốt nhất nên chuyển hướng tin nhắn đến một Kênh Tin nhắn Không hợp lệ thay vì đơn giản là loại bỏ nó.
Để loại bỏ sự trùng lặp mã (tội lỗi chết người của lập trình hướng đối tượng), tôi tạo ra lớp cơ sở MQService. Lớp này tích hợp hỗ trợ cho Địa chỉ Trả về và Nhận dạng Tương quan. Thực tế, hỗ trợ phía máy chủ cho Nhận dạng Tương quan không gì khác hơn là sao chép ID tin nhắn của tin nhắn đến vào ID tương quan của tin nhắn phản hồi. Trong ví dụ của chúng tôi, chúng tôi cũng sao chép thuộc tính AppSpecific vì sau này chúng tôi sẽ thấy rằng đôi khi chúng tôi cần tương quan theo một thuộc tính khác ngoài ID tin nhắn. MQService cũng đảm bảo gửi phản hồi đến Địa chỉ Trả về đã chỉ định. Bởi vì người yêu cầu cung cấp Địa chỉ Trả về, tham số khởi tạo duy nhất cho MQService là tên của hàng đợi yêu cầu, hàng đợi mà tin nhắn yêu cầu mới được gửi đến. Nếu người yêu cầu quên cung cấp Địa chỉ Trả về, Dịch vụ Yêu cầu-Phản hồi sẽ gửi phản hồi đến Kênh Tin nhắn Không hợp lệ. Chúng tôi cũng có thể xem xét việc gửi tin nhắn yêu cầu đến Kênh Tin nhắn Không hợp lệ vì đó là tin nhắn đã gây ra lỗi. Hiện tại, chúng tôi sẽ giữ cho cuộc sống của mình đơn giản và không đi vào chi tiết xử lý lỗi.
public abstract class MQService { static protected readonly String InvalidMessageQueueName = ".\\private$\\invalidMessageQueue"; IMessageSender invalidQueue = new MessageSenderGateway(InvalidMessageQueueName); protected IMessageReceiver requestQueue; protected Type requestBodyType; public MQService(IMessageReceiver receiver) { requestQueue = receiver; Register(requestQueue); } public MQService(String requestQueueName) { MessageReceiverGateway q = new MessageReceiverGateway(requestQueueName, GetFormatter()); Register(q); this.requestQueue = q; Console.WriteLine("Processing messages from " + requestQueueName); } protected virtual IMessageFormatter GetFormatter() { return new XmlMessageFormatter(new Type[] { GetRequestBodyType() }); } protected abstract Type GetRequestBodyType(); protected Object GetTypedMessageBody(Message msg) { try { if (msg.Body.GetType().Equals(GetRequestBodyType())) { return msg.Body; } else { Console.WriteLine("Illegal message format."); return null; } } catch (Exception e) { Console.WriteLine("Illegal message format" + e.Message); return null; } } public void Register(IMessageReceiver rec) { OnMsgEvent ev = new OnMsgEvent(OnMessage); rec.OnMessage += ev; } public void Run() { requestQueue.Begin(); } public void SendReply(Object outObj, Message inMsg) { Message outMsg = new Message(outObj); outMsg.CorrelationId = inMsg.Id; outMsg.AppSpecific = inMsg.AppSpecific; if (inMsg.ResponseQueue != null) { IMessageSender replyQueue = new MessageSenderGateway(inMsg.ResponseQueue); replyQueue.Send(outMsg); } else { invalidQueue.Send(outMsg); } } protected abstract void OnMessage(Message inMsg); } Lớp này là trừu tượng vì nó không cung cấp một triển khai cho các phương thức GetTypedMessageBody và OnMessage. Vì chúng tôi muốn các lớp của mình xử lý càng nhiều càng tốt các đối tượng kinh doanh loại mạnh thay vì các loại dữ liệu Message, chúng tôi có MQService xác minh loại của nội dung thông điệp và ép kiểu nó thành loại đúng. Vấn đề là lớp cơ sở trừu tượng này không biết loại nào để ép kiểu vì lớp cơ sở có thể được sử dụng bởi nhiều triển khai dịch vụ khác nhau, mỗi loại có khả năng sử dụng một loại thông điệp khác nhau. Để thực hiện càng nhiều công việc càng tốt trong lớp cơ sở, chúng tôi đã tạo phương thức GetTypedMessageBody và phương thức trừu tượng GetRequestBodyType. Mỗi lớp con phải triển khai phương thức GetRequestBodyType để chỉ định loại thông điệp mà nó mong đợi nhận được. MQServer sử dụng loại đó để khởi tạo bộ định dạng XML và thực hiện kiểm tra loại. Sau các kiểm tra này, lớp con có thể an toàn ép kiểu nội dung thông điệp đến loại mong muốn mà không gây ra ngoại lệ. Việc xử lý ngoại lệ bên trong GetTypedMessageBody thực sự còn đơn giản ở giai đoạn này—tất cả những gì nó làm là in một thông điệp ra màn hình. Nếu đây không phải là một ứng dụng demo đơn giản, chúng tôi chắc chắn đã sử dụng một phương pháp tinh vi hơn để ghi chép hoặc, tốt hơn nữa, một Bus Điều Khiển toàn diện.
Phương pháp OnMessage được để lại cho các lớp con của MQService thực hiện. Chúng tôi cung cấp hai cài đặt, một cài đặt đồng bộ và một cài đặt bất đồng bộ. Cài đặt đồng bộ (RequestReplyService) gọi phương thức ảo ProcessMessage, được kỳ vọng sẽ trả về một tin nhắn phản hồi, và ngay lập tức gọi SendReply. Ngược lại, cài đặt bất đồng bộ (AsyncRequestReplyService) định nghĩa phương thức ảo ProcessMessage mà không có tham số trả về. Các lớp con kế thừa có trách nhiệm gọi SendReply.
public class RequestReplyService : MQService { public RequestReplyService(IMessageReceiver receiver) : base(receiver) {} public RequestReplyService(String requestQueueName) : base (requestQueueName) {} protected override Type GetRequestBodyType() { return typeof(System.String); } protected virtual Object ProcessMessage(Object o) { String body = (String)o; Console.WriteLine("Received Message: " + body); return body; } protected override void OnMessage(Message inMsg) { inMsg.Formatter = GetFormatter(); Object inBody = GetTypedMessageBody(inMsg); if (inBody != null) { Object outBody = ProcessMessage(inBody); if (outBody != null) { SendReply(outBody, inMsg); } } } } public class AsyncRequestReplyService : MQService { public AsyncRequestReplyService(IMessageReceiver receiver) : base(receiver) {} public AsyncRequestReplyService(String requestQueueName) : base (requestQueueName) {} protected override Type GetRequestBodyType() { return typeof(System.String); } protected virtual void ProcessMessage(Object o, Message msg) { String body = (String)o; Console.WriteLine("Received Message: " + body); } protected override void OnMessage(Message inMsg) { inMsg.Formatter = GetFormatter(); Object inBody = GetTypedMessageBody(inMsg); if (inBody != null) { ProcessMessage(inBody, inMsg); } } } Cả hai lớp đều cung cấp một triển khai mặc định cho các phương thức GetRequestBodyType và ProcessMessage. GetRequestBodyType xác định rằng thông điệp mong đợi một chuỗi đơn giản, và ProcessMessage in chuỗi đó ra bảng điều khiển. Về mặt kỹ thuật, chúng ta có thể đã bỏ qua các triển khai mặc định của những phương thức này từ các lớp RequestReplyService và AsyncRequestReplyService để chúng vẫn giữ nguyên là trừu tượng. Điều này sẽ cho phép trình biên dịch phát hiện bất kỳ lớp con nào của một trong các lớp này mà quên triển khai một trong các phương thức trừu tượng. Tuy nhiên, việc có một triển khai mặc định của dịch vụ có sẵn cho mục đích thử nghiệm và gỡ lỗi thì rất thuận tiện, vì vậy chúng tôi để cho các lớp này là cụ thể để có thể được khởi tạo như hiện tại.
Tóm lại, sơ đồ lớp cho các lớp cơ sở trông như sau (chúng tôi sẽ thảo luận về các lớp ngân hàng, tổ chức tín dụng và môi giới cho vay ngay sau đây):
Lớp cơ sở cho dịch vụ tin nhắn

Bây giờ mà chúng ta đã tạo ra một tập hợp các lớp cơ sở và các hàm tiện ích, đã đến lúc bắt đầu triển khai logic ứng dụng. Một cách dễ dàng để bắt đầu tạo ra giải pháp là xây dựng các thành phần ứng dụng theo thứ tự ngược lại của sự phụ thuộc. Điều này có nghĩa là, chúng ta sẽ bắt đầu tạo ra các thành phần không phụ thuộc vào bất cứ điều gì khác. Điều này cho phép chúng ta chạy và kiểm tra những thành phần này một cách độc lập. Ngân hàng chắc chắn là một trong những thành phần đó. Người môi giới cho vay phụ thuộc vào các ngân hàng, nhưng các ngân hàng tự bản thân chúng là độc lập. Thật thuận tiện, ngân hàng là một ví dụ điển hình của dịch vụ yêu cầu-phản hồi, vì vậy việc triển khai một ngân hàng nên đơn giản như việc kế thừa từ RequestReplyService và điền vào một số logic kinh doanh.
Trước khi chúng ta bắt đầu làm việc với nội bộ của ngân hàng, chúng ta cần định nghĩa giao diện bên ngoài. Chúng ta cần xác định các loại thông điệp cho yêu cầu và phản hồi báo giá khoản vay. Đối với việc triển khai đơn giản của chúng ta, chúng ta định nghĩa một định dạng thông điệp chung cho tất cả các ngân hàng để có thể sử dụng một lớp chung cho tất cả năm thể hiện của ngân hàng. C# hỗ trợ structs, vì vậy chúng ta sẽ sử dụng chúng làm các loại thông điệp:
public struct BankQuoteRequest { public int SSN; public int CreditScore; public int HistoryLength; public int LoanAmount; public int LoanTerm; } public struct BankQuoteReply { public double InterestRate; public String QuoteID; public int ErrorCode; } Vì chúng tôi muốn sử dụng một lớp duy nhất cho tất cả các thể hiện ngân hàng, chúng tôi cần tham số hóa các ngân hàng để có hành vi khác nhau. Các ngân hàng của chúng tôi là những thực thể rất đơn giản, vì vậy các tham số duy nhất là TênNgânHàng, TỷLệPhí và ThờiHạnKhoảnVayTốiĐa. TỷLệPhí xác định số điểm lãi suất mà ngân hàng tính thêm trên tỷ lệ chuẩn - về cơ bản, là biên lợi nhuận của ngân hàng. ThờiHạnKhoảnVayTốiĐa xác định thời gian vay dài nhất (tính bằng tháng) mà ngân hàng sẵn sàng gia hạn. Nếu yêu cầu vay có thời gian dài hơn thời gian quy định, ngân hàng sẽ rất biết ơn mà từ chối. Sau khi cắm vào các bộ khởi tạo và các phương thức truy cập thích hợp, chúng tôi có thể xây dựng phương thức XửLýTinNhắn của ngân hàng:
internal class Bank : RequestReplyService { ... protected override Type GetRequestBodyType() { return typeof(BankQuoteRequest); } protected BankQuoteReply ComputeBankReply(BankQuoteRequest requestStruct) { BankQuoteReply replyStruct = new BankQuoteReply(); if (requestStruct.LoanTerm <= MaxLoanTerm) { replyStruct.InterestRate = PrimeRate + RatePremium + (double)(requestStruct.LoanTerm / 12)/10 + (double)random.Next(10) / 10; replyStruct.ErrorCode = 0; } else { replyStruct.InterestRate = 0.0; replyStruct.ErrorCode = 1; } replyStruct.QuoteID = String.Format("{0}-{1:00000}", BankName, quoteCounter); quoteCounter++; return replyStruct; } protected override Object ProcessMessage(Object o) { BankQuoteRequest requestStruct; BankQuoteReply replyStruct; requestStruct = (BankQuoteRequest)o; replyStruct = ComputeBankReply(requestStruct); Console.WriteLine("Received request for SSN {0} for {1:c} / {2} months", requestStruct.SSN, requestStruct.LoanAmount, requestStruct.LoanTerm); Thread.Sleep(random.Next(10) * 100); Console.WriteLine(" Quote: {0} {1} {2}", replyStruct.ErrorCode, replyStruct.InterestRate, replyStruct.QuoteID); return replyStruct; } } Chúng ta có thể thấy rằng dịch vụ cụ thể chỉ cần triển khai các phương thức GetRequestBodyType và ProcessMessage. Dịch vụ có thể an toàn ép kiểu đối tượng được truyền vào bởi ProcessMessage vì lớp cơ sở đã xác minh kiểu đúng. Như chúng ta thấy, phần triển khai còn lại gần như không liên quan đến thông điệp, tất cả các chi tiết được xử lý trong các lớp cơ sở. Các lớp MQService và RequestReplyService hoạt động như một Bộ kích hoạt Dịch vụ, giúp ứng dụng không phải đi sâu vào các chi tiết của hệ thống nhắn tin.
Phương pháp ComputeBankReply chứa đầy đủ logic kinh doanh cho một ngân hàng. Giá mà cuộc sống chỉ đơn giản như vậy! Thế nhưng, đây không phải là một bài giới thiệu về kinh tế vĩ mô, mà là một ví dụ về thông điệp, vì vậy chúng tôi đã làm đơn giản hóa một số điều. Lãi suất được tính toán là tổng của lãi suất chuẩn, lãi suất premium đã cấu hình, thời hạn vay và một chút ngẫu nhiên. Nếu thời hạn vay được yêu cầu dài hơn mức mà ngân hàng cảm thấy thoải mái, nó sẽ trả về mã lỗi. Mỗi báo giá mà ngân hàng phát hành đều nhận được một mã báo giá duy nhất để khách hàng có thể tham khảo sau này. Trong triển khai hiện tại, một bộ đếm đơn giản tạo ra những mã này.
Phương thức ProcessMessage tích hợp một sự trì hoãn nhỏ (giữa 1/10 và 1 giây) để làm cho giao dịch ngân hàng trở nên thực tế hơn. ProcessMessage cũng ghi lại một số hoạt động vào bảng điều khiển để chúng ta có thể thấy điều gì đang xảy ra khi chạy nó trong một ứng dụng điều khiển đơn giản.
Để khởi động một ngân hàng, trước tiên chúng ta khởi tạo nó với các tham số phù hợp, và sau đó chúng ta gọi phương thức Run mà nó kế thừa từ MQService. Bởi vì quá trình xử lý diễn ra thông qua các sự kiện, phương thức Run sẽ trả về ngay lập tức. Do đó, chúng ta cần cẩn thận không kết thúc chương trình ngay sau khi nó bắt đầu. Đối với các bài kiểm tra đơn giản của chúng tôi, tôi chỉ cần chèn một câu lệnh Console.ReadLine() sau lời gọi đến Run.
Việc triển khai cơ quan tín dụng tương tự như ngân hàng. Điểm khác biệt duy nhất là loại tin nhắn và logic kinh doanh. Cơ quan tín dụng có thể xử lý các loại tin nhắn sau:
public class CreditBureauRequest { public int SSN; } public class CreditBureauReply { public int SSN; public int CreditScore; public int HistoryLength; } Phương pháp ProcessMessage gần như giống hệt như mã ngân hàng, ngoại trừ nó xử lý các cấu trúc dữ liệu khác nhau và gọi logic ứng dụng khác nhau. Cục tín dụng cũng có một độ trễ được tích hợp sẵn.
private int getCreditScore(int ssn) { return (int)(random.Next(600) + 300); } private int getCreditHistoryLength(int ssn) { return (int)(random.Next(19) + 1); } Bây giờ chúng ta đã có một văn phòng tín dụng hoạt động và một lớp ngân hàng cho phép chúng ta tạo ra nhiều hình thái của một ngân hàng, chúng ta đã sẵn sàng làm việc trong thiết kế nội bộ của bên môi giới cho vay. Các mẫu định tuyến và chuyển đổi từ cuốn sách này giúp chúng ta phân đoạn các chức năng mà bên môi giới cho vay cần cung cấp. Chúng ta có thể nhóm các chức năng nội bộ của bên môi giới cho vay thành ba phần chính (xem hình): giao diện yêu cầu - phản hồi chấp nhận yêu cầu từ khách hàng, giao diện văn phòng tín dụng, và giao diện ngân hàng.
Cấu trúc nội bộ của môi giới vay vốn

Theo cách tương tự như việc xây dựng toàn bộ giải pháp theo thứ tự phụ thuộc ngược lại, hãy bắt đầu xây dựng các mảnh ghép chỉ phụ thuộc vào những gì đã có. Vì chúng ta vừa mới xây dựng một ngân hàng và dịch vụ cơ quan tín dụng, nên thật hợp lý khi tạo giao diện từ môi giới cho vay đến những thành phần bên ngoài này. Giao diện cơ quan tín dụng rõ ràng có vẻ đơn giản hơn, vì vậy hãy bắt đầu từ đó.
Người môi giới vay cần thực hiện các yêu cầu tới cơ quan tín dụng để lấy xếp hạng tín dụng của khách hàng, điều này là cần thiết cho ngân hàng. Điều này có nghĩa là gửi một thông điệp tới thành phần môi giới vay bên ngoài và nhận các thông điệp phản hồi. Việc bao bọc chi tiết gửi một thông điệp chung bên trong một Cổng Thông Điệp đã cho phép chúng tôi ẩn giấu nhiều chi tiết MSMQ khỏi phần còn lại của ứng dụng. Theo cùng lý do, chúng ta nên bao bọc việc gửi và nhận thông điệp tới cơ quan tín dụng bên trong một cổng cơ quan tín dụng. Cổng cơ quan tín dụng này thực hiện chức năng quan trọng của việc làm phong phú ngữ nghĩa, cho phép người môi giới vay gọi các phương thức như GetCreditScore thay vì SendMessage. Điều này làm cho mã của người môi giới vay trở nên dễ đọc hơn và cung cấp một sự bao bọc mạnh mẽ cho việc giao tiếp giữa người môi giới vay và cơ quan tín dụng. Sơ đồ sau đây minh họa các mức độ trừu tượng đạt được bằng cách "chuỗi" hai cổng này.
Người trung gian cho vay cung cấp một cấp độ trừu tượng bổ sung khỏi hạ tầng nhắn tin.

Để yêu cầu một điểm tín dụng, cổng cần tạo một thể hiện của cấu trúc CreditBureauRequest, như được chỉ định bởi cơ quan tín dụng. Tương tự, giao diện sẽ nhận kết quả bên trong một cấu trúc CreditBureauReply. Chúng ta đã đề cập trước đó rằng giải pháp được xây dựng từ các chương trình thực thi riêng biệt để cơ quan tín dụng có thể chạy trên một máy tính khác với nhà môi giới cho vay. Điều này có nghĩa là nhà môi giới cho vay có thể không có quyền truy cập vào các kiểu được định nghĩa trong assembly của cơ quan tín dụng, và thực ra, chúng ta không muốn nhà môi giới cho vay tham chiếu tới các thành phần bên trong của cơ quan tín dụng, vì điều đó sẽ loại bỏ những lợi ích của việc kết nối lỏng lẻo qua các hàng đợi tin nhắn. Nhà môi giới cho vay phải hoàn toàn không biết các dịch vụ thành phần mà yêu cầu điểm tín dụng. Tuy nhiên, nhà môi giới cần quyền truy cập vào các cấu trúc định nghĩa định dạng tin nhắn. May mắn thay, bộ SDK Microsoft .NET Framework chứa một công cụ cho phép chúng ta làm điều đó, Công cụ Định nghĩa Lược đồ XML (xsd.exe). Công cụ này có thể tạo các lược đồ XML từ một assembly và cũng có thể tạo mã nguồn C# từ các lược đồ XML. Hình dưới đây mô tả quy trình:
Tạo các stub lớp từ một assembly khác

`xsd.exe trích xuất định nghĩa kiểu công khai và tạo ra một tệp XML schema dựa trên định nghĩa kiểu và các thuộc tính tùy chọn kiểm soát việc tuần tự hóa. Trong trường hợp của chúng tôi, xsd.exe đã tạo ra sơ đồ sau:`
<?xml version="1.0" encoding="utf-8"?> <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="CreditBureauRequest" type="CreditBureauRequest" /> <xs:complexType name="CreditBureauRequest"> <xs:sequence> <xs:element minOccurs="1" maxOccurs="1" name="SSN" type="xs:int" /> </xs:sequence> </xs:complexType> <xs:element name="CreditBureauReply" type="CreditBureauReply" /> <xs:complexType name="CreditBureauReply"> <xs:sequence> <xs:element minOccurs="1" maxOccurs="1" name="SSN" type="xs:int" /> <xs:element minOccurs="1" maxOccurs="1" name="CreditScore" type="xs:int" /> <xs:element minOccurs="1" maxOccurs="1" name="HistoryLength" type="xs:int" /> </xs:sequence> </xs:complexType> <xs:element name="Run" nillable="true" type="Run" /> <xs:complexType name="Run" /> </xs:schema>
Thông thường, một dịch vụ sẽ công bố định nghĩa sơ đồ này cho các bên gọi tiềm năng. Điều này cho phép bên gọi lựa chọn sản xuất định dạng tin nhắn cần thiết theo nhiều cách khác nhau. Đầu tiên, bên gọi có thể xây dựng tin nhắn yêu cầu tuân thủ XSD một cách rõ ràng. Ngoài ra, bên gọi có thể sử dụng tính năng tuần tự hóa tích hợp sẵn của .NET. Trong trường hợp này, khách hàng vẫn có tùy chọn các ngôn ngữ lập trình khác nhau vì CLR của .NET không phụ thuộc vào ngôn ngữ lập trình.
Chúng tôi quyết định sử dụng chức năng tuần tự hóa tích hợp sẵn của .NET. Do đó, chúng tôi chạy lại xsd.exe để tạo các tệp nguồn sẽ được sử dụng bởi người tiêu dùng dịch vụ, và chúng tôi nhận được một tệp có hình dạng như sau:
// // This source code was auto-generated by xsd, Version=1.1.4322.573. // namespace CreditBureau { using System.Xml.Serialization; /// <remarks/> [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)] public class CreditBureauRequest { /// <remarks/> public int SSN; } ... } Cần lưu ý rằng việc tuần tự hóa và khôi phục tuần tự hóa XML của .NET cho phép sự ràng buộc lỏng lẻo. Về mặt kỹ thuật, tin nhắn yêu cầu mà chúng ta gửi đến văn phòng tín dụng không nhất thiết phải có cùng kiểu CLR chính xác như kiểu được sử dụng trong triển khai của văn phòng tín dụng miễn là đại diện XML chứa các phần tử cần thiết. Ví dụ, điều này cho phép một bên yêu cầu gửi một tin nhắn có đại diện XML chứa các phần tử bổ sung mà không làm gián đoạn giao tiếp. Trong ví dụ của chúng tôi, chúng tôi giả định rằng người môi giới vay sẵn sàng tuân thủ định dạng đã chỉ định của văn phòng tín dụng và sử dụng cùng loại dữ liệu ở cả hai đầu của giao tiếp.
Chúng tôi hiện đã sẵn sàng để gửi thông điệp theo định dạng chính xác đến cơ quan tín dụng. Tuy nhiên, chúng tôi cần ghi nhớ rằng, việc giao tiếp này là không đồng bộ với một thông điệp yêu cầu riêng biệt và một thông điệp phản hồi không đồng bộ. Chúng tôi có thể thiết kế cổng thông tin cơ quan tín dụng sao cho sau khi gửi yêu cầu, mã của cổng sẽ chờ cho đến khi phản hồi trở lại. Cách tiếp cận này có một nhược điểm đáng kể: Ứng dụng sẽ chỉ ngồi và chờ trong khi cơ quan tín dụng đang xử lý một thông điệp. Loại xử lý giả đồng bộ này có thể nhanh chóng dẫn đến một nút cổ chai về hiệu suất. Nếu chúng tôi thực hiện từng bước của quá trình thành giả đồng bộ, điều đó có nghĩa là nhà môi giới cho vay chỉ có thể xử lý một yêu cầu tại một thời điểm. Ví dụ, nó sẽ không thể yêu cầu điểm tín dụng cho một yêu cầu mới trong khi vẫn đang chờ phản hồi từ ngân hàng cho yêu cầu báo giá trước đó. Để hình dung sự khác biệt, hãy xem xét rằng nhà môi giới cho vay phải thực hiện hai bước chính: Lấy điểm tín dụng và lấy báo giá tốt nhất từ các ngân hàng. Nếu chúng ta giả định rằng nhà môi giới cho vay chỉ thực hiện một lần thực thi tuần tự duy nhất, quá trình thực thi sẽ giống như nửa phía trên của hình dưới đây:
Xử lý theo quy trình có thể cung cấp thông lượng cao hơn đáng kể.

Vì phần lớn công việc thực tế được thực hiện bởi các thành phần bên ngoài, nên thành phần môi giới cho vay chủ yếu chỉ ngồi chờ kết quả - đây không phải là cách sử dụng tài nguyên máy tính hiệu quả. Nếu chúng ta thiết kế toàn bộ quy trình môi giới cho vay dưới dạng Người tiêu dùng theo hướng sự kiện, chúng ta có thể bắt đầu xử lý nhiều yêu cầu song song và xử lý kết quả khi chúng đến. Chúng tôi gọi chế độ này là xử lý theo đường ống. Khả năng mở rộng của hệ thống giờ đây chỉ phụ thuộc vào khả năng xử lý của các thành phần bên ngoài và không phụ thuộc vào môi giới cho vay. Nếu chúng ta chỉ chạy một phiên bản duy nhất của quy trình văn phòng tín dụng, sự khác biệt có thể không rõ ràng vì hàng đợi yêu cầu của văn phòng sẽ tự động xếp hàng các yêu cầu. Tuy nhiên, nếu chúng ta quyết định chạy nhiều phiên bản văn phòng tín dụng song song, chúng ta sẽ thấy ngay lập tức sự cải thiện về hiệu suất (thông tin về hiệu suất sẽ được trình bày tiếp theo).
Có hai cách chính để biến quy trình môi giới cho vay thành hướng sự kiện. Chúng ta có thể tạo ra một quy trình tuần tự nhưng tạo ra một luồng mới cho mỗi tin nhắn yêu cầu đến. Ngoài ra, chúng ta có thể để hệ thống nhắn tin thông báo cho môi giới cho vay bất cứ khi nào có sự kiện đang chờ. Bằng cách này, chúng ta để cho hệ thống nhắn tin điều khiển các luồng thực thi. Mỗi cách tiếp cận đều có ưu và nhược điểm. Lập trình một quy trình tuần tự có thể làm cho mã dễ hiểu hơn; tuy nhiên, nếu thành phần của chúng ta chủ yếu là một thành phần môi giới mà môi giới tin nhắn giữa các thực thể bên ngoài, nó có thể dẫn đến một số lượng luồng lớn đang làm việc không có gì ngoài việc chờ đợi các tin nhắn đến. Những luồng này có thể tiêu tốn một số lượng lớn tài nguyên hệ thống mà không đạt được nhiều. Do đó, có thể chúng ta sẽ tốt hơn nếu để cho hệ thống nhắn tin điều khiển việc thực thi. Bất cứ khi nào một tin nhắn sẵn sàng để được tiêu thụ, hệ thống sẽ gọi đến việc thực thi của môi giới. Điều này cho phép chúng ta duy trì một luồng duy nhất của việc thực thi và không phải lo lắng về việc quản lý luồng. Tuy nhiên, chúng ta cần xử lý thực tế rằng đường đi thực thi không phải là một phương thức tuần tự duy nhất, mà là nhiều đoạn mã được thực thi khi các tin nhắn đến.
Bạn có thể đã đoán rằng cách để làm cho mọi thứ trở nên dựa trên sự kiện trong .NET là sử dụng delegate. Như mong đợi, cổng thông tin tín dụng định nghĩa một delegate mới.
public delegate void OnCreditReplyEvent(CreditBureauReply creditReply, Object ACT);
Giao thức này cho phép các đoạn mã khác thông báo cho cổng thông tin tín dụng phương thức nào sẽ được gọi khi có kết quả. Cổng thông tin tín dụng sẽ trả lại một cấu trúc CreditBureauReply được xác định đúng loại cho người gọi. Nó cũng truyền một cái gì đó mà chúng tôi gọi là ACT - Mã Hoàn Thành Không Đồng Bộ [POSA2]. Mã này cho phép người gọi truyền dữ liệu vào cổng và nhận lại dữ liệu khi thông điệp trả lời tương ứng đến (xem Cổng Thông Tin Nhắn). Cơ bản, cổng thông tin tín dụng thực hiện việc tương quan cho các thông điệp yêu cầu và trả lời để người gọi không cần phải làm điều đó.
Những gì còn lại là một phương pháp để yêu cầu điểm tín dụng và một phương pháp xử lý tin nhắn trả lời đến, liên kết ACT phù hợp và gọi đến đại lý được nhập đúng cách.
internal struct CreditRequestProcess { public int CorrelationID; public Object ACT; public OnCreditReplyEvent callback; } internal class CreditBureauGateway { protected IMessageSender creditRequestQueue; protected IMessageReceiver creditReplyQueue; protected IDictionary activeProcesses = (IDictionary)(new Hashtable()); protected Random random = new Random(); public void Listen() { creditReplyQueue.Begin(); } public void GetCreditScore(CreditBureauRequest quoteRequest, OnCreditReplyEvent OnCreditResponse, Object ACT) { Message requestMessage = new Message(quoteRequest); requestMessage.ResponseQueue = creditReplyQueue.GetQueue(); requestMessage.AppSpecific = random.Next(); CreditRequestProcess processInstance = new CreditRequestProcess(); processInstance.ACT = ACT; processInstance.callback = OnCreditResponse; processInstance.CorrelationID = requestMessage.AppSpecific; creditRequestQueue.Send(requestMessage); activeProcesses.Add(processInstance.CorrelationID, processInstance); } private void OnCreditResponse(Message msg) { msg.Formatter = GetFormatter(); CreditBureauReply replyStruct; try { if (msg.Body is CreditBureauReply) { replyStruct = (CreditBureauReply)msg.Body; int CorrelationID = msg.AppSpecific; if (activeProcesses.Contains(CorrelationID)) { CreditRequestProcess processInstance = (CreditRequestProcess)(activeProcesses[CorrelationID]); processInstance.callback(replyStruct, processInstance.ACT); activeProcesses.Remove(CorrelationID); } else { Console.WriteLine ("Incoming credit response does not match any request"); } } else { Console.WriteLine("Illegal reply."); } } catch (Exception e) { Console.WriteLine("Exception: {0}", e.ToString()); } } } Khi một người gọi yêu cầu một điểm tín dụng qua phương thức GetCreditScore, cổng thông tin tín dụng sẽ phân bổ một instance mới của cấu trúc CreditRequestProcess. Bộ sưu tập activeProcesses chứa một instance của CreditRequestProcess cho mỗi yêu cầu còn tồn đọng, được khóa bởi Correlation Identifier của tin nhắn. Cấu trúc này cũng lưu trữ delegate cho sự kiện OnCreditReplyEvent. Việc lưu trữ delegate cho mỗi tin nhắn cho phép mỗi người gọi chỉ định một vị trí callback khác nhau cho mỗi yêu cầu. Như chúng ta sẽ thấy sau này, điều này cho phép người gọi sử dụng delegate để quản lý trạng thái cuộc trò chuyện.
Điều quan trọng là chúng tôi không sử dụng trường ID tin nhắn tích hợp sẵn của tin nhắn để tương quan. Thay vào đó, chúng tôi gán một số nguyên ngẫu nhiên cho trường AppSpecific và tương quan các tin nhắn đến bằng giá trị của trường đó (hãy nhớ rằng chúng tôi đã thiết kế RequestReplyService để sao chép cả trường ID và trường AppSpecific vào tin nhắn phản hồi). Tại sao chúng ta muốn tương quan bằng một cái gì đó khác ngoài ID tin nhắn? Lợi thế của ID tin nhắn là nó là duy nhất cho mỗi tin nhắn trong hệ thống. Nhưng điều đó cũng hạn chế tính linh hoạt của chúng tôi. Việc yêu cầu một tin nhắn phản hồi phải tương quan với ID tin nhắn của tin nhắn yêu cầu không cho phép chúng tôi chèn các bước trung gian (ví dụ, một bộ định tuyến) vào luồng tin nhắn. Vì bất kỳ bước trung gian nào cũng sẽ tiêu thụ tin nhắn yêu cầu và công bố một tin nhắn mới đến dịch vụ, nên CorrelationId của tin nhắn phản hồi sẽ khớp với tin nhắn mà dịch vụ nhận được nhưng không khớp với tin nhắn mà nhà môi giới cho vay ban đầu đã gửi (xem hình).
"Các trung gian cản trở mối tương quan với các ID tin nhắn được hệ thống sinh ra"

Có hai giải pháp cho vấn đề này. Đầu tiên, bất kỳ trung gian nào cũng sẽ được yêu cầu phải chặn cả tin nhắn yêu cầu và phản hồi và phải trang bị cho các tin nhắn phản hồi giá trị CorrelationId chính xác (để biết ví dụ về cách tiếp cận này, hãy xem Smart Proxy [xxx]). Ngoài ra, chúng ta có thể sử dụng một trường riêng biệt cho mục đích tương quan để tất cả các tin nhắn liên quan đi qua trung gian và dịch vụ đều mang cùng một Định danh Tương quan. Trong ví dụ này, chúng ta đã chọn cách tiếp cận thứ hai để tiện lợi hơn cho một thành phần trung gian trong việc chặn tin nhắn yêu cầu giữa môi giới cho vay và văn phòng tín dụng (chúng ta sẽ tận dụng điều này trong Chương 12, "Giai đoạn: Ví dụ về Quản lý Hệ thống"). Chúng ta nên chọn giá trị như thế nào cho thuộc tính AppSpecific? Chúng ta có thể sử dụng các giá trị tuần tự, nhưng sau đó chúng ta phải cẩn thận để hai phiên bản đồng thời không sử dụng cùng một giá trị khởi đầu. Chúng ta cũng có thể sử dụng một mô-đun tạo ID trung tâm (ví dụ: một cơ sở dữ liệu) đảm bảo tính duy nhất trong toàn hệ thống. Điều này có vẻ hơi rắc rối cho ví dụ đơn giản này, vì vậy chúng ta đã chọn một số ngẫu nhiên. .NET tạo ra các số ngẫu nhiên dưới dạng số nguyên 32 bit có dấu, vì vậy xác suất xuất hiện trùng lặp là 1 trên 2 tỷ, rủi ro mà chúng ta sẵn sàng chấp nhận.
Cổng thông tin tín dụng giờ đây cung cấp sự trừu tượng sạch sẽ khỏi hạ tầng hàng đợi tin nhắn Windows mà chúng tôi đã hướng tới. Giao diện công khai duy nhất vào cổng thông tin tín dụng (ngoài các bộ tạo) là một delegate và hai phương thức:
delegate void OnCreditReplyEvent(CreditBureauReply creditReply, Object ACT); class CreditBureauGateway { void Listen() {...} void GetCreditScore(CreditBureauRequest quoteRequest, OnCreditReplyEvent OnCreditResponse, Object ACT) {...} ... } Cả hai cấu trúc đều không đề cập đến một thông điệp hay hàng đợi thông điệp. Điều này mang lại một số lợi ích. Đầu tiên, chúng ta có thể dễ dàng triển khai một phiên bản giả lập của cổng thông tin tín dụng mà không phụ thuộc vào hàng đợi thông điệp (tương tự như MockQueue). Thứ hai, chúng ta có thể thay thế triển khai của cổng thông tin tín dụng nếu chúng ta quyết định sử dụng một phương thức vận chuyển khác với MSMQ. Ví dụ, nếu chúng ta định sử dụng một giao diện dịch vụ web sử dụng SOAP và HTTP thay vì MSMQ, các phương thức được cung cấp bởi cổng thông tin có lẽ sẽ không phải thay đổi gì cả.
Thiết kế của cổng ngân hàng tuân theo các nguyên tắc tương tự như thiết kế của cổng cơ quan tín dụng. Chúng tôi sử dụng cùng một quy trình như trước để khai báo các stub cho các loại thông điệp yêu cầu và phản hồi được chỉ định bởi ngân hàng. Phần bên ngoài của cổng ngân hàng rất giống với cổng cơ quan tín dụng:
delegate void OnBestQuoteEvent(BankQuoteReply bestQuote, Object ACT); class BankGateway { void Listen() {...} void GetBestQuote(BankQuoteRequest quoteRequest, OnBestQuoteEvent onBestQuoteEvent, Object ACT) {...} ... } Cách hoạt động nội bộ phức tạp hơn một chút vì kiểu tương tác Scatter-Gather chuyển một yêu cầu BankQuote đến nhiều ngân hàng. Tương tự, một BankQuoteReply đơn lẻ thường là kết quả của nhiều thông điệp phản hồi báo giá từ ngân hàng. Phần đầu tiên được xử lý bởi Danh sách Người nhận, trong khi phần sau được xử lý bởi một Bộ tổng hợp. Hãy bắt đầu với Danh sách Người nhận. Nó phải thực hiện ba chức năng chính:
Tính toán các người nhận phù hợp
Gửi tin nhắn đến các người nhận
Khởi tạo Bộ tổng hợp để xử lý các phản hồi đến
Như đã mô tả trong phần giới thiệu của chương này, việc triển khai này sử dụng phong cách phân phối Scatter-Gather, chủ động xác định ngân hàng nào để chuyển hướng yêu cầu đến. Cách tiếp cận này hợp lý về mặt kinh doanh nếu các ngân hàng tính phí môi giới cho mỗi báo giá hoặc nếu ngân hàng và môi giới có thỏa thuận yêu cầu môi giới phải tiền kiểm tra các đầu mối khách hàng mà họ tạo ra. Người môi giới cho vay đưa ra quyết định định tuyến dựa trên điểm tín dụng của khách hàng, số tiền vay và thời gian lịch sử tín dụng. Chúng tôi đóng gói mỗi kết nối đến một ngân hàng bên trong một lớp kế thừa từ lớp trừu tượng BankConnection. Lớp này chứa một tham chiếu đến hàng đợi tin nhắn được địa chỉ đúng và một phương thức CanHandleLoanRequest xác định xem yêu cầu báo giá có nên được chuyển tiếp đến ngân hàng này hay không. BankConnectionManager đơn giản lặp qua danh sách tất cả các kết nối ngân hàng và tổng hợp danh sách những kết nối phù hợp với tiêu chí của báo giá vay. Nếu danh sách các ngân hàng dài hơn, chúng tôi có thể xem xét việc triển khai một động cơ quy tắc có thể cấu hình. Chúng tôi thích cách tiếp cận hiện tại vì nó đơn giản và rõ ràng.
internal class BankConnectionManager { static protected BankConnection[] banks = {new Bank1(), new Bank2(), new Bank3(), new Bank4(), new Bank5() }; public IMessageSender[] GetEligibleBankQueues (int CreditScore, int HistoryLength, int LoanAmount) { ArrayList lenders = new ArrayList(); for (int index = 0; index < banks.Length; index++) { if (banks[index].CanHandleLoanRequest(CreditScore, HistoryLength, LoanAmount)) lenders.Add(banks[index].Queue); } IMessageSender[] lenderArray = (IMessageSender [])Array.CreateInstance (typeof(IMessageSender), lenders.Count); lenders.CopyTo(lenderArray); return lenderArray; } } internal abstract class BankConnection { protected MessageSenderGateway queue; protected String bankName = ""; public MessageSenderGateway Queue { get { return queue; } } public String BankName { get { return bankName; } } public BankConnection (MessageQueue queue) { this.queue = new MessageSenderGateway(queue); } public BankConnection (String queueName) { this.queue = new MessageSenderGateway(queueName); } public abstract bool CanHandleLoanRequest(int CreditScore, int HistoryLength, int LoanAmount); } internal class Bank1 : BankConnection { protected String bankname = "Exclusive Country Club Bankers"; public Bank1 () : base (".\\private$\\bank1Queue") {} public override bool CanHandleLoanRequest(int CreditScore, int HistoryLength, int LoanAmount) { return LoanAmount >= 75000 && CreditScore >= 600 && HistoryLength >= 8; } } ... Một khi danh sách các ngân hàng liên quan đã được biên soạn, việc gửi tin nhắn chỉ là một vấn đề đơn giản là lặp lại qua danh sách. Trong một ứng dụng thực tế, việc lặp này nên diễn ra trong một giao dịch duy nhất để tránh các điều kiện lỗi mà trong đó một tin nhắn có thể được gửi đến một số ngân hàng nhưng không đến những ngân hàng khác. Một lần nữa, chúng tôi quyết định để sự đơn giản chiến thắng cho ví dụ này.
internal class MessageRouter { public static void SendToRecipientList (Message msg, IMessageSender[] recipientList) { IEnumerator e = recipientList.GetEnumerator(); while (e.MoveNext()) { ((IMessageSender)e.Current).Send(msg); } } } Bây giờ, khi các thông điệp yêu cầu đang trên đường đến các ngân hàng, chúng ta cần khởi tạo Aggregator để chuẩn bị tiếp nhận các báo giá từ ngân hàng. Do tính chất hướng sự kiện của môi giới cho vay, aggregator cần sẵn sàng làm việc với nhiều phần tổng hợp đồng thời, duy trì một phần tổng hợp hoạt động cho mỗi yêu cầu báo giá đang chờ. Điều này có nghĩa là các thông điệp đến cần phải được tương quan độc đáo với một phần tổng hợp cụ thể. Thật không may, chúng ta không thể sử dụng ID thông điệp làm định danh tương quan vì Danh sách Người nhận cần gửi các thông điệp riêng lẻ đến mỗi ngân hàng. Kết quả là, nếu ba ngân hàng tham gia vào một yêu cầu báo giá, Danh sách Người nhận cần gửi ba thông điệp duy nhất, mỗi thông điệp đến một ngân hàng. Mỗi thông điệp này sẽ có một ID thông điệp duy nhất, vì vậy nếu các ngân hàng tương quan bằng ID thông điệp, ba phản hồi sẽ có các ID tương quan khác nhau mặc dù chúng thuộc về cùng một phần tổng hợp. Điều này sẽ khiến việc xác định các thông điệp liên quan trở nên không thể thực hiện đối với aggregator. Chúng ta có thể để phần tổng hợp lưu trữ ID thông điệp cho mỗi thông điệp yêu cầu và do đó tương quan ID tương quan của thông điệp đến trở lại phần tổng hợp. Tuy nhiên, điều này phức tạp hơn mức cần thiết. Thay vào đó, chúng ta chỉ cần tạo ra các ID tương quan của riêng mình - một cho mỗi phần tổng hợp thay vì một cho mỗi thông điệp. Chúng ta lưu trữ ID (số) này trong thuộc tính AppSpecific của các thông điệp yêu cầu đi ra. Các ngân hàng kế thừa từ RequestReplyService, cái đã chuyển giao thuộc tính AppSpecific của thông điệp đến cho các thông điệp phản hồi. Khi một thông điệp báo giá đến từ một ngân hàng, BankGateway có thể dễ dàng tương quan thông điệp đến bằng thuộc tính AppSpecific của thông điệp (xem hình).
Ngân hàng Gateway sử dụng thuộc tính thông điệp cụ thể của ứng dụng để tương quan các thông điệp phản hồi với các tập hợp.

Cổng ngân hàng khởi tạo một tập hợp với ID tập hợp (được tạo ra bởi một bộ đếm đơn giản) và số lượng tin nhắn dự kiến. Ngoài ra, người gọi cần cung cấp một ủy quyền và có thể chọn để chỉ định một tham chiếu đối tượng tới ACT theo cách mà chức năng cổng thông tin tín dụng hoạt động. Chiến lược tập hợp là đơn giản. Tập hợp được coi là hoàn chỉnh khi tất cả các ngân hàng được chọn đã phản hồi bằng một tin nhắn trả lời. Danh sách Người nhận khởi tạo tập hợp với số lượng tin nhắn dự kiến. Hãy nhớ rằng các ngân hàng có tùy chọn từ chối cung cấp báo giá. Để chúng tôi biết khi nào một tập hợp hoàn chỉnh, chúng tôi yêu cầu các ngân hàng cung cấp một tin nhắn trả lời với mã lỗi được thiết lập nếu họ không muốn cung cấp báo giá. Chúng tôi có thể dễ dàng điều chỉnh chiến lược tập hợp, ví dụ, để cắt đứt quá trình đấu thầu sau 1 giây và lấy phản hồi tốt nhất cho đến thời điểm đó.
internal class BankQuoteAggregate { protected int ID; protected int expectedMessages; protected Object ACT; protected OnBestQuoteEvent callback; protected double bestRate = 0.0; protected ArrayList receivedMessages = new ArrayList(); protected BankQuoteReply bestReply = null; public BankQuoteAggregate(int ID, int expectedMessages, OnBestQuoteEvent callback, Object ACT) { this.ID = ID; this.expectedMessages = expectedMessages; this.callback = callback; this.ACT = ACT; } public void AddMessage(BankQuoteReply reply) { if (reply.ErrorCode == 0) { if (bestReply == null) { bestReply = reply; } else { if (reply.InterestRate < bestReply.InterestRate) { bestReply = reply; } } } receivedMessages.Add(reply); } public bool IsComplete() { return receivedMessages.Count == expectedMessages; } public BankQuoteReply getBestResult() { return bestReply; } public void NotifyBestResult() { if (callback != null) { callback(bestReply, ACT); } } } Được trang bị với quản lý kết nối ngân hàng, danh sách người nhận và tổng hợp, việc triển khai các chức năng của BankGateway trở nên tương đối đơn giản.
internal class BankGateway { protected IMessageReceiver bankReplyQueue; protected BankConnectionManager connectionManager; protected IDictionary aggregateBuffer = (IDictionary)(new Hashtable()); protected int aggregationCorrelationID; public void Listen() { bankReplyQueue.Begin(); } public void GetBestQuote(BankQuoteRequest quoteRequest, OnBestQuoteEvent onBestQuoteEvent, Object ACT) { Message requestMessage = new Message(quoteRequest); requestMessage.AppSpecific = aggregationCorrelationID; requestMessage.ResponseQueue = bankReplyQueue.GetQueue(); IMessageSender[] eligibleBanks = connectionManager.GetEligibleBankQueues(quoteRequest.CreditScore, quoteRequest.HistoryLength, quoteRequest.LoanAmount); aggregateBuffer.Add(aggregationCorrelationID, new BankQuoteAggregate(aggregationCorrelationID, eligibleBanks.Length, onBestQuoteEvent, ACT)); aggregationCorrelationID++; MessageRouter.SendToRecipientList(requestMessage, eligibleBanks); } private void OnBankMessage(Message msg) { msg.Formatter = GetFormatter(); BankQuoteReply replyStruct; try { if (msg.Body is BankQuoteReply) { replyStruct = (BankQuoteReply)msg.Body; int aggregationCorrelationID = msg.AppSpecific; Console.WriteLine("Quote {0:0.00}% {1} {2}", replyStruct.InterestRate, replyStruct.QuoteID, replyStruct.ErrorCode); if (aggregateBuffer.Contains(aggregationCorrelationID)) { BankQuoteAggregate aggregate = (BankQuoteAggregate)(aggregateBuffer[aggregationCorrelationID]); aggregate.AddMessage(replyStruct); if (aggregate.IsComplete()) { aggregate.NotifyBestResult(); aggregateBuffer.Remove(aggregationCorrelationID); } } else { Console.WriteLine("Incoming bank response does not match any
aggregate"); } } else { Console.WriteLine("Illegal request."); } } catch (Exception e) { Console.WriteLine("Exception: {0}", e.ToString()); } } } Khi cổng ngân hàng nhận được phản hồi báo giá từ một ngân hàng, phương thức OnBankMessage sẽ được thực thi. Phương thức này chuyển đổi tin nhắn đến thành loại đúng và tiếp tục tìm vị trí của tổng hợp liên quan thông qua thuộc tính AppSpecific. Nó thêm yêu cầu mới vào tổng hợp. Khi tổng hợp hoàn thành (như được định nghĩa trong lớp BankQuoteAggregate), cổng ngân hàng gọi đến đại diện được cung cấp bởi người gọi.
Giờ đây, khi chúng ta đã có một cổng thông tin tín dụng và cổng thông tin ngân hàng được đóng gói tốt, chúng ta sẵn sàng để người môi giới cho vay chấp nhận các yêu cầu. Trước đó, chúng ta đã bàn về thiết kế của các lớp cơ sở MQService và AsyncRequestReplyService. Lớp LoanBroker kế thừa từ AsyncRequestReplyService vì nó không thể gửi kết quả trở lại hàng đợi phản hồi ngay lập tức, mà chỉ sau khi hoàn thành một số hoạt động bất đồng bộ khác (thu thập thông tin tín dụng và giao tiếp với các ngân hàng).
Bước đầu tiên trong việc triển khai LoanBroker là xác định các loại tin nhắn mà loan broker xử lý:
public struct LoanQuoteRequest { public int SSN; public double LoanAmount; public int LoanTerm; } public struct LoanQuoteReply { public int SSN; public double LoanAmount; public double InterestRate; public string QuoteID; } Tiếp theo, chúng ta tạo một lớp kế thừa từ AsyncRequestReplyService và ghi đè phương thức ProcessMessage.
Người môi giới vay khác với các lớp trước vì quy trình được kích hoạt bởi một tin nhắn đến không nằm trong bất kỳ phương thức nào đơn lẻ. Thay vào đó, việc hoàn thành quy trình phụ thuộc vào một chuỗi các sự kiện bên ngoài. Người môi giới vay có thể nhận ba loại sự kiện:
Một tin nhắn yêu cầu vay mới đã đến.
Một tin nhắn phản hồi điểm tín dụng đến (qua Cổng thông tin của Cục Tín dụng).
Một tin nhắn báo giá ngân hàng đến (qua BankGateway).
Vì logic cho môi giới khoản vay được phân bổ qua nhiều trình xử lý sự kiện, chúng ta cần giữ trạng thái của môi giới qua các hàm này. Đó là lý do tại sao các mã hoàn thành bất đồng bộ xuất hiện! Hãy nhớ rằng cổng thông tin bureau tín dụng và cổng ngân hàng cho phép người gọi (môi giới khoản vay) truyền tham chiếu đến một thể hiện đối tượng khi gửi yêu cầu. Cổng thông tin sẽ trả tham chiếu đối tượng lại khi nhận được tin nhắn phản hồi. Để tận dụng chức năng này, chúng ta sẽ khai báo một ACT trong môi giới khoản vay như sau:
internal class ACT { public LoanQuoteRequest loanRequest; public Message message; public ACT(LoanQuoteRequest loanRequest, Message message) { this.loanRequest = loanRequest; this.message = message; } } ACT chứa một bản sao của tin nhắn yêu cầu gốc (bao gồm ID tin nhắn và địa chỉ phản hồi cần thiết để tạo tin nhắn phản hồi) và cấu trúc dữ liệu yêu cầu (cần thiết để sao chép SSN và số tiền vay vào tin nhắn phản hồi). Về mặt kỹ thuật, ACT lưu trữ một lượng nhỏ thông tin trùng lặp vì chúng tôi có thể trích xuất nội dung của cấu trúc yêu cầu từ tin nhắn yêu cầu. Tuy nhiên, sự tiện lợi khi truy cập vào một cấu trúc có kiểu dữ liệu chặt chẽ đáng giá cho vài byte dư thêm.
Phần còn lại của người môi giới cho vay được thực hiện như sau:
internal class LoanBroker : AsyncRequestReplyService { protected ICreditBureauGateway creditBureauInterface; protected BankGateway bankInterface; public LoanBroker(String requestQueueName, String creditRequestQueueName, String creditReplyQueueName, String bankReplyQueueName, BankConnectionManager connectionManager): base(requestQueueName) { creditBureauInterface = (ICreditBureauGateway) (new CreditBureauGatewayImp(creditRequestQueueName, creditReplyQueueName)); creditBureauInterface.Listen(); bankInterface = new BankGateway(bankReplyQueueName, connectionManager); bankInterface.Listen(); } protected override Type GetRequestBodyType() { return typeof(LoanQuoteRequest); } protected override void ProcessMessage(Object o, Message msg) { LoanQuoteRequest quoteRequest; quoteRequest = (LoanQuoteRequest)o; CreditBureauRequest creditRequest = LoanBrokerTranslator.GetCreditBureaurequest(quoteRequest); ACT act = new ACT(quoteRequest, msg); creditBureauInterface.GetCreditScore(creditRequest, new OnCreditReplyEvent(OnCreditReply), act); } private void OnCreditReply(CreditBureauReply creditReply, Object act) { ACT myAct = (ACT)act; Console.WriteLine("Received Credit Score -- SSN {0} Score {1} Length {2}", creditReply.SSN, creditReply.CreditScore, creditReply.HistoryLength); BankQuoteRequest bankRequest = LoanBrokerTranslator.GetBankQuoteRequest(myAct.loanRequest ,creditReply); bankInterface.GetBestQuote(bankRequest, new OnBestQuoteEvent(OnBestQuote), act); } private void OnBestQuote(BankQuoteReply bestQuote, Object act) { ACT myAct = (ACT)act; LoanQuoteReply quoteReply = LoanBrokerTranslator.GetLoanQuoteReply (myAct.loanRequest, bestQuote); Console.WriteLine("Best quote {0} {1}", quoteReply.InterestRate, quoteReply.QuoteID); SendReply(quoteReply, myAct.message); } } `LoanBroker kế thừa từ AsyncRequestReplyService, cung cấp hỗ trợ cho việc nhận các yêu cầu và gửi các phản hồi tương ứng. LoanBroker ghi đè phương thức ProcessMessage để xử lý các thông điệp yêu cầu đến. ProcessMessage tạo một thể hiện mới của ACT và gọi cổng thông tin của công ty tín dụng để yêu cầu một điểm tín dụng. Thú vị thay, phương thức kết thúc ở đây. Việc xử lý tiếp tục khi cổng thông tin của công ty tín dụng gọi phương thức OnCreditReply, đại biểu được chỉ định bởi phương thức ProcessMessage. Phương thức này sử dụng ACT và phản hồi từ công ty tín dụng để tạo yêu cầu báo giá ngân hàng và gọi cổng ngân hàng để gửi các thông điệp yêu cầu. Lần này, nó chỉ định phương thức OnBestQuote làm đại biểu hồi lại. Khi cổng ngân hàng nhận tất cả các phản hồi báo giá từ ngân hàng, nó gọi phương thức này qua đại biểu và trả lại thể hiện của ACT. OnBestQuote sử dụng báo giá ngân hàng và ACT để tạo một phản hồi cho khách hàng và gửi đi bằng cách sử dụng triển khai lớp cơ sở của SendReply.`
Một lớp mà bạn có thể đã chú ý trong mã nguồn là LoanBrokerTranslator. Lớp này cung cấp một vài phương thức tĩnh giúp chuyển đổi giữa các định dạng tin nhắn khác nhau.
Lớp LoanBroker minh họa sự đánh đổi mà chúng tôi đã thực hiện trong thiết kế của mình. Mã nguồn không có tham chiếu nào đến thông điệp hoặc các khái niệm liên quan đến luồng (ngoại trừ việc kế thừa từ AsyncRequestReplyService), điều này làm cho mã rất dễ đọc. Tuy nhiên, việc thực thi hàm chính được phân bổ qua ba phương thức mà không có tham chiếu trực tiếp nào đến nhau, ngoài các delegate. Điều này có thể làm cho dòng chảy thực thi trở nên khó hiểu nếu không xem xét tổng thể giải pháp, bao gồm tất cả các thành phần bên ngoài.
Khi chúng ta xem xét cách mà môi giới cho vay hoạt động, chúng ta nhận ra rằng chúng ta đang tách biệt dữ liệu và chức năng. Chúng ta có một thể hiện của lớp LoanBroker mô phỏng nhiều thể hiện thông qua bộ sưu tập ACT. Mặc dù ACT rất hữu ích, nhưng chúng dường như đi ngược lại tinh thần của lập trình hướng đối tượng bằng cách tách biệt dữ liệu và chức năng - hai phần cấu thành nên một đối tượng. Tuy nhiên, chúng ta có thể tái cấu trúc lớp LoanBroker để tránh việc tra cứu lặp lại ACT nếu chúng ta sử dụng các delegate theo cách tốt hơn. Delegate về cơ bản là các con trỏ hàm an toàn kiểu. Do đó, chúng trỏ đến một thể hiện đối tượng cụ thể. Vì vậy, thay vì cung cấp cho cục tín dụng và cổng ngân hàng một tham chiếu đến một phương thức trong thể hiện LoanBroker duy nhất, chúng ta có thể sử dụng các delegate để trỏ đến một thể hiện cụ thể của một "đối tượng quy trình" duy trì trạng thái hiện tại, giống như một ACT, nhưng cũng chứa logic của quy trình môi giới cho vay. Để làm điều này, chúng ta biến ACT thành một lớp mới gọi là LoanBrokerProcess và chuyển các chức năng xử lý thông điệp vào lớp này.
internal class LoanBrokerProcess { protected LoanBrokerPM broker; protected String processID; protected LoanQuoteRequest loanRequest; protected Message message; protected CreditBureauGateway creditBureauGateway; protected BankGateway bankInterface; public LoanBrokerProcess(LoanBrokerPM broker, String processID, CreditBureauGateway creditBureauGateway, BankGateway bankGateway, LoanQuoteRequest loanRequest, Message msg) { this.broker = broker; this.creditBureauGateway = broker.CreditBureauGateway; this.bankInterface = broker.BankInterface; this.processID = processID; this.loanRequest = loanRequest; this.message = msg; CreditBureauRequest creditRequest = LoanBrokerTranslator.GetCreditBureaurequest(loanRequest); creditBureauGateway.GetCreditScore(creditRequest, new OnCreditReplyEvent(OnCreditReply), null); } private void OnCreditReply(CreditBureauReply creditReply, Object act) { Console.WriteLine("Received Credit Score -- SSN {0} Score {1} Length {2}", creditReply.SSN, creditReply.CreditScore, creditReply.HistoryLength); BankQuoteRequest bankRequest = LoanBrokerTranslator.GetBankQuoteRequest(loanRequest, creditReply); bankInterface.GetBestQuote(bankRequest, new OnBestQuoteEvent(OnBestQuote), null); } private void OnBestQuote(BankQuoteReply bestQuote, Object act) { LoanQuoteReply quoteReply = LoanBrokerTranslator.GetLoanQuoteReply (loanRequest, bestQuote); Console.WriteLine("Best quote {0} {1}", quoteReply.InterestRate, quoteReply.QuoteID); broker.SendReply(quoteReply, message); broker.OnProcessComplete(processID); } } Phương thức không còn tham chiếu đến tham số ACT do cục tín dụng và cổng ngân hàng cung cấp vì tất cả thông tin cần thiết được lưu trữ trong instance của LoanBrokerProcess. Khi quá trình hoàn tất, nó gửi tin nhắn phản hồi bằng phương thức SendReply mà LoanBrokerPM kế thừa từ AsyncRequestReplyService. Tiếp theo, nó thông báo cho LoanBrokerPM về việc hoàn thành quá trình. Chúng tôi có thể đã thực hiện thông báo này bằng cách sử dụng một delegate, nhưng chúng tôi quyết định sử dụng một tham chiếu đến broker thay vào đó.
Sử dụng lớp LoanBrokerProcess đơn giản hóa lớp môi giới cho vay chính.
internal class LoanBrokerPM : AsyncRequestReplyService { protected CreditBureauGateway creditBureauGateway; protected BankGateway bankInterface; protected IDictionary activeProcesses = (IDictionary)(new Hashtable()); public LoanBrokerPM(String requestQueueName, String creditRequestQueueName, String creditReplyQueueName, String bankReplyQueueName, BankConnectionManager connectionManager): base(requestQueueName) { creditBureauGateway = new CreditBureauGateway(creditRequestQueueName, creditReplyQueueName); creditBureauGateway.Listen(); bankInterface = new BankGateway(bankReplyQueueName, connectionManager); bankInterface.Listen(); } protected override Type GetRequestBodyType() { return typeof(LoanQuoteRequest); } protected override void ProcessMessage(Object o, Message message) { LoanQuoteRequest quoteRequest; quoteRequest = (LoanQuoteRequest)o; String processID = message.Id; LoanBrokerProcess newProcess = new LoanBrokerProcess(this, processID, creditBureauGateway, bankInterface, quoteRequest, message); activeProcesses.Add(processID, newProcess); } public void OnProcessComplete(String processID) { activeProcesses.Remove(processID); } } `LoanBrokerPM này về cơ bản là một triển khai tổng quát của một Quản lý Quy trình. Nó tạo ra một phiên bản quy trình mới khi một thông điệp mới đến. Khi một quy trình hoàn thành, quản lý quy trình sẽ xóa phiên bản quy trình khỏi danh sách các quy trình đang hoạt động. Quản lý quy trình sử dụng ID thông điệp như là ID quy trình duy nhất được gán cho mỗi phiên bản quy trình. Chúng ta có thể thay đổi hành vi của trung gian cho vay chỉ bằng cách chỉnh sửa lớp LoanBrokerProcess, lớp này không có bất kỳ tham chiếu nào đến việc truyền thông ngoại trừ việc chuyển các đối tượng thông điệp xung quanh. Có vẻ như việc chú ý đến việc đóng gói hợp lý và tái cấu trúc đã có kết quả. Sơ đồ lớp sau đây tóm tắt cấu trúc bên trong của trung gian cho vay:`
Sơ đồ lớp môi giới vay vốn

Mảnh ghép duy nhất còn lại là client kiểm tra. Thiết kế client kiểm tra tương tự như của cổng thông tin bureau tín dụng. Client kiểm tra có thể thực hiện một số lượng yêu cầu lặp lại nhất định và tương quan các phản hồi đến từ với các yêu cầu còn lại. Khi chúng ta bắt đầu tất cả các quy trình (các ngân hàng, bureau tín dụng và nhà môi giới cho vay), chúng ta có thể thực hiện ví dụ. Chúng ta sử dụng một số lớp chính đơn giản để khởi động các thành phần tương ứng như các ứng dụng console. Chúng ta thấy sự hoạt động nhộn nhịp trên màn hình, cho thấy dòng chảy của các tin nhắn qua hệ thống (xem hình).
Chạy ví dụ MSMQ

Bây giờ chúng ta đã có giải pháp hoàn chỉnh đang hoạt động, chúng ta có thể thu thập một số chỉ số hiệu suất để so sánh thông lượng của giải pháp bất đồng bộ với giải pháp đồng bộ. Sử dụng trình tạo dữ liệu thử nghiệm, chúng ta gửi 50 yêu cầu được tạo ra ngẫu nhiên đến trung gian cho vay. Trình tạo dữ liệu thử nghiệm báo cáo rằng mất 33 giây để nhận được 50 tin nhắn phản hồi.
Gửi 50 yêu cầu báo giá

Thật cám dỗ khi nghĩ rằng mỗi yêu cầu mất 33/50 = 0,6 giây. Sai rồi! Tốc độ xử lý của môi giới cho vay là 50 yêu cầu trong 33 giây, nhưng một số yêu cầu đã mất 27 giây để hoàn thành. Tại sao hệ thống lại chậm như vậy? Hãy cùng xem xét một bức tranh tĩnh của hàng đợi tin nhắn trong quá trình thử nghiệm:
31 tin nhắn đang chờ trong hàng đợi yêu cầu tín dụng

Có ba mươi mốt thông điệp đang chờ trong hàng đợi yêu cầu từ cơ quan tín dụng! Rõ ràng, cơ quan tín dụng là điểm nghẽn của chúng tôi, vì tất cả các yêu cầu báo giá đều phải đi qua cơ quan tín dụng trước. Bây giờ chúng ta có thể thu hoạch một phần lợi ích từ việc kết nối lỏng lẻo và khởi động hai phiên bản bổ sung của cơ quan tín dụng. Chúng ta hiện có ba phiên bản song song của dịch vụ cơ quan tín dụng đang chạy. Điều này sẽ giúp khắc phục điểm nghẽn của chúng ta, đúng không? Hãy xem nào:
Gửi 50 yêu cầu báo giá, sử dụng ba tổ chức tín dụng.

Thời gian tổng để xử lý tất cả 50 tin nhắn được giảm xuống còn 21 giây, với yêu cầu dài nhất chờ phản hồi trong 16 giây. Trung bình, khách hàng phải chờ để nhận phản hồi cho yêu cầu vay trong 8.63 giây, chỉ bằng một nửa so với phiên bản ban đầu. Có vẻ như chúng ta đã loại bỏ nút thắt cổ chai, nhưng thông lượng tin nhắn không tăng lên đáng kể như chúng ta đã hy vọng. Hãy nhớ rằng, trong ví dụ đơn giản này, chúng ta đang chạy tất cả các quy trình trên một CPU duy nhất vì vậy tất cả các quy trình cạnh tranh cho cùng một tài nguyên. Hãy xem xét thống kê hàng đợi mới để xác minh rằng nút thắt cổ chai của bureau tín dụng thực sự đã được khắc phục.
Bây giờ Ngân hàng 5 có vẻ như là một nút thắt cổ chai.

Có vẻ như chúng ta đã loại bỏ một nút thắt cổ chai chỉ để phát hiện ra một nút thắt mới - Ngân hàng 5. Tại sao lại là Ngân hàng 5? Ngân hàng 5 là một tiệm cầm đồ; nó cung cấp khoản vay cho mọi người, vì vậy Ngân hàng 5 là một phần của hầu hết các yêu cầu báo giá. Chúng ta có thể bắt đầu nhiều phiên bản của Ngân hàng 5, nhưng không thực tế khi mong đợi tiệm cầm đồ chạy nhiều phiên bản chỉ để cải thiện thông lượng của chúng ta. Lựa chọn khác của chúng ta là thay đổi logic định tuyến cho các yêu cầu ngân hàng. Vì tiệm cầm đồ tính phí cao hơn nhiều so với các ngân hàng khác, báo giá của nó thường là báo giá thấp nhất chỉ trong những trường hợp mà không ngân hàng nào khác cung cấp báo giá. Xem xét điều này, chúng ta có thể cải thiện hiệu quả của hệ thống bằng cách không định tuyến yêu cầu đến tiệm cầm đồ nếu báo giá cũng có thể được phục vụ bởi ngân hàng khác. Thay đổi này sẽ không ảnh hưởng đến hành vi tổng thể của hệ thống.
Chúng tôi thay đổi Trình quản lý Kết nối Ngân hàng để bao gồm Ngân hàng 5 chỉ cho những yêu cầu báo giá không thể được phục vụ bởi bất kỳ ngân hàng nào khác. Trình quản lý Kết nối Ngân hàng đã được chỉnh sửa như sau:
[View full width] internal class BankConnectionManager { static protected BankConnection[] banks = {new Bank1(), new Bank2(), new Bank3(), newBank4() }; static protected BankConnection catchAll = new Bank5(); public IMessageSender[] GetEligibleBankQueues(int CreditScore, int HistoryLength, int LoanAmount) { ArrayList lenders = new ArrayList(); for (int index = 0; index < banks.Length; index++) { if (banks[index].CanHandleLoanRequest(CreditScore, HistoryLength, LoanAmount)) lenders.Add(banks[index].Queue); } if (lenders.Count == 0) lenders.Add(catchAll.Queue); IMessageSender[] lenderArray = (IMessageSender [])Array.CreateInstance (typeof(IMessageSender), lenders.Count); lenders.CopyTo(lenderArray); return lenderArray; } }
Chạy với mã đã được sửa đổi tạo ra các kết quả như hình dưới đây.
Gửi 50 Yêu Cầu Báo Giá Sử Dụng Ba Tổ Chức Tín Dụng và một Trình Quản Lý Kết Nối Ngân Hàng Được Chỉnh Sửa

Kết quả kiểm tra hiện cho thấy tất cả 50 yêu cầu đã được phục vụ trong 12 giây, chỉ bằng một nửa thời gian ban đầu. Quan trọng hơn, thời gian trung bình để phục vụ một yêu cầu báo giá vay hiện nay đã giảm xuống dưới 4 giây, cải thiện gấp bốn lần so với phiên bản ban đầu. Ví dụ này chứng minh lợi thế của việc định tuyến dự đoán bằng cách sử dụng Danh sách Người nhận. Bởi vì người môi giới cho vay có quyền kiểm soát định tuyến, chúng tôi có thể quyết định mức độ "trí tuệ" mà chúng tôi có thể xây dựng vào logic định tuyến mà không cần thay đổi gì đối với các bên bên ngoài. Sự đánh đổi là người môi giới cho vay trở nên ngày càng phụ thuộc vào kiến thức về các bên nội bộ. Ví dụ, trong khi Trình quản lý Kết nối Ngân hàng ban đầu coi tất cả các ngân hàng là như nhau, phiên bản đã chỉnh sửa dựa vào thực tế rằng Ngân hàng 5 là một nhà cung cấp tất cả trong một chỉ nên được liên hệ khi không còn lựa chọn nào khác. Nếu Ngân hàng 5 bắt đầu cung cấp lãi suất tốt hơn, khách hàng có thể không còn nhận được thỏa thuận tốt nhất có thể.
Màn hình clip cũng cho thấy rằng các tin nhắn phản hồi không nhất thiết phải đến theo thứ tự mà các yêu cầu đã được thực hiện. Chúng ta có thể thấy rằng khách hàng thử nghiệm nhận được phản hồi cho yêu cầu số 48 ngay sau khi nhận được phản hồi cho yêu cầu số 43. Bởi vì chúng ta không bỏ lỡ bất kỳ phản hồi nào, điều này có nghĩa là khách hàng thử nghiệm đã nhận được phản hồi từ yêu cầu 44 đến 47 trước khi nhận được phản hồi 43. Làm thế nào mà những yêu cầu này lại vượt qua số 43? Có vẻ như yêu cầu 43 đã được chuyển đến Ngân hàng Bán lẻ Tổng hợp (Ngân hàng 3). Sau Tiệm Cầm đồ, ngân hàng này có tiêu chí lựa chọn ít hạn chế nhất tiếp theo và có khả năng hơn so với các ngân hàng khác đã bị quá tải với các yêu cầu. Nếu yêu cầu 44 đến 47 không phù hợp với tiêu chí của Ngân hàng Bán lẻ Tổng hợp, cổng ngân hàng sẽ nhận được tất cả các phản hồi cho những yêu cầu này, trong khi yêu cầu báo giá cho yêu cầu 43 vẫn còn đang nằm trong hàng đợi của ngân hàng 3. Bởi vì người môi giới cho vay của chúng ta thực sự hoạt động theo sự kiện, họ sẽ trả lời bất kỳ yêu cầu vay nào ngay khi nhận được tất cả các báo giá từ ngân hàng. Kết quả là, nếu các báo giá ngân hàng cho yêu cầu 44 đến trước khi các báo giá cho số 43, người môi giới cho vay sẽ gửi tin nhắn phản hồi cho yêu cầu 44 trước. Tình huống này cũng làm nổi bật tầm quan trọng của Nhận diện Tương quan trong các tin nhắn để khách hàng thử nghiệm có thể ghép nối các phản hồi với các yêu cầu ngay cả khi chúng đến không theo thứ tự.
Tuning các hệ thống dựa trên tin nhắn không đồng bộ có thể là một nhiệm vụ rất phức tạp. Ví dụ của chúng tôi cho thấy một số kỹ thuật cơ bản nhất để xác định và giải quyết các điểm nghẽn. Nhưng ngay cả ví dụ đơn giản của chúng tôi cũng cho thấy rõ rằng việc khắc phục một vấn đề (điểm nghẽn của bureau tín dụng) có thể gây ra một vấn đề khác (điểm nghẽn của Ngân hàng 5). Chúng tôi cũng có thể thấy rõ những lợi ích của việc nhắn tin không đồng bộ và các người tiêu dùng dựa trên sự kiện. Chúng tôi đã có thể xử lý 50 yêu cầu báo giá trong 12 giây; một giải pháp đồng bộ sẽ mất từ 8 đến 10 lần thời gian dài hơn!
Ví dụ về môi giới cho vay cho thấy cách mà một ứng dụng đơn giản có thể trở nên phức tạp hợp lý khi nó trở nên phân tán, bất đồng bộ và theo sự kiện. Hiện tại, chúng tôi có hơn một tá lớp và sử dụng các ủy quyền xuyên suốt để đối phó với bản chất theo sự kiện của xử lý tin nhắn bất đồng bộ. Sự phức tạp tăng lên cũng đồng nghĩa với nguy cơ gia tăng về các lỗi. Bản chất bất đồng bộ khiến những lỗi này khó tái tạo hoặc xử lý vì chúng phụ thuộc vào các điều kiện tạm thời cụ thể. Bởi vì những rủi ro bổ sung này, các giải pháp nhắn tin đòi hỏi một phương pháp rất kỹ lưỡng trong việc kiểm thử. Chúng tôi có thể viết một cuốn sách hoàn toàn về kiểm thử các giải pháp nhắn tin, nhưng bây giờ tôi muốn đưa ra một số lời khuyên đơn giản, có thể thực hiện được về kiểm thử, được tóm tắt trong ba quy tắc sau đây:
Tách ứng dụng khỏi việc triển khai nhắn tin bằng cách sử dụng giao diện và các lớp triển khai.
Kiểm tra logic kinh doanh bằng các trường hợp kiểm tra đơn vị trước khi kết nối nó vào môi trường nhắn tin.
Cung cấp một triển khai giả của lớp nhắn tin cho phép bạn kiểm tra đồng bộ.
Kiểm tra một ứng dụng đơn lẻ dễ dàng hơn nhiều so với việc kiểm tra nhiều ứng dụng phân tán được kết nối qua các kênh nhắn tin. Một ứng dụng đơn lẻ cho phép chúng ta theo dõi toàn bộ đường dẫn thực thi, chúng ta không cần một quy trình khởi động phức tạp để khởi động tất cả các thành phần, và không cần phải xóa kênh giữa các bài kiểm tra (xem Bộ Xóa Kênh [xxx]). Đôi khi, việc ngăn chặn một số chức năng bên ngoài trong khi kiểm tra những chức năng khác là hữu ích. Ví dụ, trong khi chúng ta kiểm tra cổng ngân hàng, chúng ta có thể tạm dừng cổng thông tin tín dụng thay vì thực sự gửi tin nhắn đến một quy trình tín dụng bên ngoài.
Làm thế nào chúng ta có thể đạt được một số lợi ích của việc kiểm tra bên trong một ứng dụng duy nhất với tác động tối thiểu đến mã ứng dụng? Chúng ta có thể tách biệt việc triển khai của một Cổng Giao tiếp khỏi định nghĩa giao diện. Điều đó cho phép chúng ta cung cấp nhiều triển khai khác nhau của giao diện.
Tách giao diện tổ chức tín dụng khỏi triển khai

Bởi vì chúng tôi đã bao bọc tất cả logic cụ thể về nhắn tin bên trong cổng thông tin của cơ quan tín dụng, chúng tôi có thể định nghĩa một giao diện rất đơn giản:
public interface ICreditBureauGateway { void GetCreditScore(CreditBureauRequest quoteRequest, OnCreditReplyEvent OnCreditResponse, Object ACT); void Listen(); } Ví dụ, chúng ta có thể tạo một triển khai cổng thông tin tín dụng giả mà không thực sự kết nối với bất kỳ hàng đợi tin nhắn nào mà thay vào đó gọi delegate được chỉ định ngay bên trong phương thức GetCreditScore. Triển khai giả này chứa cùng một logic như cơ quan tín dụng thực tế, do đó phần còn lại của môi giới cho vay hoàn toàn không biết về sự thay đổi này.
public class MockCreditBureauGatewayImp : ICreditBureauGateway { private Random random = new Random(); public MockCreditBureauGatewayImp() { } public void GetCreditScore(CreditBureauRequest quoteRequest, OnCreditReplyEvent OnCreditResponse, Object ACT) { CreditBureauReply reply = new CreditBureauReply(); reply.CreditScore = (int)(random.Next(600) + 300); reply.HistoryLength = (int)(random.Next(19) + 1); reply.SSN = quoteRequest.SSN; OnCreditResponse(reply, ACT); } public void Listen() { } } Việc cài đặt lớp Credit Bureau đã chứng minh sự tách biệt rõ ràng giữa các chức năng liên quan đến messaging (được đóng gói trong lớp cơ sở) và logic kinh doanh (giảm xuống thành một hàm ngẫu nhiên trong ví dụ đơn giản của chúng tôi). Trong một kịch bản thực tế, logic kinh doanh có thể (hy vọng) phức tạp hơn một chút. Trong trường hợp đó, sẽ có lợi khi di chuyển các phương thức getCreditScore và getCreditHistoryLength cùng nhau vào một lớp riêng biệt không có bất kỳ sự phụ thuộc nào vào lớp messaging (mặc dù nó ít rõ ràng hơn, nhưng kế thừa vẫn mang theo các sự phụ thuộc từ lớp con đến lớp cơ sở và các lớp liên quan). Sau đó, chúng ta có thể sử dụng một công cụ kiểm tra đơn vị như nUnit (http://www.nunit.org) để viết các trường hợp kiểm tra mà không cần lo lắng về messaging.
Việc triển khai giả của ICreditBureauGateway là đơn giản và hiệu quả. Nhưng nó cũng thay thế tất cả mã liên quan đến gateway của cơ quan tín dụng, vì vậy lớp CreditBureauGatewayImp phải được kiểm tra riêng biệt. Nếu chúng ta muốn loại bỏ sự phụ thuộc (và ảnh hưởng đến hiệu suất liên quan) vào hàng đợi tin nhắn nhưng vẫn thực thi mã bên trong lớp CreditBureauGatewayImp, chúng ta có thể sử dụng một triển khai giả của các giao diện IMessageReceiver và IMessageSender. Một triển khai giả đơn giản có thể trông như sau:
public class MockQueue: IMessageSender, IMessageReceiver { private OnMsgEvent onMsg = new OnMsgEvent(DoNothing); public void Send(Message msg){ onMsg(msg); } private static void DoNothing(Message msg){ } public OnMsgEvent OnMessage { get { return onMsg; } set { onMsg = value; } } public void Begin() { } public MessageQueue GetQueue() { return null; } } Chúng ta có thể thấy rằng Send kích hoạt delegate onMsg ngay lập tức mà không sử dụng bất kỳ hàng đợi tin nhắn nào. Để sử dụng hàng đợi giả này cho cổng thông tin của cục tín dụng, chúng ta cần đảm bảo phản hồi bằng một tin nhắn đúng loại. Chúng ta sẽ không thể đơn giản chỉ trả lại tin nhắn yêu cầu cho tin nhắn phản hồi. Việc triển khai này không được trình bày ở đây nhưng có thể đơn giản nếu, chẳng hạn, chúng ta sử dụng một tin nhắn phản hồi có sẵn.
Phần này nhắc nhở chúng tôi rằng ngay cả một hệ thống nhắn tin đơn giản (trong thực tế, người môi giới cho vay chỉ cần thực hiện hai bước: lấy điểm tín dụng và nhận báo giá tốt nhất từ ngân hàng) cũng có thể trở nên khá phức tạp do tính chất không đồng bộ và sự liên kết lỏng lẻo giữa các thành phần. Tuy nhiên, chúng tôi vẫn đã thực hiện một số biện pháp tiết kiệm để giữ cho ví dụ dễ quản lý. Cụ thể, ví dụ này không đề cập đến các chủ đề sau:
Xử lý lỗi
Giao dịch
An toàn luồng
Ví dụ không có cơ chế quản lý để xử lý lỗi. Tại thời điểm này, các thành phần chỉ đơn giản xuất ra thông điệp vào các cửa sổ bảng điều khiển khác nhau - không phải là một giải pháp thích hợp cho một hệ thống sản xuất. Đối với một việc thực hiện thực tế, các thông điệp lỗi cần phải được chuyển tới một bảng điều khiển trung tâm để có thể thông báo cho một người vận hành một cách thống nhất. Các mẫu quản lý hệ thống trong Chương 11, "Quản lý Hệ thống" (ví dụ, Bus Điều Khiển [xxx]) giải quyết các yêu cầu này.
Ví dụ này không sử dụng hàng đợi giao dịch. Chẳng hạn, nếu MessageRouter bị sự cố sau khi gửi hai trong bốn tin nhắn yêu cầu báo giá đến các ngân hàng, một số ngân hàng sẽ xử lý yêu cầu báo giá, trong khi những ngân hàng khác thì không. Tương tự, nếu người môi giới cho vay gặp sự cố sau khi nhận tất cả phản hồi báo giá từ ngân hàng nhưng trước khi gửi phản hồi đến khách hàng, khách hàng sẽ không bao giờ nhận được phản hồi. Trong một hệ thống thực tế, các hành động như vậy cần phải được đóng gói bên trong các giao dịch để các tin nhắn đến không bị tiêu thụ cho đến khi tin nhắn ra tương ứng đã được gửi.
Triển khai môi giới cho vay chỉ thực hiện trong một luồng đơn và không quan tâm đến tính an toàn của luồng. Ví dụ, phương thức BeginReceive trên hàng đợi tin nhắn đến (được giấu trong MessageReceiverGateway) sẽ không được gọi cho đến khi việc xử lý tin nhắn trước đó đã hoàn thành. Điều này hoàn toàn phù hợp cho một ứng dụng mẫu (và nhanh hơn nhiều so với triển khai đồng bộ), nhưng trong một môi trường có thông lượng cao, chúng ta sẽ muốn sử dụng một Trình Phân Phối Tin Nhắn quản lý nhiều luồng thực hiện.
Chương này đã đưa chúng ta đi qua việc triển khai ứng dụng môi giới cho vay sử dụng hàng đợi tin nhắn bất đồng bộ và MSMQ. Chúng tôi đã cố ý không né tránh việc thể hiện các chi tiết triển khai nhằm làm sáng tỏ những vấn đề thực tế tiềm ẩn trong việc xây dựng các ứng dụng nhắn tin bất đồng bộ. Chúng tôi tập trung vào các sự đánh đổi trong thiết kế nhiều hơn là vào API nhắn tin cụ thể của nhà cung cấp để ví dụ này cũng có giá trị cho các nhà phát triển không sử dụng C#.
Ví dụ này nhắc chúng ta về những phức tạp trong việc triển khai ngay cả một ứng dụng nhắn tin đơn giản. Nhiều điều có thể được coi là hiển nhiên trong một ứng dụng monolithic (ví dụ: gọi một phương thức) có thể đòi hỏi một lượng mã lập trình đáng kể khi sử dụng nhắn tin bất đồng bộ. May mắn thay, các mẫu thiết kế cung cấp cho chúng ta một ngôn ngữ để mô tả một số sự đánh đổi trong thiết kế mà không cần phải đi sâu vào những thuật ngữ của nhà cung cấp.
bởi Michael J. Rettig
Hai triển khai trước đây của môi giới cho vay đã sử dụng các khung tích hợp cung cấp chức năng Kênh Tin nhắn cơ bản. Ví dụ, cả Axis và MSMQ đều cung cấp API để gửi tin nhắn đến hoặc nhận tin nhắn từ một Kênh Tin nhắn, trong khi ứng dụng phải tự lo liệu hầu như mọi thứ khác. Chúng tôi đã chọn loại triển khai này một cách có chủ đích để chứng minh cách mà một giải pháp tích hợp có thể được xây dựng từ đầu, sử dụng các thư viện Java hoặc C# phổ biến.
Nhiều bộ sản phẩm EAI thương mại cung cấp chức năng đáng kể hơn để đơn giản hóa quá trình phát triển các giải pháp tích hợp. Những bộ sản phẩm này thường bao gồm các môi trường phát triển trực quan cho phép cấu hình kéo-thả của các Bộ chuyển đổi Thông điệp và Quản lý Quy trình. Nhiều bộ còn cung cấp các chức năng quản lý hệ thống và quản lý siêu dữ liệu tinh vi. Chúng tôi đã chọn bộ tích hợp TIBCO ActiveEnterprise cho ví dụ thực hiện này. Giống như các thực hiện trước, chúng tôi chủ yếu tập trung vào các quyết định thiết kế và các thỏa hiệp, và chỉ giới thiệu lượng ngôn ngữ cụ thể của sản phẩm cần thiết để hiểu giải pháp. Do đó, phần này sẽ hữu ích ngay cả khi bạn chưa làm việc với TIBCO ActiveEnterprise trước đây. Nếu bạn quan tâm đến thông tin chi tiết về sản phẩm hoặc nhà cung cấp, vui lòng truy cập http://www.tibco.com.
Ví dụ triển khai này cũng khác biệt trong thiết kế giải pháp bằng cách sử dụng phương pháp Scatter-Gather kiểu Đấu giá. Phương pháp này sử dụng Kênh Xuất bản-Đăng ký thay vì Danh sách Người nhận để cho phép người môi giới cho vay gửi yêu cầu báo giá đến bất kỳ số lượng ngân hàng nào. Loại mẫu Scatter-Gather này thực hiện một yêu cầu-phản hồi động với một số lượng người nghe không xác định. Thêm vào đó, việc triển khai thành phần người môi giới cho vay sử dụng tính năng quản lý quy trình kinh doanh được cung cấp bởi công cụ Quản lý Quy trình của TIBCO.
Ứng dụng của chúng tôi là một hệ thống yêu cầu báo giá ngân hàng đơn giản. Khách hàng gửi yêu cầu báo giá đến giao diện môi giới vay. Môi giới vay thực hiện yêu cầu bằng cách trước tiên lấy điểm tín dụng, sau đó yêu cầu báo giá từ một số ngân hàng. Khi môi giới vay nhận được báo giá từ các ngân hàng, họ chọn báo giá tốt nhất và trả lại cho khách hàng (xem hình).
Khách hàng của hệ thống mong đợi một giao diện Yêu cầu-Trả lời đồng bộ tới môi giới vay vốn; khách hàng gửi yêu cầu báo giá và chờ đợi tin nhắn phản hồi từ môi giới vay vốn. Môi giới vay vốn lại sử dụng giao diện Yêu cầu-Trả lời để giao tiếp với trung tâm tín dụng nhằm lấy điểm tín dụng. Khi nhận được yêu cầu ban đầu từ khách hàng, môi giới vay vốn có tùy chọn thực hiện các hoạt động bất đồng bộ phía sau bề mặt đồng bộ phân tán. Điều này cho phép môi giới vay vốn sử dụng kiểu đấu giá Scatter-Gather với Kênh Phát-Hẹn để thu thập báo giá từ nhiều ngân hàng.
Kiến trúc giải pháp TIBCO Loan Broker

Quy trình đấu giá bắt đầu bằng việc phát đi thông điệp yêu cầu báo giá đến Kênh Publish-Subscribe bank.loan.request để bất kỳ ngân hàng nào quan tâm có thể lắng nghe thông điệp và cung cấp tỷ lệ của riêng mình. Số lượng ngân hàng gửi phản hồi là không xác định và có thể thay đổi cho mỗi yêu cầu báo giá. Cuộc đấu giá hoạt động bằng cách mở đấu giá cho các ngân hàng, sau đó chờ một khoảng thời gian đã định để nhận các thông điệp phản hồi trên kênh bank.loan.reply. Mỗi khi một lời đề nghị được nhận, thời gian chờ sẽ được đặt lại, cho phép các ngân hàng khác có thời gian để gửi một lời đề nghị khác nếu có thể. Trong trường hợp này, các lời đề nghị của các ngân hàng khác là công khai, vì vậy một ngân hàng khác có thể lắng nghe các lời đề nghị khác và đặt một lời đề nghị đối ứng nếu họ muốn.
Nhà môi giới vay tiền phát tán yêu cầu báo giá đến một số lượng không xác định các đối tượng nhận. Điều này hoàn toàn khác với Danh sách Người Nhận, trong đó việc gửi yêu cầu được thực hiện đến một danh sách ngân hàng đã được xác định trước. Điều này được phản ánh trong điều kiện tính đầy đủ của Nhà Tập Hợp. Thay vì chờ đợi phản hồi từ mỗi ngân hàng như trong các triển khai trước đây, Nhà Tập Hợp hoàn toàn dựa vào điều kiện hết thời gian để chấm dứt cuộc đấu giá. Nhà Tập Hợp đơn giản là bỏ qua mọi phản hồi nhận được sau khi cuộc đấu giá hết thời gian. Nếu không có ngân hàng nào trả lời trong khoảng thời gian đã chỉ định, Nhà Tập Hợp gửi một tin nhắn phản hồi đến khách hàng cho biết rằng không có báo giá nào được nhận.
Biểu đồ Hoạt động Mô tả Hành vi Quản lý Quy trình

Trong triển khai này, các chức năng Làm giàu Nội dung và Tập hợp được thực hiện trong thành phần Quản lý Quy trình. Kết quả là, sơ đồ kiến trúc giải pháp không mô tả chi tiết về sự tương tác giữa các thành phần, vì chúng được nhúng trong một thành phần duy nhất. Thay vào đó, chúng ta cần xem xét sơ đồ hoạt động đại diện cho định nghĩa Mẫu Quy trình được sử dụng bởi Quản lý Quy trình. Một sơ đồ hoạt động ban đầu định nghĩa rõ ràng vai trò của môi giới vay vốn và cung cấp cơ sở cho Mẫu Quy trình. Từ sơ đồ, chúng ta có thể thấy rằng môi giới vay vốn có nhiều trách nhiệm. Điều này chuyển giao tốt vào sơ đồ quy trình, cho thấy đồ họa thứ tự chính xác của các sự kiện và các con đường quyết định.
Để giải thích về thiết kế của giải pháp của chúng tôi, chúng tôi cần giới thiệu một số khái niệm cơ bản về bộ sản phẩm TIBCO. Việc triển khai các giải pháp TIBCO thường yêu cầu phải đánh giá các công cụ khác nhau cho một vấn đề cụ thể vì đôi khi, một vấn đề có thể được giải quyết bằng nhiều công cụ khác nhau. Mấu chốt là chọn ra công cụ tốt nhất. Chúng tôi giới hạn cuộc thảo luận chỉ trong những tính năng TIBCO cần thiết để xây dựng triển khai ví dụ:
TIB/Gặp Gỡ Vận Tải
Công cụ Quản lý Quy trình TIB/Quản lý Tích hợp
Kho TIBCO cho Quản lý Siêu dữ liệu
Tại trung tâm của bộ công cụ nhắn tin của TIBCO là lớp vận chuyển TIB/RendezVous. RendezVous cung cấp cơ chế nhắn tin để gửi và nhận tin nhắn TIBCO trên bus thông tin. TIBCO hỗ trợ nhiều loại vận chuyển, bao gồm (nhưng không giới hạn ở) JMS, HTTP, FTP và email. RendezVous cung cấp vận chuyển cơ bản cho các tin nhắn trong ví dụ của chúng tôi. Vận chuyển hỗ trợ cả tin nhắn đồng bộ và không đồng bộ, cũng như Kênh Điểm-Đến-Điểm và Kênh Phát-Hành-Đăng-Ký. Mỗi kênh có thể được cấu hình cho các mức dịch vụ khác nhau.
Tin nhắn đáng tin cậy (RV) cung cấp hiệu suất cao, nhưng có nguy cơ thực tế là mất tin nhắn.
Tin nhắn đã được chứng nhận (RVCM) được giao ít nhất một lần.
Tin nhắn giao dịch (RVTX) đảm bảo giao hàng đúng một lần và chỉ một lần.
Tương tự như các ví dụ về MSMQ trong cuốn sách này, TIBCO cung cấp một API mở để tạo ra các giải pháp nhắn tin sử dụng Java hoặc C++ và bao gồm một loạt các công cụ để đơn giản hóa quá trình phát triển.
TIB/IntegrationManager là một công cụ phát triển của TIBCO bao gồm một giao diện người dùng phong phú để thiết kế các giải pháp quy trình làm việc và một động cơ Quản lý Quy trình để thực thi chúng. Giao diện đồ họa cung cấp một loạt các tùy chọn cấu hình, quy trình làm việc và triển khai đa dạng được lưu trữ trong Kho lưu trữ TIBCO. TIBCO sử dụng kho lưu trữ như là artefact cấu hình trung tâm cho hệ thống. Nó giữ tất cả siêu dữ liệu, quy trình làm việc và mã tùy chỉnh.
Thành phần quy trình của giải pháp là một khía cạnh giúp nó khác biệt với giải pháp cấp mã. Đối với ví dụ về môi giới khoản vay, TIB/IntegrationManager cung cấp nhắn tin bất đồng bộ và đồng bộ cũng như quy trình cơ bản, bao gồm Trạng thái Phiên Máy chủ [EAA]. Đối với mục đích của chúng ta, chúng ta có thể chia TIB/IntegrationManager thành ba phần: kênh, người tạo công việc và sơ đồ quy trình.
Các thành phần TIB/Quản lý tích hợp

Mỗi quy trình trong TIB/IntegrationManager tạo ra một "công việc" (hoặc phiên bản quy trình) cung cấp một đối tượng phiên trung tâm để duy trì trạng thái. Đối tượng này bao gồm một môi trường có khe với các thao tác lấy và đặt để lưu trữ các đối tượng, cũng như các phương thức tiện ích để tương tác với phiên. Một GUI đơn giản cho phép các nhà phát triển TIBCO tạo ra các định nghĩa quy trình (gọi là Sơ đồ Quy trình trong TIBCO) xác định trình tự các nhiệm vụ mà công việc thực hiện. Các định nghĩa quy trình giống như các sơ đồ hoạt động kiểu UML bao gồm các nhiệm vụ được kết nối bởi các đường chuyển tiếp (xem hình minh họa trên trang tiếp theo). Tuy nhiên, các sơ đồ chỉ cung cấp cấu trúc; sau mỗi hoạt động (tức là, hộp trên sơ đồ) là một lượng cấu hình và mã đáng kể. Trong ví dụ của chúng tôi, chúng tôi cần một số mã để xử lý các khoản vay. TIB/IntegrationManager sử dụng ECMAScript (thường được gọi là JavaScript) làm ngôn ngữ kịch bản cơ bản.
Ví dụ sơ đồ quy trình Quản lý Tích hợp TIB

Một sơ đồ quy trình điển hình bao gồm một loạt các tác vụ tích hợp. Những thứ này bao gồm các tác vụ kiểm soát như nhánh, thanh đồng bộ hoặc điểm quyết định, các tác vụ tín hiệu để gửi và nhận thông điệp, và các tác vụ thực thi như dịch dữ liệu, định tuyến và tích hợp hệ thống. Sơ đồ cơ bản được mô tả ở đây bao gồm hai tác vụ: một tác vụ ECMAScript thực hiện một số logic tùy chỉnh và một tác vụ tín hiệu ra để xuất bản một thông điệp lên một kênh. Các chuyển tiếp tác vụ có thể chứa logic để lựa chọn một tuyến đường cụ thể dựa trên nội dung thông điệp hoặc các tiêu chí khác.
Tích hợp và nhắn tin gần như luôn yêu cầu một dạng dữ liệu tự mô tả (xem "Giới thiệu" trong Chương 8, "Biến đổi Thông điệp"). TIBCO định nghĩa các lớp siêu dữ liệu là các đối tượng ActiveEnterprise (AE) được lưu trữ trong kho TIBCO. Mỗi đối tượng AE gửi qua một kênh thông điệp đều bao gồm một Chỉ thị Định dạng để chỉ ra định nghĩa lớp mà thông điệp này tuân theo.
Quản lý siêu dữ liệu của thông điệp là một phần quan trọng trong quy trình phát triển. Các nhà phát triển TIBCO có thể định nghĩa siêu dữ liệu trực tiếp trong môi trường phát triển, có thể trích xuất nó từ các hệ thống bên ngoài như cơ sở dữ liệu quan hệ (sử dụng Bộ kết nối Siêu dữ liệu như đã mô tả trong Kết nối Kênh [xxx]), hoặc nhập các lược đồ XML. Siêu dữ liệu cung cấp một hợp đồng rõ ràng cho các đối tượng và thông điệp trong hệ thống. Khi các lớp được định nghĩa trong kho TIBCO, các đối tượng có sẵn để khởi tạo và thao tác trong kịch bản ECMA.
//Instantiation of a TIBCO AE class var bank = new aeclass.BankQuoteRequest(); bank.CorrelationID = job.generateGUID(); bank.SSN = job.request.SSN;
Tuy nhiên, hãy nhớ rằng đây là một môi trường động, được lập trình kịch bản với việc kiểm tra kiểu tại thời điểm biên dịch hạn chế. Việc thay đổi định nghĩa siêu dữ liệu có thể dễ dàng làm hỏng một phần khác của hệ thống của bạn. Nếu không có các phương pháp kiểm tra và phát triển thích hợp, các hệ thống dựa trên tin nhắn có thể dễ dàng biến thành hệ thống "chỉ thêm", có nghĩa là siêu dữ liệu chỉ được thêm vào hệ thống và không bao giờ được thay đổi vì sợ làm hỏng điều gì đó.
Sơ đồ Kiến trúc Giải pháp, ở trang 446, cho chúng ta thấy rằng giải pháp yêu cầu các dịch vụ sau.
Nhà môi giới cho vay
Nhận yêu cầu ban đầu
Nhận điểm tín dụng
Tổ chức đấu giá trái phiếu với các ngân hàng
"Trả về ưu đãi vay tốt nhất cho khách hàng"
Dịch vụ tín dụng
Cung cấp điểm tín dụng dựa trên số an sinh xã hội (SSN)
Ngân hàng(s)
Gửi báo giá dựa trên điểm tín dụng và số tiền vay.
Mỗi dịch vụ đều có thể truy cập thông qua một giao diện bên ngoài. Đối với mỗi giao diện như vậy, chúng tôi phải đưa ra các quyết định thiết kế sau:
Phong cách trò chuyện: Đồng bộ vs. Bất đồng bộ
Chất lượng dịch vụ cấp độ
Các phong cách giao tiếp cho các giao diện đã được xác định trước bởi kiến trúc giải pháp. Cả môi giới cho vay và dịch vụ tín dụng đều cần các giao diện đồng bộ, trong khi việc giao tiếp với các ngân hàng sẽ hoàn toàn là bất đồng bộ.
Cấp độ dịch vụ cho các giải pháp nhắn tin có thể trở nên phức tạp, đặc biệt là khi xem xét các tình huống chuyển đổi. May mắn thay, cấp độ dịch vụ trong ví dụ về khoản vay giải quyết thành một giải pháp đơn giản. Trong trường hợp xảy ra lỗi (thời gian chờ, tin nhắn bị mất, hệ thống ngừng hoạt động), yêu cầu ban đầu có thể được gửi lại (nhà môi giới khoản vay là một Bộ nhận Idempotent [xxx]). Hãy nhớ rằng chúng ta chỉ đang Obtaining a quote tại thời điểm này. Nó chưa phải là một thỏa thuận có tính ràng buộc về mặt pháp lý. Tất nhiên, loại giả định này cần phải được tài liệu hóa trong hệ thống và được tất cả các bên liên quan hiểu rõ. Ví dụ, các ngân hàng cần biết rằng một yêu cầu báo giá có thể được gửi lại lần thứ hai. Nếu các ngân hàng theo dõi các yêu cầu vay của khách hàng để phát hiện gian lận, chúng ta có thể phải thay đổi giải pháp để tránh gửi các yêu cầu trùng lặp, chẳng hạn bằng cách sử dụng Giao hàng Đảm bảo.
Hệ thống môi giới cho vay có hai giao diện đồng bộ giữa khách hàng và môi giới cho vay, cũng như giữa môi giới cho vay và tổ chức tín dụng. TIBCO triển khai nhắn tin theo phong cách RPC với các thao tác sử dụng Request-Reply và Command Message. Về cơ bản, đây là một lớp đồng bộ để bao bọc động cơ nhắn tin TIBCO. Trong quá trình gọi các thao tác TIBCO, bạn có thể lắng nghe các thông điệp yêu cầu và phản hồi đi qua bus. Thông điệp yêu cầu được công bố trên kênh đã chỉ định (ví dụ: customer.loan.request). Thông điệp bao gồm một Địa chỉ Trả về chỉ định địa chỉ của một kênh INBOX gọi là để nhận phản hồi. TIBCO ẩn giấu các chi tiết bất đồng bộ phía sau mô hình lập trình phong cách RPC. Trong TIB/IntegrationManager, các thao tác miền như lấy điểm tín dụng được định nghĩa như một phần của các lớp AE và có thể được gọi từ công cụ mô hình hóa quy trình. Ví dụ, để mở rộng môi giới cho vay như một giao diện đồng bộ, chúng ta phải thực hiện một vài bước triển khai. Việc triển khai dịch vụ tổ chức tín dụng theo sát các bước tương tự này.
Các lớp AE định nghĩa định dạng dữ liệu cho các thông điệp được gửi qua các kênh TIB/RendezVous. Việc định nghĩa một lớp trong TIB/IntegrationManager khác hẳn với việc tạo một lớp trong IDE mà bạn ưa thích. Các lớp AE được định nghĩa thông qua một loạt các hộp thoại (xem hình) từ IDE TIB/IntegrationManager. Các hộp thoại cho phép bạn chọn một tên cho lớp của mình và sau đó chỉ định các trường cho lớp. Các trường có thể được kiểu là số nguyên, số thực, hoặc số double, hoặc có thể được cấu thành từ các lớp AE khác.
Định nghĩa một lớp AE với các thuộc tính và phép toán

Tương tự như việc thêm các phương thức giao diện, các phép toán có thể được thêm vào một lớp AE. Các tham số và kiểu trả về có thể được chỉ định trong định nghĩa. Như một giao diện, không có triển khai nào được chỉ định. Việc triển khai sẽ được gán sau khi chúng ta sử dụng trình tạo công việc để liên kết một kênh với một thể hiện quy trình.
Một sơ đồ quy trình cung cấp cách thực hiện cho hoạt động. Các hoạt động được thực hiện trong ví dụ này yêu cầu một tham số trả về. Không như các phương thức được thực hiện trong mã, một sơ đồ quy trình không có giá trị "trả về". Thay vào đó, chúng ta chỉ định vị trí trong công việc nơi giá trị trả về sẽ được đặt. Chúng ta chỉ định điều này trong trình tạo công việc, và chúng ta phải nhớ để gán đúng giá trị cho vị trí trong công việc trong sơ đồ quy trình của chúng ta. Việc thực hiện thực tế của sơ đồ quy trình sẽ được thảo luận chi tiết trong các trang tiếp theo.
Kênh cho phép chúng ta xác định phương tiện vận chuyển, định nghĩa thông điệp, dịch vụ và chủ đề. Đối với các hoạt động đồng bộ của chúng ta, chúng ta cần một kênh client/server. Chúng ta có thể chỉ định các lớp AE mà chúng ta đã tạo ở bước 1. Từ các định nghĩa giao diện ban đầu của chúng ta, chúng ta đã chọn RendezVous với nhắn tin tin cậy. Cấu hình các tùy chọn này chỉ là một vấn đề nhấp chuột và chọn các tùy chọn phù hợp.
Định nghĩa thuộc tính kênh

Người tạo công việc lấy giá trị từ kênh và chuyển chúng đến sơ đồ quy trình bằng cách tạo một công việc và khởi tạo các slot môi trường của nó. Khi công việc được tạo, sơ đồ quy trình sẽ được khởi tạo. Việc thực thi sẽ theo đường dẫn được định nghĩa bởi sơ đồ hoạt động. Khi quá trình hoàn tất, người tạo công việc sẽ trả lại phản hồi về kênh. Chúng ta có thể thấy trong hộp thoại người tạo công việc tên của hoạt động của chúng ta.
Cấu hình Tạo công việc

Với các dịch vụ đồng bộ của chúng tôi đã sẵn sàng, chúng tôi có thể triển khai môi giới vay vốn để kết nối mọi thứ lại với nhau. Sơ đồ được bao gồm thể hiện quy trình môi giới vay vốn. Quy trình này định nghĩa hành vi của thành phần môi giới vay vốn. Trong các bước trước đó, chúng tôi đã định nghĩa hoạt động AE, kênh và trình tạo công việc để khởi tạo sơ đồ quy trình khi một khách hàng gửi tin nhắn đến kênh CreditRequest.
Từ góc độ thiết kế, chúng ta cần rất cẩn thận về những gì được đưa vào sơ đồ quy trình. Các sơ đồ lớn và phức tạp nhanh chóng trở nên khó quản lý. Việc tạo ra một sự phân tách hiệu quả giữa các mối quan tâm trong các sơ đồ là rất quan trọng, tránh sự pha trộn xấu giữa logic kinh doanh và logic quy trình bên trong một định nghĩa quy trình duy nhất. Việc định nghĩa đâu là logic quy trình và đâu là logic kinh doanh là điều khó khăn. Một quy tắc đơn giản là nghĩ về logic quy trình như là sự tương tác với hệ thống bên ngoài: Hệ thống nào tôi sẽ kết nối tiếp theo? Tôi sẽ làm gì nếu hệ thống không khả dụng? Logic kinh doanh thường liên quan đến ngôn ngữ cụ thể trong lĩnh vực: Tôi làm thế nào để kích hoạt một đơn hàng? Tôi làm thế nào để tính toán điểm tín dụng? Tôi làm thế nào để tạo báo giá cho một khoản vay ngân hàng? Với bản chất phức tạp của mã kinh doanh, một ngôn ngữ phát triển đầy đủ tính năng thường là sự lựa chọn tốt nhất để triển khai. Hầu hết các công cụ quản lý quy trình, bao gồm TIB/IntegrationManager, cho phép bạn tích hợp trực tiếp với Java hoặc ngôn ngữ khác.
Đối với những ai quen thuộc với khái niệm MVC (Mô hình, Giao diện, Kiểm soát), việc triển khai có thể được xem trong một bối cảnh tương tự. Bằng cách đơn giản đổi tên giao diện thành quy trình làm việc, triển khai của chúng tôi rơi vào một định nghĩa ngắn gọn.
Quy trình làm việc một mô hình trực quan của quy trình làm việc.
Bộ điều khiển là động cơ quy trình nhận sự kiện từ bus tin nhắn, thực hiện các thành phần phù hợp của quy trình làm việc.
Mô hình hóa mã nguồn cơ sở (ECMAScript, JavaScript, Java, J2EE, v.v.).
Sơ đồ dưới đây chứa một sự kết hợp giữa các hộp thực thi kịch bản và các tác vụ tùy chỉnh thực hiện các hành động tích hợp. Một trong những lợi ích lớn của việc mô hình hóa các quy trình bằng công cụ mô hình hóa quy trình hình ảnh là "mã" đang chạy trông rất giống với sơ đồ hoạt động UML mà chúng tôi đã sử dụng để thiết kế giải pháp.
Định nghĩa quy trình môi giới vay tiền

Vì mỗi biểu tượng tác vụ có thể chứa mã thực tế hoặc các tham số cấu hình quan trọng, chúng ta sẽ đi qua từng tác vụ và mô tả nó một cách chi tiết hơn.
Hộp đầu tiên thể hiện một ECMAScript khởi tạo một đối tượng AE và gán giá trị cho các trường.
var credit = new aeclass.CreditBureauRequest(); credit.SSN = job.request.SSN; job.creditRequest = credit;
Yêu cầu tín dụng được tạo ra cần thiết như một tham số trong hoạt động tiếp theo, hoạt động này sẽ gọi đến các thao tác đồng bộ với cơ quan tín dụng. Cơ quan tín dụng được triển khai như một sơ đồ quy trình tách rời bao gồm một tác vụ ECMA duy nhất, nhận tin nhắn và trả lại điểm tín dụng. Hoạt động đồng bộ ngụ ý rằng quy trình Môi giới Khoản vay sẽ chờ đợi cho đến khi tin nhắn phản hồi từ cơ quan tín dụng đến.
Khi người môi giới cho vay nhận được phản hồi từ cục tín dụng, chúng ta có thể thấy trong sơ đồ rằng một đối tượng AE khác cần được tạo ra để công bố yêu cầu báo giá đến bất kỳ ngân hàng nào tham gia. Để thực hiện chức năng này, chúng ta sử dụng tác vụ Mapper cho phép chúng ta lập bản đồ đồ họa các mục dữ liệu từ nhiều nguồn khác nhau. Mapper là một triển khai trực quan của mẫu Biên dịch Tin nhắn. Tác vụ Mapper thể hiện một trong những lợi thế của việc quản lý siêu dữ liệu. Bởi vì TIB/IntegrationManager có quyền truy cập vào siêu dữ liệu xác định cấu trúc của mỗi đối tượng, Mapper hiển thị cấu trúc của các đối tượng nguồn và đích và cho phép chúng ta lập bản đồ trực quan các trường chỉ với vài cú nhấp chuột. Một đối tượng mới được khởi tạo với các giá trị từ đối tượng đầu vào. Chúng ta sử dụng phương thức generateGUID của đối tượng công việc để tạo ra một Định danh Tương quan duy nhất và gán nó cho trường ID Tương quan của đối tượng bankRequest. Như chúng ta sẽ thấy sau này, trường ID Tương quan là quan trọng để cho phép chúng ta xử lý nhiều yêu cầu vay cùng một lúc.
Nhiệm vụ Bản Đồ Hình Ảnh Tạo Ra Thông Điệp Yêu Cầu Ngân Hàng

Thay vì sử dụng Mapper trực quan, chúng tôi có thể đã sử dụng một tác vụ ECMAScript để đạt được cùng một chức năng. Mã tương đương sẽ trông như sau. Bạn có thể thấy cách mà chúng tôi tạo một đối tượng mới của loại BankQuoteRequest và gán từng trường từ các đối tượng nguồn.
var bank = new aeclass.BankQuoteRequest(); //Create ID to uniquely identify this transaction. // We will need this later to filter replies bank.CorrelationID = job.generateGUID(); bank.SSN = job.request.SSN; bank.CreditScore = job.creditReply.CreditScore; bank.HistoryLength = job.creditReply.HistoryLength; bank.LoanAmount = job.request.LoanAmount; bank.LoanTerm = job.request.LoanTerm; job.bankRequest = bank;
Việc sử dụng tác vụ Mapper trực quan hay tác vụ ECMAScript để triển khai chức năng Biên dịch Thông điệp phụ thuộc vào loại và độ phức tạp của một bản đồ. Tác vụ Mapper có thể cho chúng ta cái nhìn trực quan đẹp về các kết nối giữa các đối tượng nguồn và mục tiêu nhưng có thể trở nên khó đọc khi các đối tượng có nhiều trường. Mặt khác, tác vụ Mapper bao gồm các hàm đặc biệt cho phép chúng ta ánh xạ các trường lặp (tức là, Mảng) chỉ với một dòng thay vì phải mã hóa vòng lặp.
Tiếp theo, một tác vụ ECMAScript rất đơn giản khởi tạo một mảng bidd để chứa các phản hồi ngân hàng đến. Đoạn mã này chỉ chứa một dòng duy nhất:
job.bids = new Array();
Nhiệm vụ tiếp theo là một tác vụ Xuất Tín hiệu mà công bố đối tượng bankRequest vào kênh bank.loan.request. Đây là một hành động bất đồng bộ, vì vậy quy trình ngay lập tức chuyển sang bước tiếp theo mà không chờ đợi phản hồi.
Các tác vụ sau đây chờ nhận các tin nhắn phản hồi báo giá đến trên kênh bank.loan.reply. Nếu một tin nhắn được nhận trong khoảng thời gian timeout được chỉ định, tác vụ kịch bản sẽ thêm tin nhắn đã nhận vào mảng bids.
job.bids[job.bids.length] = job.loanReply;
Khi thời gian đấu giá kết thúc, tác vụ Signal In sẽ hết thời gian và chuyển quá trình sang tác vụ cuối cùng. Tác vụ ECMAScript này thực hiện thuật toán tổng hợp của Aggregator, chọn báo giá tốt nhất từ tất cả các lượt đấu giá. Đoạn mã tạo một phiên bản mới của LoanQuoteReply, chuyển các trường SSN và LoanAmount từ đối tượng yêu cầu sang đối tượng trả lời, và lặp qua mảng các lượt đấu giá để tìm báo giá tốt nhất.
var loanReply = new aeclass.LoanQuoteReply(); loanReply.SSN = job.request.SSN; loanReply.LoanAmount = job.request.LoanAmount; var bids = job.bids; for(var i = 0; i < bids.length; i++){ var item = bids[i]; if(i == 0 || (item.InterestRate < loanReply.InterestRate)){ loanReply.InterestRate = item.InterestRate; loanReply.QuoteID = item.QuoteID; } } job.loanReply = loanReply; Dòng cuối cùng của đoạn mã ECMA đặt đối tượng phản hồi khoản vay để được trả lại cho khách hàng vào một vị trí công việc. Chúng tôi đã cấu hình trình tạo công việc môi giới khoản vay để trả lại thuộc tính loanReply của công việc cho khách hàng như một thông điệp phản hồi (xem hình). Khi quá trình hoàn tất, trình tạo công việc sẽ kéo thông điệp được tìm thấy trong thuộc tính loanReply của công việc và trả giá trị đó về cho khách hàng.
Cấu hình Tập Quy Tắc Tạo Công Việc để Trả Về Báo Giá Tốt Nhất

Việc triển khai cuộc đấu giá đã gặp một số rào cản phát triển. Tính đồng thời thêm một mức độ phức tạp cho vấn đề. Để cuộc đấu giá hoạt động, chúng ta cần công bố một thông điệp bất đồng bộ, sau đó chờ một khoảng thời gian nhất định để nhận phản hồi. Tuy nhiên, nếu có nhiều cuộc đấu giá diễn ra cùng lúc, chúng ta phải đảm bảo rằng mỗi nhà môi giới cho vay chỉ nhận được những phản hồi mà họ quan tâm, không phải tất cả các phản hồi.
Chức năng này được thực hiện bằng cách sử dụng một Bộ nhận dạng tương quan và một Người tiêu dùng chọn lọc để loại bỏ các tin nhắn không liên quan. Lý tưởng nhất, chúng tôi muốn việc lọc này xảy ra ở cấp độ kênh chứ không phải ở mức phiên bản quy trình. Tuy nhiên, điều đó sẽ yêu cầu việc tạo động các chủ đề kênh tại thời gian chạy, một chủ đề cho mỗi cuộc đấu giá chưa hoàn thành. Hiện tại, có những ràng buộc trong việc triển khai trong TIB/IntegrationManager ngăn cản chúng tôi sử dụng cách tiếp cận này. Khi một sơ đồ quy trình được khởi tạo tại thời gian chạy, nó cần đăng ký tất cả các chủ đề mà nó đang lắng nghe. Điều này cho phép động cơ quy trình nghe các tin nhắn trên các chủ đề đó và xếp hàng chúng khi cần thiết. Việc xếp hàng ngăn chặn các lỗi thời gian do các sơ đồ quy trình công bố trên một chủ đề và sau đó chuyển sang trạng thái khác để lắng nghe một câu trả lời. Trong thế giới bất đồng bộ, nếu quá trình chuyển giao mất quá nhiều thời gian, câu trả lời có thể được nhận trước khi sơ đồ quy trình có cơ hội đăng ký. Do đó, sơ đồ quy trình một cách thuận tiện xếp hàng các tin nhắn đến, nhưng với cái giá là không cho phép các chủ đề động. Với yêu cầu của ví dụ hiện tại, việc lọc ở cấp độ quy trình hoạt động rất tốt. Bộ nhận dạng tương quan là một mã định danh duy nhất được gán cho mỗi quy trình và sau đó được truyền cho mỗi quy trình ngân hàng và được bao gồm trong mỗi câu trả lời. Một dòng mã ECMAScript đơn lẻ cung cấp việc lọc trong nhiệm vụ Signal In.
(event.msg.CorrelationID == job.bankRequest.CorrelationID)
Với ví dụ đã được thiết lập, chúng ta có thể chạy giải pháp. Việc chạy giải pháp liên quan đến việc khởi động động cơ TIB/IntegrationManager. Để kiểm tra giải pháp, một client kiểm tra đơn giản được bao gồm trong kho lưu trữ, gửi các yêu cầu vay mỗi 5 giây. Các stub đơn giản được sử dụng cho việc triển khai dịch vụ tín dụng và các ngân hàng. Một trong những lợi thế của kênh Publish-Subscribe là chúng ta có thể dễ dàng lắng nghe tất cả các tin nhắn trên bus tin nhắn để kiểm tra lưu lượng tin nhắn. Chúng tôi đã sử dụng một công cụ đơn giản để ghi lại tất cả các tin nhắn vào bảng điều khiển. Để rõ ràng, chúng tôi đã cắt ngắn nội dung tin nhắn để chỉ hiển thị các trường liên quan và loại bỏ thông tin nhận dạng định dạng và theo dõi được bao gồm trong mỗi tin nhắn. Từ các bản ghi, chúng tôi có thể xem thời gian, chủ đề và hộp thư của các tin nhắn. Các hộp thư là địa chỉ trả về cho các dịch vụ đồng bộ.
[View full width] tibrvlisten: Listening to subject > 2003-07-12 16:42:30 (2003-07-12 21:42:30.032000000Z): subject=customer.loan.request, reply=_INBOX.C0A80164.1743F10809898B4B60.3, SSN=1234567890 LoanAmount=100000.000000 LoanTerm=360 2003-07-12 16:42:30 (2003-07-12 21:42:30.052000000Z): subject=credit.loan.request, reply=_INBOX.C0A80164.1743F10809898B4B60.4, SSN=1234567890 2003-07-12 16:42:30 (2003-07-12 21:42:30.092000000Z): subject=bank.loan.request, SSN=1234567890 CreditScore=345 HistoryLength=456 LoanAmount=100000.000000 CorrelationID="pUQI3GEWK5Q3d-QiuLzzwGM-zzw" LoanTerm=360 2003-07-12 16:42:30 (2003-07-12 21:42:30.112000000Z): subject=bank.loan.reply, InterestRate=5.017751 QuoteID="5E0x1K_dK5Q3i-QiuMzzwGM-zzw" ErrorCode=0CorrelationID="pUQI3GEWK5Q3d-QiuLzzwGM-zzw" 2003-07-12 16:42:30 (2003-07-12 21:42:30.112000000Z): subject=bank.loan.reply, InterestRate=5.897514 QuoteID="S9iIAXqgK5Q3n-QiuNzzwGM-zzw" ErrorCode=0
CorrelationID="pUQI3GEWK5Q3d-QiuLzzwGM-zzw"
Chúng tôi thấy tin nhắn yêu cầu từ khách hàng thử nghiệm trên kênh customer.loan.request. Tin nhắn bao gồm số an sinh xã hội của khách hàng cũng như số tiền vay và thời gian mong muốn ($100,000 cho 360 tháng). Tin nhắn chỉ định kênh trả lời riêng tư của khách hàng thử nghiệm, _INBOX.C0A80164. 1743F10809898B4B60.3, làm Địa chỉ Trả về để nhà môi giới cho vay biết nơi gửi tin nhắn phản hồi.
Thông điệp tiếp theo đại diện cho yêu cầu từ môi giới vay đến dịch vụ tín dụng, mang theo hộp thư riêng của môi giới vay như là Địa chỉ Trả về. Dịch vụ tín dụng chỉ yêu cầu số an sinh xã hội. Thông điệp trả lời không được ghi lại bởi công cụ ghi chép của chúng tôi vì các kênh _INBOX là các kênh riêng tư.
Sau khi người môi giới cho vay nhận được điểm tín dụng, họ sẽ công bố một tin nhắn đến kênh yêu cầu vay của ngân hàng. Hai ngân hàng trong ví dụ của chúng ta ngay lập tức phản hồi với một lãi suất mỗi ngân hàng. Mỗi ngân hàng cũng gán một QuoteID duy nhất cho phản hồi để khách hàng có thể tham khảo sau này. Thời gian đấu giá sẽ hết hạn trong vài giây. Vì chúng ta không thể thấy tin nhắn phản hồi từ quy trình môi giới cho vay đến khách hàng thử nghiệm, chúng ta có thể kiểm tra trong nhật ký gỡ lỗi của động cơ quản lý quy trình để xác minh rằng khách hàng thử nghiệm của chúng ta đã nhận được lãi suất thấp hơn. Trong tin nhắn này, chúng ta có thể thấy CorrelationID và Format Indicator cho lớp.
reply= class/LoanQuoteReply { SSN=1234567890 InterestRate=5.017751017038945 LoanAmount=100000.0 QuoteID=5E0x1K_dK5Q3i-QiuMzzwGM-zzw } Giải pháp cung cấp một số điểm thú vị để so sánh. Quy trình làm việc trực quan có thể dễ dàng nhìn thấy và hiểu, nhưng cũng như trong mã, sự đơn giản tương đối này có thể biến thành một mê cung nhầm lẫn khi các triển khai trở nên phức tạp hơn. Tính chất động của Scatter-Gather cho phép tách biệt sạch sẽ giao diện công bố-đăng ký. Người môi giới cho vay có thể công bố yêu cầu vay ngân hàng mà không cần biết về các ngân hàng đã đăng ký. Tương tự, Bộ tổng hợp cho các phản hồi không cần biết số lượng phản hồi mong đợi. Nhược điểm tiềm ẩn của sự linh hoạt này là nó có thể ẩn giấu lỗi do việc đặt tên chủ đề không chính xác, lỗi của nhà phát triển, hoặc tin nhắn bị mất.
Triển khai trực quan dựa trên GUI với TIBCO cung cấp một phương pháp bổ sung cho các triển khai ở mức mã. Trong khi sức mạnh và sự linh hoạt của mã không thể phủ nhận, một môi trường đồ họa có thể đơn giản hóa rất nhiều nhiệm vụ phức tạp. Cấu hình là một phần rất lớn trong tích hợp, và các môi trường đồ họa hoạt động tốt cho điều này. Đôi khi, có thể có vẻ như các nhà phát triển phải lựa chọn giữa việc viết mã và sử dụng công cụ phát triển của nhà cung cấp. Tuy nhiên, chúng thường có thể đồng tồn tại hiệu quả. Ví dụ, bạn có thể chọn sử dụng TIB/IntegrationManager để mô hình hóa các quy trình làm việc tích hợp và sử dụng các bean phiên J2EE để triển khai logic miền.
Để ngắn gọn, ví dụ của chúng tôi khá đơn giản, dẫn đến một kịch bản dễ hiểu. Các triển khai thực tế hiếm khi đơn giản như vậy. Các công cụ phát triển nhanh có thể hỗ trợ phát triển ban đầu nhanh hơn nhưng có thể hạn chế các lựa chọn phát triển của bạn. Các công cụ quản lý quy trình có thể giúp che giấu sự phức tạp của việc truyền thông, cho phép các nhà phát triển tập trung vào các nhiệm vụ tích hợp mà không phải lo lắng về những gì xảy ra ở phía sau. Tuy nhiên, sự thiếu hiểu biết về hạ tầng truyền thông đã dẫn đến sự thất bại của hơn một dự án.
Giới thiệu
Cổng nhắn tin
`Bản đồ Tin nhắn`
Khách hàng giao dịch
Người tiêu dùng lấy ý kiến
Người tiêu dùng dựa trên sự kiện
Người tiêu dùng cạnh tranh
Trình gởi tin nhắn
Người tiêu dùng chọn lọc
Người đăng ký bền vững
Bộ nhận Idempotent
Kích hoạt dịch vụ
Trong Chương 3, "Hệ thống Gửi tin nhắn," chúng ta đã thảo luận về Điểm Cuối Tin Nhắn. Đây là cách mà một ứng dụng kết nối với hệ thống gửi tin nhắn để nó có thể gửi và nhận tin nhắn. Là một lập trình viên ứng dụng, khi bạn lập trình dựa trên một API gửi tin nhắn như JMS hoặc không gian tên System.Messaging, bạn đang phát triển mã điểm cuối. Nếu bạn đang sử dụng một gói phần mềm trung gian thương mại, hầu hết mã này đã được thực hiện cho bạn thông qua các thư viện và công cụ được cung cấp bởi nhà cung cấp.
Một số mẫu điểm cuối áp dụng cho cả người gửi và người nhận. Chúng liên quan đến cách mà ứng dụng liên quan đến hệ thống nhắn tin nói chung.
Đóng gói mã thông điệp Nói chung, một ứng dụng không nên biết rằng nó đang sử dụng Mã hóa để tích hợp với các ứng dụng khác. Hầu hết mã của ứng dụng nên được viết mà không cần cân nhắc đến truyền thông. Tại những điểm mà ứng dụng tích hợp với những ứng dụng khác, nên có một lớp mã mỏng thực hiện phần tích hợp của ứng dụng. Khi tích hợp được thực hiện với truyền thông, lớp mã mỏng gắn kết ứng dụng với hệ thống truyền thông là Cổng Giao Tiếp.
Dịch dữ liệu Thật tuyệt khi các ứng dụng gửi và nhận sử dụng cùng một biểu diễn dữ liệu nội bộ và khi định dạng tin nhắn cũng sử dụng biểu diễn đó. Tuy nhiên, điều này thường không xảy ra. Hoặc là bên gửi và bên nhận không đồng ý về định dạng dữ liệu, hoặc các tin nhắn sử dụng một định dạng khác (thường để hỗ trợ các bên gửi và nhận khác). Trong tình huống này, hãy sử dụng một Bộ ánh xạ Tin nhắn để chuyển đổi dữ liệu giữa định dạng của ứng dụng và định dạng của tin nhắn.
Cac giao dich duoc kiem soat ben ngoai He thong nhan tin su dung cac giao dich ben trong; ben ngoai, theo mac dinh, moi cuoc goi phuong thuc gui hoac nhan deu chay trong mot giao dich rieng. Tuy nhien, cac nha san xuat va tieu thu tin nhan co tuyet chon su dung Khach hang Giao dich de kiem soat nhung giao dich nay ben ngoai, dieu nay rat huu ich khi ban can gom nhieu tin nhan lai voi nhau hoac phoi hop nhan tin voi cac dich vu giao dich khac.
Các mẫu điểm cuối khác chỉ áp dụng cho người tiêu thụ tin nhắn. Gửi tin nhắn thì dễ. Có nhiều vấn đề liên quan đến việc quyết định khi nào một tin nhắn nên được gửi, nó nên chứa nội dung gì, và cách truyền đạt ý định của nó tới người nhận - đó là lý do tại sao chúng ta có các mẫu Xây dựng Tin nhắn (xem Chương 5, "Xây dựng Tin nhắn") nhưng một khi tin nhắn đã được xây dựng, việc gửi nó là dễ dàng. Nhận tin nhắn, ngược lại, thì phức tạp. Do đó, nhiều mẫu điểm cuối xoay quanh việc nhận tin nhắn.
Một chủ đề quan trọng trong việc tiêu thụ thông điệp là việc kiểm soát lưu lượng: khả năng của một ứng dụng để kiểm soát hoặc hạn chế tỷ lệ mà nó tiêu thụ thông điệp. Như đã được thảo luận trong phần Giới thiệu của cuốn sách, một vấn đề tiềm ẩn mà bất kỳ máy chủ nào cũng phải đối mặt là khối lượng yêu cầu từ các khách hàng cao có thể làm quá tải máy chủ. Với Gọi Thủ tục từ xa, máy chủ hầu như hoàn toàn phụ thuộc vào tỷ lệ mà các khách hàng thực hiện các cuộc gọi. Tương tự, với Hệ thống Nhắn tin, máy chủ không thể kiểm soát tỷ lệ mà các khách hàng gửi yêu cầu, nhưng máy chủ có thể kiểm soát tỷ lệ mà nó xử lý những yêu cầu đó. Ứng dụng không cần phải nhận và xử lý các thông điệp nhanh chóng như chúng được gửi đến từ hệ thống nhắn tin; nó có thể xử lý chúng với tốc độ bền vững trong khi Kênh Nhắn tin xếp hàng các thông điệp để được xử lý theo nguyên tắc ai đến trước, được phục vụ trước. Tuy nhiên, nếu các thông điệp tích tụ quá nhiều và máy chủ có đủ tài nguyên để xử lý nhiều thông điệp nhanh hơn, máy chủ có thể tăng thông lượng tiêu thụ thông điệp của nó thông qua việc sử dụng các bộ tiêu thụ thông điệp đồng thời. Vì vậy, hãy sử dụng những mẫu bộ tiêu thụ thông điệp này để cho phép ứng dụng của bạn kiểm soát tỷ lệ mà nó tiêu thụ thông điệp.
Nhiều mẫu tiêu thụ thông điệp đến theo cặp đại diện cho các lựa chọn thay thế, có nghĩa là bạn có thể thiết kế một điểm kết thúc theo cách này hoặc cách khác. Một ứng dụng duy nhất có thể thiết kế một số điểm kết thúc theo cách này và một số điểm kết thúc theo cách khác, nhưng một điểm kết thúc duy nhất chỉ có thể triển khai một lựa chọn thay thế. Các lựa chọn thay thế từ mỗi cặp có thể được kết hợp, dẫn đến một số lượng lớn các lựa chọn về cách triển khai một điểm kết thúc cụ thể.
Người tiêu dùng đồng bộ hoặc bất đồng bộ Một lựa chọn thay thế là sử dụng Người tiêu dùng Polling hoặc Người tiêu dùng Dựa trên Sự kiện [JMS 1.1], [Hapner], [Dickman]. Polling cung cấp khả năng kiểm soát tốt nhất vì nếu máy chủ bận, nó sẽ không yêu cầu thêm tin nhắn, vì vậy các tin nhắn sẽ được xếp hàng. Những người tiêu dùng dựa trên sự kiện có xu hướng xử lý các tin nhắn nhanh nhất có thể khi chúng đến, điều này có thể làm quá tải máy chủ; nhưng mỗi người tiêu dùng chỉ có thể xử lý một tin nhắn tại một thời điểm, vì vậy việc giới hạn số lượng người tiêu dùng sẽ hiệu quả kiểm soát tốc độ tiêu thụ.
Giao nhiệm vụ tin nhắn so với việc chiếm giữ tin nhắn Một lựa chọn khác liên quan đến cách một nhóm nhỏ người tiêu dùng xử lý một số tin nhắn. Nếu mỗi người tiêu dùng nhận được một tin nhắn, họ có thể xử lý các tin nhắn đồng thời. Cách tiếp cận đơn giản nhất là Người tiêu dùng cạnh tranh, trong đó một Kênh Điểm-đến-Điểm có nhiều người tiêu dùng. Mỗi người có thể lấy bất kỳ tin nhắn nào; việc triển khai hệ thống nhắn tin quyết định người tiêu dùng nào nhận được tin nhắn. Nếu bạn muốn kiểm soát quá trình khớp tin nhắn với người tiêu dùng, hãy sử dụng một Bộ phân phối Tin nhắn. Đây là một người tiêu dùng duy nhất nhận được tin nhắn nhưng ủy thác nó cho một người thực hiện để xử lý. Một ứng dụng có thể giới hạn tải trọng tin nhắn bằng cách hạn chế số lượng người tiêu dùng/người thực hiện. Ngoài ra, bộ phân phối trong một Bộ phân phối Tin nhắn có thể triển khai hành vi kiểm soát tải trọng rõ ràng.
Chấp nhận tất cả các thông điệp hoặc lọc Theo mặc định, bất kỳ thông điệp nào được gửi trên Kênh Thông điệp sẽ trở nên khả dụng cho bất kỳ Điểm kết nối Thông điệp nào lắng nghe trên kênh đó để tiêu thụ thông điệp. Tuy nhiên, một số người tiêu thụ có thể không muốn tiêu thụ bất kỳ thông điệp nào trên kênh đó, mà chỉ muốn tiêu thụ các thông điệp của một loại hoặc mô tả nhất định. Một người tiêu thụ có sự phân biệt như vậy có thể sử dụng Người tiêu thụ Chọn lọc để mô tả loại thông điệp mà họ sẵn sàng nhận. Sau đó, hệ thống nhắn tin sẽ chỉ làm cho những thông điệp phù hợp với mô tả đó có sẵn cho người nhận đó.
Đăng ký khi đang ngắt kết nối Một vấn đề phát sinh với các kênh Đăng ký - Phát hành là: nếu một người đăng ký quan tâm đến dữ liệu đang được phát hành trên một kênh cụ thể và sẽ lại quan tâm, nhưng hiện tại đang ngắt kết nối với mạng hoặc tắt máy để bảo trì thì sao? Liệu một ứng dụng đang ngắt kết nối có bỏ lỡ các tin nhắn được phát hành trong khi nó đang ngắt kết nối, ngay cả khi nó đã đăng ký? Theo mặc định, có, một đăng ký chỉ có hiệu lực khi người đăng ký đang kết nối. Để giữ cho ứng dụng không bỏ lỡ các tin nhắn được phát hành giữa các kết nối, hãy biến nó thành một Người Đăng Ký Bền Vững.
Idempotence Đôi khi cùng một tin nhắn được gửi đến nhiều lần, hoặc vì hệ thống nhắn tin không chắc chắn rằng tin nhắn đã được gửi đi thành công, hoặc vì chất lượng dịch vụ của Kênh Nhắn Tin đã bị giảm để cải thiện hiệu suất. Ngược lại, người nhận tin nhắn thường giả định rằng mỗi tin nhắn sẽ được gửi đi đúng một lần, và họ thường gặp vấn đề khi tiến hành xử lý lặp lại do các tin nhắn trùng lặp. Một người nhận được thiết kế như một Người Nhận Idempotent xử lý các tin nhắn trùng lặp một cách duyên dáng và ngăn chặn chúng gây ra vấn đề trong ứng dụng người nhận.
Dịch vụ đồng bộ hoặc không đồng bộ Một lựa chọn khó khác là liệu một ứng dụng nên cung cấp các dịch vụ của nó để được gọi theo cách đồng bộ (thông qua Gọi Thủ Tục Từ Xa) hay không đồng bộ (thông qua Nhắn Tin). Các khách hàng khác nhau có thể ưa chuộng các phương pháp khác nhau; các tình huống khác nhau có thể yêu cầu các phương pháp khác nhau. Vì thường rất khó để chọn chỉ một phương pháp này hay phương pháp kia, hãy sử dụng cả hai. Một Bộ Kích Hoạt Dịch Vụ kết nối một Kênh Nhắn Tin với một dịch vụ đồng bộ trong một ứng dụng để khi một tin nhắn được nhận, dịch vụ sẽ được gọi. Các khách hàng đồng bộ có thể đơn giản gọi dịch vụ trực tiếp; các khách hàng không đồng bộ có thể gọi dịch vụ bằng cách gửi một tin nhắn.
Một chủ đề quan trọng khác trong chương này là khó khăn khi sử dụng Khách hàng Giao dịch với các mẫu khác. Người Tiêu thụ Dựa trên Sự kiện thường không thể kiểm soát giao dịch bên ngoài một cách đúng đắn, Bộ Phát tin nhắn phải được thiết kế cẩn thận để làm như vậy, và các Người Tiêu thụ Cạnh tranh quản lý giao dịch bên ngoài có thể gặp phải những vấn đề nghiêm trọng. Cách an toàn nhất để sử dụng Khách hàng Giao dịch là với một Người Tiêu thụ Chờ đơn lẻ, nhưng đó có thể không phải là một giải pháp rất thỏa đáng.
Cần đặc biệt nhắc đến các bean điều khiển tin nhắn kiểu JMS (MDB), một loại Enterprise JavaBeans (EJB) [EJB 2.0], [Hapner]. Một MDB là một người tiêu thụ tin nhắn vừa là Người tiêu thụ dựa trên sự kiện vừa là Khách hàng giao dịch, hỗ trợ các giao dịch phân tán J2EE (ví dụ: XAResource), và nó có thể được quản lý động như các Người tiêu thụ cạnh tranh, ngay cả đối với Kênh Xuất bản-Đăng ký. Đây là một sự kết hợp khó khăn và tẻ nhạt để triển khai trong mã ứng dụng của riêng bạn, nhưng chức năng này đã được cung cấp như một tính năng sẵn có từ các bộ chứa EJB tương thích (chẳng hạn như WebLogic của BEA và WebSphere của IBM). (Khung MDB được triển khai như thế nào? Thực chất, bộ chứa triển khai một Trình phân phối Tin nhắn với một bể thực hiện có kích thước động, nơi mỗi thực hiện tiêu thụ tin nhắn bằng cách sử dụng phiên và giao dịch của chính nó.)
Cuối cùng, hãy nhớ rằng một Điểm Kết Nối Tin Nhắn đơn lẻ có thể kết hợp nhiều mẫu khác nhau từ chương này. Một nhóm Người Tiêu Thụ Cạnh Tranh có thể được triển khai như những Người Tiêu Thụ Thăm Dò cũng như là những Người Tiêu Thụ Lựa Chọn và hoạt động như một Kích Hoạt Dịch Vụ trên một dịch vụ trong ứng dụng. Một Trình Gửi Tin Nhắn có thể là một Người Tiêu Thụ Dựa Trên Sự Kiện và một Người Đăng Ký Bền Vững sử dụng một Trình Chuyển Đổi Tin Nhắn. Dù các mẫu khác mà một điểm kết nối triển khai, nó cũng nên là một Cổng Tin Nhắn. Vì vậy, đừng nghĩ đến việc sử dụng một mẫu nào đó - hãy nghĩ đến các sự kết hợp. Đó chính là vẻ đẹp của việc giải quyết các vấn đề bằng các mẫu.
Có rất nhiều tùy chọn để biến một ứng dụng thành Điểm Cuối Tin Nhắn. Chương này giải thích những tùy chọn đó là gì và cách sử dụng chúng một cách hiệu quả nhất.
Một ứng dụng truy cập một hệ thống khác qua Tin nhắn.
| Làm thế nào để bạn đóng gói quyền truy cập vào hệ thống nhắn tin từ phần còn lại của ứng dụng? |
Hầu hết các ứng dụng tùy chỉnh truy cập vào hạ tầng nhắn tin thông qua API do nhà cung cấp cung cấp. Mặc dù có nhiều loại API khác nhau, các thư viện này thường cung cấp các chức năng tương tự, chẳng hạn như "mở kênh," "tạo tin nhắn," và "gửi tin nhắn." Mặc dù loại API này cho phép ứng dụng gửi bất kỳ loại dữ liệu tin nhắn nào qua bất kỳ loại kênh nào, nhưng đôi khi rất khó để xác định ý định của việc gửi dữ liệu tin nhắn.
Giải pháp nhắn tin vốn có tính bất đồng bộ. Điều này có thể làm phức tạp mã để truy cập một chức năng bên ngoài thông qua nhắn tin. Thay vì gọi một phương thức GetCreditScore trả về điểm tín dụng số, ứng dụng phải gửi tin nhắn yêu cầu và mong đợi tin nhắn phản hồi đến vào một thời điểm sau (xem Yêu cầu-Phản hồi). Nhà phát triển ứng dụng có thể thích sự ngữ nghĩa đơn giản của một hàm đồng bộ hơn là phải xử lý các sự kiện tin nhắn đến.
Kết nối lỏng lẻo giữa các ứng dụng cung cấp những lợi thế về kiến trúc, chẳng hạn như khả năng phục hồi trước những thay đổi nhỏ trong định dạng tin nhắn (ví dụ: thêm các trường). Thông thường, kết nối lỏng lẻo được đạt được bằng cách sử dụng tài liệu XML hoặc các cấu trúc dữ liệu khác không được xác định kiểu chặt chẽ như lớp Java hoặc C#. Lập trình chống lại các cấu trúc như vậy thường khá nhàm chán và dễ mắc lỗi vì không có hỗ trợ kiểm tra kiểu tại thời điểm biên dịch để phát hiện tên trường viết sai hoặc kiểu dữ liệu không khớp. Do đó, chúng ta thường đạt được sự linh hoạt trong định dạng dữ liệu với cái giá phải trả là nỗ lực phát triển ứng dụng.
Đôi khi, một chức năng logic đơn giản cần được thực thi thông qua việc nhắn tin lại yêu cầu nhiều hơn một tin nhắn được gửi. Ví dụ, một chức năng để lấy thông tin khách hàng thực tế có thể yêu cầu nhiều tin nhắn, một tin để lấy địa chỉ, một tin khác để lấy lịch sử đơn hàng, và một tin nữa để lấy thông tin cá nhân. Mỗi tin nhắn trong số này có thể được xử lý bởi một hệ thống khác nhau. Chúng ta không muốn làm rối mã ứng dụng với tất cả logic cần thiết để gửi và nhận ba tin nhắn riêng biệt. Chúng ta có thể giảm bớt một phần gánh nặng cho ứng dụng bằng cách sử dụng một phương thức Scatter-Gather nhận một tin nhắn duy nhất, gửi ba tin nhắn riêng biệt và tổng hợp chúng trở lại thành một tin nhắn trả lời duy nhất. Tuy nhiên, không phải lúc nào chúng ta cũng có khả năng thêm chức năng này vào phần mềm nhắn tin trung gian.
| Sử dụng một Cổng Nhắn Tin, một lớp encapsulates các gọi hàm cụ thể cho nhắn tin và cung cấp các phương thức cụ thể cho miền cho ứng dụng.
|
Cổng thông điệp bao encapsulates mã liên lạc cụ thể (ví dụ: mã cần thiết để gửi hoặc nhận tin nhắn) và tách biệt nó khỏi phần còn lại của mã ứng dụng. Theo cách này, chỉ có mã Cổng thông điệp biết về hệ thống nhắn tin; phần còn lại của mã ứng dụng thì không. Cổng thông điệp cung cấp một chức năng kinh doanh cho phần còn lại của ứng dụng, vì vậy thay vì yêu cầu ứng dụng thiết lập các thuộc tính như Message.MessageReadPropertyFilter.AppSpecific, một Cổng thông điệp cung cấp các phương thức có ý nghĩa như GetCreditScore mà nhận các tham số được kiểu hóa mạnh mẽ như bất kỳ phương thức nào khác. Một Cổng thông điệp là phiên bản cụ thể về nhắn tin của mẫu Cổng tổng quát hơn [EAA].
Một Cổng loại bỏ các phụ thuộc trực tiếp giữa Ứng dụng và các Hệ thống nhắn tin.

Một Cổng Nhắn Tin nằm giữa ứng dụng và hệ thống nhắn tin và cung cấp một API theo miền cụ thể cho ứng dụng (xem hình trước). Bởi vì ứng dụng thậm chí không biết rằng nó đang sử dụng một hệ thống nhắn tin, chúng ta có thể thay thế cổng bằng một triển khai khác sử dụng công nghệ tích hợp khác, chẳng hạn như gọi thủ tục từ xa hoặc dịch vụ Web.
Nhiều Cổng Tin nhắn gửi một tin nhắn tới một thành phần khác và mong đợi một tin nhắn phản hồi (xem Yêu cầu-Phản hồi). Một Cổng Tin nhắn như vậy có thể được triển khai theo hai cách khác nhau:
Cổng thông tin nhắn (Đồng bộ) chặn
Cổng thông tin nhắn theo sự kiện (Bất đồng bộ)
Một cổng nhắn tin chặn gửi đi một tin nhắn và chờ đợi tin nhắn phản hồi đến trước khi trả lại quyền điều khiển cho ứng dụng. Khi cổng nhận được phản hồi, nó xử lý tin nhắn và trả lại kết quả cho ứng dụng (xem sơ đồ chuỗi sau).
Cổng thông tin nhắn (Đồng bộ) Chặn

Một cổng nhắn tin chặn encapsulates tính chất không đồng bộ của tương tác nhắn tin, cung cấp một phương thức đồng bộ thông thường cho logic ứng dụng. Do đó, ứng dụng không nhận thức được bất kỳ sự không đồng bộ nào trong giao tiếp. Ví dụ, một cổng chặn có thể cung cấp phương thức sau:
int GetCreditScore(string SSN);
Trong khi cách tiếp cận này làm cho việc viết mã ứng dụng chống lại Cổng nhắn tin trở nên rất đơn giản, nó cũng có thể dẫn đến hiệu suất kém vì ứng dụng cuối cùng dành phần lớn thời gian để ngồi chờ các tin nhắn phản hồi trong khi lẽ ra nó có thể thực hiện các tác vụ khác.
Một Cổng Nhắn Tin theo sự kiện (Event-driven Messaging Gateway) phơi bày tính chất bất đồng bộ của lớp nhắn tin cho ứng dụng. Khi ứng dụng thực hiện yêu cầu theo miền cụ thể đến Cổng Nhắn Tin, nó cung cấp một hàm gọi lại theo miền cụ thể cho phản hồi. Điều khiển ngay lập tức trở lại ứng dụng. Khi tin nhắn phản hồi đến, Cổng Nhắn Tin xử lý nó và sau đó gọi hàm gọi lại (xem sơ đồ tuần tự bên dưới).
Cổng thông tin nhắn dựa trên sự kiện (Bất đồng bộ)

Ví dụ, trong C#, sử dụng các ủy quyền, Cổng thông tin có thể công khai giao diện sau:
delegate void OnCreditReplyEvent(int CreditScore); void RequestCreditScore(string SSN, OnCreditReplyEvent OnCreditResponse);
Phương thức RequestCreditScore chấp nhận một tham số bổ sung, chỉ định phương thức callback sẽ được gọi khi tin nhắn phản hồi đến. Phương thức callback có một tham số CreditScore để Cổng thông tin Tin nhắn có thể truyền kết quả đến ứng dụng. Tùy thuộc vào ngôn ngữ lập trình hoặc nền tảng, callback có thể được thực hiện bằng các con trỏ hàm, tham chiếu đối tượng hoặc delegate (như được hiển thị ở đây). Lưu ý rằng mặc dù giao diện này mang tính sự kiện, nhưng không có sự phụ thuộc nào vào một công nghệ nhắn tin cụ thể.
Ngoài ra, ứng dụng có thể định kỳ kiểm tra xem kết quả đã đến chưa. Cách tiếp cận này làm cho giao diện cấp cao đơn giản mà không gây ra tình trạng chặn, về cơ bản áp dụng mẫu Half-Sync/Half-Async [POSA2]. Mẫu này mô tả việc sử dụng các bộ đệm để lưu trữ các tin nhắn đến, để ứng dụng có thể kiểm tra theo sự tiện lợi của mình xem có tin nhắn nào đã đến hay không.
Một trong những thách thức khi sử dụng Cổng Nhắn Tin theo sự kiện là Cổng Nhắn Tin yêu cầu ứng dụng duy trì trạng thái giữa phương thức yêu cầu và sự kiện callback (ngăn xếp gọi sẽ xử lý điều này trong trường hợp chặn). Khi Cổng Nhắn Tin gọi sự kiện callback vào logic ứng dụng, ứng dụng phải có khả năng liên kết phản hồi với yêu cầu mà nó đã thực hiện trước đó để có thể tiếp tục xử lý đúng luồng thực thi. Cổng Nhắn Tin có thể giúp ứng dụng dễ dàng duy trì trạng thái hơn nếu nó cho phép ứng dụng truyền một tham chiếu đến một tập hợp dữ liệu tùy ý cho phương thức yêu cầu. Cổng Nhắn Tin sẽ sau đó truyền lại dữ liệu này cho ứng dụng với sự kiện callback. Bằng cách này, ứng dụng có tất cả dữ liệu cần thiết có sẵn khi sự kiện callback bất đồng bộ được gọi. Kiểu tương tác này thường được gọi là ACT (Mã Hoàn Thành Bất Đồng Bộ) [POSA2].
Giao diện công khai của một Cổng Nhắn Tin hướng sự kiện hỗ trợ ACT có thể trông như thế này:
delegate void OnCreditReplyEvent(int CreditScore, Object ACT); void RequestCreditScore(string SSN, OnCreditReplyEvent OnCreditResponse, Object ACT);
Phương pháp RequestCreditScore có một tham số bổ sung, là một tham chiếu đến một đối tượng tổng quát. Cổng thông điệp lưu trữ tham chiếu này, chờ đợi thông điệp trả lời đến. Khi thông điệp trả lời đến, cổng gọi delegate kiểu OnCreditReplyEvent, truyền vào kết quả của quá trình cũng như tham chiếu đối tượng. Trong khi hỗ trợ một ACT là một tính năng rất tiện lợi cho ứng dụng, nó cũng mang đến nguy cơ rò rỉ bộ nhớ nếu Cổng thông điệp duy trì một tham chiếu đến một đối tượng nhưng thông điệp trả lời dự kiến không bao giờ đến.
Việc tạo ra nhiều lớp Cổng Nhắn tin có thể mang lại lợi ích. Cổng Nhắn tin "cấp thấp" có thể đơn giản chỉ là trừu tượng hóa cú pháp của hệ thống nhắn tin nhưng vẫn duy trì nghĩa nhắn tin tổng quát, ví dụ, SendMessage. Cổng Nhắn tin này có thể giúp bảo vệ phần còn lại của ứng dụng khi doanh nghiệp thay đổi công nghệ nhắn tin, chẳng hạn, từ MSMQ sang dịch vụ Web. Chúng tôi bọc Cổng Nhắn tin cơ bản này bằng một Cổng Nhắn tin bổ sung mà chuyển đổi API nhắn tin tổng quát thành một API hẹp, chuyên biệt theo miền, chẳng hạn như GetCreditScore. Chúng tôi sử dụng cấu hình này trong triển khai MSMQ của ví dụ về Môi giới Cho vay (xem hình ảnh bên dưới; cũng xem phần "Triển khai Bất đồng bộ với MSMQ" trong Chương 9, "Giữa: Nhắn tin Tổ hợp").
"Một chuỗi cổng cung cấp các cấp độ trừu tượng khác nhau."

Ngoài việc làm cho việc lập trình ứng dụng trở nên đơn giản hơn, mục đích của Cổng Thông Điệp cũng là loại bỏ sự phụ thuộc của mã ứng dụng vào các công nghệ thông điệp cụ thể. Điều này dễ dàng thực hiện bằng cách bao bọc bất kỳ cuộc gọi phương thức cụ thể nào liên quan đến thông điệp phía sau giao diện Cổng Thông Điệp. Tuy nhiên, hầu hết các lớp thông điệp đều ném ra các ngoại lệ cụ thể liên quan đến thông điệp, chẳng hạn như InvalidDestinationException do JMS phát sinh. Nếu chúng ta thực sự muốn làm cho mã ứng dụng của mình độc lập với thư viện thông điệp, Cổng Thông Điệp cần phải bắt bất kỳ ngoại lệ cụ thể nào liên quan đến thông điệp và thay vào đó ném ra một ngoại lệ cụ thể cho ứng dụng (hoặc một ngoại lệ tổng quát). Đoạn mã này có thể trở nên hơi tẻ nhạt, nhưng rất hữu ích nếu chúng ta phải chuyển đổi các triển khai bên dưới, chẳng hạn, từ JMS sang dịch vụ Web.
Trong nhiều tình huống, chúng ta có thể tạo ra mã Cổng Nhắn tin từ siêu dữ liệu được cung cấp bởi tài nguyên bên ngoài. Điều này phổ biến trong thế giới dịch vụ Web. Gần như mọi nhà cung cấp hoặc nền tảng mã nguồn mở đều cung cấp một công cụ như wsdl2java kết nối với Ngôn ngữ Mô tả Dịch vụ Web (WSDL) được cung cấp bởi một dịch vụ Web bên ngoài. Công cụ này tạo ra các lớp Java (hoặc C#, hoặc ngôn ngữ nào bạn cần) bao gói tất cả các xử lý khó khăn liên quan đến SOAP và cung cấp một lệnh gọi hàm đơn giản. Chúng tôi đã tạo ra một công cụ tương tự có thể đọc các định nghĩa lược đồ tin nhắn từ kho TIBCO và tạo ra mã nguồn Java cho một lớp giả lập định nghĩa lược đồ. Điều này cho phép các nhà phát triển ứng dụng gửi các tin nhắn TIBCO ActiveEnterprise với kiểu chính xác mà không cần phải học API của TIBCO.
Cổng thông tin nhắn là những công cụ tuyệt vời cho việc kiểm tra. Bởi vì chúng tôi đã đóng gói tất cả mã liên lạc phía sau một giao diện hẹp, cụ thể theo miền, chúng tôi có thể dễ dàng tạo ra một thực thi giả của giao diện này. Chúng tôi chỉ cần tách biệt giao diện và thực thi và cung cấp hai thực thi: một thực thi "thực" truy cập vào hạ tầng nhắn tin và một thực thi "giả" cho mục đích kiểm tra (xem hình). Thực thi giả hoạt động như một Stub Dịch vụ [EAA] và cho phép chúng tôi kiểm tra ứng dụng mà không cần phụ thuộc vào nhắn tin. Một Stub Dịch vụ cũng có thể hữu ích để gỡ lỗi một ứng dụng sử dụng Cổng thông tin nhắn theo sự kiện. Ví dụ, một stub kiểm tra đơn giản cho một Cổng thông tin nhắn theo sự kiện có thể đơn giản gọi lại (hoặc ủy quyền) ngay từ phương thức yêu cầu, thực hiện hiệu quả cả hai quá trình yêu cầu và phản hồi trong một luồng. Điều này có thể đơn giản hóa việc gỡ lỗi từng bước một cách đáng kể.
Cổng như một công cụ kiểm tra

| Ví dụ: Cổng thông tin trung gian cho vay bất đồng bộ trong MSMQ Ví dụ này cho thấy một phần của ví dụ về môi giới cho vay được giới thiệu trong Chương 9, "Khoảng giữa: Gửi tin nhắn hợp thành" (xem "Triển khai không đồng bộ với MSMQ"). [View full width] public delegate void OnCreditReplyEvent(CreditBureauReply Bạn sẽ nhận thấy rằng phương thức công khai GetCreditScore và ủy quyền công khai OnCreditReplyEvent không đề cập đến việc nhắn tin. Cách triển khai này cho phép ứng dụng gọi truyền một tham chiếu đối tượng tùy ý dưới dạng ACT. CreditBureauGateway lưu trữ tham chiếu đối tượng này trong một từ điển được đánh chỉ số bởi Mã nhận dạng tương quan của tin nhắn yêu cầu. Khi tin nhắn phản hồi đến, CreditBureauGateway có thể truy xuất dữ liệu đã được liên kết với tin nhắn yêu cầu gửi đi. Ứng dụng gọi không cần lo lắng về cách các tin nhắn được liên kết với nhau. |
Khi các ứng dụng sử dụng Nhắn tin, dữ liệu của Tin nhắn thường được lấy từ các đối tượng miền của ứng dụng. Nếu chúng ta sử dụng Tin nhắn Tài liệu, tin nhắn đó có thể đại diện trực tiếp cho một hoặc nhiều đối tượng miền. Nếu chúng ta sử dụng Tin nhắn Lệnh, một số trường dữ liệu liên quan đến lệnh có khả năng được trích xuất từ các đối tượng miền. Có một số khác biệt rõ rệt giữa tin nhắn và đối tượng. Ví dụ, hầu hết các đối tượng dựa vào các mối quan hệ dưới dạng tham chiếu đối tượng và các mối quan hệ kế thừa. Nhiều hạ tầng nhắn tin không hỗ trợ những khái niệm này vì chúng phải có khả năng giao tiếp với nhiều ứng dụng khác nhau, một số trong số đó có thể không hoàn toàn hướng đối tượng.
| Làm thế nào để bạn di chuyển dữ liệu giữa các đối tượng miền và hệ thống nhắn tin trong khi giữ cho chúng độc lập với nhau? |
Tại sao chúng ta không thể làm cho các tin nhắn của mình trông giống hệt như các đối tượng miền và khiến vấn đề đó biến mất? Trong nhiều trường hợp, chúng ta không kiểm soát định dạng tin nhắn vì nó được xác định bởi một Mô hình Dữ liệu Chính hoặc một tiêu chuẩn nhắn tin chung (ví dụ: ebXML). Chúng ta vẫn có thể xuất bản tin nhắn ở định dạng tương ứng với đối tượng miền và sử dụng một Bộ chuyển đổi Tin nhắn trong lớp nhắn tin để thực hiện các chuyển đổi cần thiết sang định dạng tin nhắn chung. Cách tiếp cận này thường được các bộ chuyển đổi sử dụng cho các hệ thống bên thứ ba không cho phép chuyển đổi bên trong ứng dụng (ví dụ: bộ chuyển đổi cơ sở dữ liệu).
Ngoài ra, lớp miền có thể tạo và xuất bản một thông điệp theo định dạng yêu cầu mà không cần đến một Bộ biên dịch thông điệp riêng biệt. Tùy chọn này thường mang lại hiệu suất tốt hơn vì chúng ta không xuất bản một thông điệp trung gian. Hơn nữa, nếu mô hình miền của chúng ta chứa nhiều đối tượng nhỏ, có thể sẽ có lợi nếu kết hợp chúng thành một thông điệp duy nhất trước tiên để đơn giản hóa việc định tuyến và cải thiện hiệu quả bên trong lớp nhắn tin. Ngay cả khi chúng ta có thể chấp nhận bước chuyển đổi bổ sung, chúng ta sẽ gặp phải những hạn chế nếu muốn tạo ra các thông điệp mô phỏng các đối tượng miền. Nhược điểm của cách tiếp cận này là miền trở nên phụ thuộc vào định dạng thông điệp, điều này khiến cho việc bảo trì miền trở nên khó khăn nếu định dạng thông điệp thay đổi.
Hầu hết các hạ tầng nhắn tin hỗ trợ khái niệm về một đối tượng "Tin nhắn" như một phần của API. Đối tượng tin nhắn này bao gồm dữ liệu sẽ được gửi qua một kênh. Trong hầu hết các trường hợp, đối tượng tin nhắn này chỉ có thể chứa các kiểu dữ liệu cơ bản như chuỗi, số hoặc ngày tháng, nhưng không hỗ trợ kế thừa hoặc tham chiếu đối tượng. Đây là một trong những điểm khác biệt chính giữa các giao tiếp theo kiểu RPC (tức là RMI) và các hệ thống nhắn tin bất đồng bộ. Giả sử chúng ta gửi một tin nhắn bất đồng bộ chứa một tham chiếu đối tượng đến một thành phần. Để xử lý tin nhắn, thành phần đó phải giải quyết tham chiếu đối tượng. Nó sẽ làm điều này bằng cách yêu cầu đối tượng từ nguồn tin nhắn. Tuy nhiên, tương tác yêu cầu-phản hồi sẽ làm thất bại một số động lực khi sử dụng nhắn tin bất đồng bộ ngay từ đầu (tức là, giảm thiểu sự liên kết giữa các thành phần). Thậm chí tồi tệ hơn, vào thời điểm tin nhắn bất đồng bộ được nhận bởi bên theo dõi, đối tượng được tham chiếu có thể không còn tồn tại trong hệ thống nguồn nữa.
Một nỗ lực để giải quyết vấn đề tham chiếu đối tượng là duyệt qua cây phụ thuộc của một đối tượng và bao gồm tất cả các đối tượng phụ thuộc trong tin nhắn. Ví dụ, nếu một đối tượng Đơn hàng tham chiếu đến năm đối tượng Mặt hàng Đơn hàng, chúng ta sẽ bao gồm năm đối tượng đó trong tin nhắn. Điều này đảm bảo rằng người nhận có quyền truy cập vào tất cả dữ liệu được tham chiếu bởi đối tượng "gốc". Tuy nhiên, nếu chúng ta sử dụng mô hình đối tượng miền chi tiết với nhiều đối tượng liên quan lẫn nhau, kích thước tin nhắn có thể nhanh chóng tăng lên. Sẽ rất mong muốn có nhiều kiểm soát hơn về những gì được bao gồm trong một tin nhắn và những gì không.
Hãy giả sử trong một khoảnh khắc rằng đối tượng miền của chúng ta là tự chứa và không có tham chiếu đến các đối tượng khác. Chúng ta vẫn không thể đơn giản chỉ đưa toàn bộ đối tượng miền vào một tin nhắn, vì hầu hết các hạ tầng nhắn tin không hỗ trợ các đối tượng do chúng phải độc lập với ngôn ngữ (giao diện JMS ObjectMessage và lớp Message trong không gian tên System.Messaging của .NET là ngoại lệ, vì các hệ thống nhắn tin này là cụ thể cho ngôn ngữ [Java] hoặc cụ thể cho nền tảng [.NET CLR]). Chúng ta có thể nghĩ đến việc tuần tự hóa đối tượng thành một chuỗi và lưu trữ nó trong một trường chuỗi gọi là "data," điều này được hầu hết mọi hệ thống nhắn tin hỗ trợ. Tuy nhiên, cách tiếp cận này cũng có những nhược điểm. Đầu tiên, một Bộ định tuyến tin nhắn sẽ không thể sử dụng các thuộc tính của đối tượng cho mục đích định tuyến vì trường chuỗi này sẽ "mờ đục" đối với lớp nhắn tin. Điều này cũng sẽ làm cho việc kiểm tra và gỡ lỗi trở nên khó khăn, vì chúng ta sẽ phải giải mã nội dung của trường dữ liệu. Hơn nữa, việc xây dựng tất cả các tin nhắn sao cho chúng chỉ chứa một trường chuỗi đơn sẽ không cho phép chúng ta định tuyến tin nhắn theo loại tin nhắn vì tất cả các tin nhắn trông giống nhau đối với hạ tầng. Sẽ cũng rất khó để xác minh định dạng chính xác của tin nhắn vì hạ tầng nhắn tin sẽ không xác minh bất cứ điều gì bên trong trường dữ liệu. Cuối cùng, chúng ta sẽ không thể sử dụng các tiện ích tuần tự hóa do thư viện thời gian chạy ngôn ngữ cung cấp vì những biểu diễn này thường không tương thích giữa các ngôn ngữ. Vì vậy, chúng ta sẽ phải viết mã tuần tự hóa riêng của mình.
Một số hạ tầng nhắn tin hiện nay hỗ trợ các trường XML bên trong tin nhắn, cho phép chúng ta có thể tuần tự hoá các đối tượng thành XML. Điều này có thể giảm bớt một số bất lợi vì các tin nhắn giờ đây dễ dàng để giải mã hơn và một số lớp nhắn tin có thể truy cập trực tiếp vào các phần tử bên trong chuỗi XML. Tuy nhiên, chúng ta giờ đây phải đối mặt với các tin nhắn khá dài dòng và việc xác thực kiểu dữ liệu bị hạn chế. Hơn nữa, chúng ta vẫn phải viết mã để chuyển đổi một đối tượng thành XML và ngược lại. Tùy thuộc vào ngôn ngữ lập trình mà chúng ta sử dụng, điều này có thể khá phức tạp, đặc biệt nếu chúng ta sử dụng một ngôn ngữ cũ không hỗ trợ phản chiếu.
Chúng ta nên tách mã ánh xạ này ra khỏi đối tượng miền vì một số lý do. Trước hết, chúng ta có thể không muốn kết hợp mã liên quan đến các tính năng ngôn ngữ cấp thấp với logic ứng dụng. Trong nhiều trường hợp, chúng ta sẽ có một nhóm lập trình viên chuyên làm việc với lớp nhắn tin, trong khi một nhóm khác tập trung vào logic miền. Việc kết hợp cả hai phần mã vào một đối tượng sẽ khiến các nhóm khó làm việc song song.
Thứ hai, việc tích hợp mã ánh xạ bên trong đối tượng miền khiến đối tượng miền phụ thuộc vào hạ tầng nhắn tin vì mã ánh xạ sẽ cần gọi vào API nhắn tin (ví dụ: để tạo đối tượng Tin nhắn). Trong hầu hết các trường hợp, sự phụ thuộc này không mong muốn vì nó ngăn cản việc tái sử dụng các đối tượng miền trong một ngữ cảnh khác mà không sử dụng nhắn tin hoặc sử dụng hạ tầng nhắn tin của nhà cung cấp khác. Kết quả là, chúng ta sẽ nghiêm trọng cản trở khả năng tái sử dụng của các đối tượng miền.
Chúng ta thường thấy mọi người viết "các lớp trừu tượng" bao bọc API hạ tầng nhắn tin, hiệu quả làm cho mã xử lý nhắn tin độc lập với API nhắn tin. Một lớp như vậy cung cấp một cấp độ gián tiếp vì nó tách biệt giao diện nhắn tin với việc triển khai nhắn tin. Do đó, chúng ta có thể tái sử dụng mã liên quan đến nhắn tin ngay cả khi phải chuyển sang lớp nhắn tin của nhà cung cấp khác. Tất cả những gì chúng ta cần làm là triển khai một lớp trừu tượng mới mà dịch giao diện nhắn tin sang API mới. Tuy nhiên, cách tiếp cận này không giải quyết được sự phụ thuộc của các đối tượng miền vào lớp nhắn tin. Các đối tượng miền giờ sẽ chứa các tham chiếu đến giao diện nhắn tin đã trừu tượng hóa thay vì API nhắn tin cụ thể của nhà cung cấp. Nhưng chúng ta vẫn không thể sử dụng các đối tượng miền trong một ngữ cảnh không sử dụng nhắn tin.
Nhiều tin nhắn được tạo thành từ nhiều đối tượng miền khác nhau. Bởi vì chúng ta không thể truyền tham chiếu đối tượng qua hạ tầng nhắn tin, nên rất có thể chúng ta cần bao gồm các trường từ các đối tượng khác. Trong một số trường hợp, chúng ta có thể bao gồm toàn bộ "cây phụ thuộc" của tất cả các đối tượng phụ thuộc bên trong một tin nhắn. Lớp nào nên giữ mã ánh xạ? Cùng một đối tượng có thể là một phần của nhiều loại tin nhắn khác nhau kết hợp với các đối tượng khác nhau, vì vậy không có câu trả lời dễ dàng cho câu hỏi này.
| Tạo một Trình ánh xạ Tin nhắn riêng biệt chứa logic ánh xạ giữa hạ tầng tin nhắn và các đối tượng miền. Cả đối tượng và hạ tầng đều không có kiến thức về sự tồn tại của Trình ánh xạ Tin nhắn.
|
Bộ lập bản đồ Nhắn tin truy cập một hoặc nhiều đối tượng miền và chuyển đổi chúng thành một thông điệp theo yêu cầu của kênh nhắn tin. Nó cũng thực hiện chức năng ngược lại, tạo hoặc cập nhật các đối tượng miền dựa trên các thông điệp đến. Vì Bộ lập bản đồ Nhắn tin được triển khai như một lớp riêng biệt tham chiếu đến cả đối tượng miền và lớp nhắn tin, nên không lớp nào nhận thức về lớp kia. Các lớp thậm chí không biết về Bộ lập bản đồ Nhắn tin.
Bản đồ Nhắn tin là một sự chuyên môn hóa của mẫu Bản đồ [EAA]. Nó có một số tương đồng với Bản đồ Dữ liệu [EAA]. Bất kỳ ai đã làm việc với các chiến lược ánh xạ O-R (Đối tượng-Quan hệ) sẽ hiểu được những phức tạp của việc ánh xạ dữ liệu giữa các lớp sử dụng các lý thuyết khác nhau. Các vấn đề vốn có trong Bản đồ Nhắn tin cũng phức tạp tương tự, và một cuộc thảo luận chi tiết về tất cả các khía cạnh có thể xảy ra vượt quá phạm vi của cuốn sách này. Nhiều mẫu Kiến trúc Nguồn Dữ liệu trong [EAA] là những tài liệu đọc tốt cho bất kỳ ai quan tâm đến việc tạo ra một lớp Bản đồ Nhắn tin.
Một Trình ánh xạ tin nhắn khác với khái niệm lớp trừu tượng thường được sử dụng bao quanh API tin nhắn. Trong trường hợp của một lớp trừu tượng, các đối tượng miền không biết về API tin nhắn, nhưng chúng biết về lớp trừu tượng (lớp trừu tượng thực hiện chức năng của một Cổng tin nhắn). Trong trường hợp của một Trình ánh xạ tin nhắn, các đối tượng hoàn toàn không biết rằng chúng đang xử lý tin nhắn.
Mục tiêu của một Messaging Mapper tương tự như Mediator [GoF], cũng được sử dụng để tách biệt các thành phần. Trong trường hợp của Mediator, các thành phần đều nhận thức được Mediator, trong khi đó, không thành phần nào nhận thức được Messaging Mapper.
Nếu cả đối tượng miền và hạ tầng nhắn tin không biết về Bộ ánh xạ nhắn tin, thì làm thế nào nó được gọi? Trong hầu hết các trường hợp, Bộ ánh xạ nhắn tin được gọi thông qua các sự kiện được kích hoạt bởi hạ tầng nhắn tin hoặc ứng dụng. Vì không bên nào phụ thuộc vào Bộ ánh xạ nhắn tin, việc thông báo sự kiện có thể xảy ra thông qua một đoạn mã riêng biệt hoặc bằng cách làm cho Bộ ánh xạ nhắn tin trở thành một mẫu Quan sát [GoF]. Ví dụ, nếu chúng ta sử dụng API JMS để giao tiếp với hạ tầng nhắn tin, chúng ta có thể triển khai giao diện MessageListener để được thông báo về bất kỳ tin nhắn đến nào. Tương tự, chúng ta có thể sử dụng một Quan sát để được thông báo về bất kỳ sự kiện liên quan nào bên trong các đối tượng miền và để gọi Bộ ánh xạ nhắn tin. Nếu chúng ta cần gọi Bộ ánh xạ nhắn tin trực tiếp từ ứng dụng, chúng ta nên định nghĩa một giao diện Bộ ánh xạ nhắn tin để ứng dụng ít nhất không phụ thuộc vào triển khai của Bộ ánh xạ nhắn tin.
Một số triển khai Messaging Mapper có thể chứa nhiều mã lặp đi lặp lại: Lấy một trường từ đối tượng miền và lưu nó vào đối tượng tin nhắn. Tiếp tục với trường tiếp theo và lặp lại cho đến khi tất cả các trường được hoàn thành. Điều này có thể khá tẻ nhạt và cũng có mùi giống như sự trùng lặp mã một cách nghi ngờ. Chúng ta có một số công cụ để giúp tránh sự tẻ nhạt này. Đầu tiên, chúng ta có thể viết một Messaging Mapper tổng quát sử dụng phản chiếu để trích xuất các trường từ một đối tượng miền một cách tổng quát. Ví dụ, nó có thể duyệt qua danh sách tất cả các trường bên trong đối tượng miền và lưu chúng vào một trường có cùng tên trong đối tượng tin nhắn. Rõ ràng, điều này chỉ hoạt động nếu tên các trường khớp nhau. Theo những cuộc thảo luận trước đây của chúng ta, chúng ta cần đưa ra một cách nào đó để giải quyết các tham chiếu đối tượng, vì chúng ta không thể lưu trữ chúng trong đối tượng tin nhắn. Sự thay thế là sử dụng một bộ tạo mã có thể cấu hình để tạo mã Messaging Mapper. Điều này cho phép chúng ta có thêm sự linh hoạt trong việc đặt tên các trường (tên trường tin nhắn và tên trường đối tượng miền không cần phải khớp nhau), và chúng ta có thể nghĩ ra những cách khéo léo để xử lý các tham chiếu đối tượng. Nhược điểm của các bộ tạo mã là chúng có thể khó kiểm tra và gỡ lỗi, nhưng nếu chúng ta làm cho nó đủ tổng quát, chúng ta chỉ cần viết nó một lần.
Một số khung làm việc, chẳng hạn như Microsoft .NET, có tính năng tuần tự hóa đối tượng tích hợp sẵn, cho phép chuyển đổi các đối tượng thành XML và ngược lại, và giảm bớt nhiều công việc nặng nhọc liên quan đến việc tuần tự hóa đối tượng. Ngay cả khi khung làm việc thực hiện một số công việc chuyển đổi đối tượng thành thông điệp, việc chuyển đổi này chỉ giới hạn ở cấp độ dịch cú pháp. Có thể rất cám dỗ để chỉ để khung làm việc thực hiện tất cả công việc, nhưng nó sẽ chỉ tạo ra các thông điệp tương ứng với các đối tượng miền một-một. Như chúng tôi đã giải thích trước đó, điều này có thể không mong muốn vì các ràng buộc và tiêu chí thiết kế cho các thông điệp rất khác biệt so với các đối tượng miền. Có thể hợp lý khi định nghĩa một tập hợp "đối tượng giao diện" tương ứng với cấu trúc thông điệp mong muốn và để khung làm việc thực hiện chuyển đổi giữa các thông điệp và những đối tượng này. Lớp Dịch vụ Nhắn tin sẽ quản lý việc dịch giữa các đối tượng miền thực sự và các đối tượng giao diện. Những đối tượng giao diện này có một số điểm tương đồng với Các Đối Tượng Chuyển Giao Dữ Liệu [EAA] mặc dù động lực có hơi khác một chút.
Ngay cả khi chúng ta sử dụng một Bộ ánh xạ Tin nhắn, việc sử dụng một Bộ chuyển đổi Tin nhắn để chuyển đổi các tin nhắn được tạo ra bởi Bộ ánh xạ Tin nhắn thành các tin nhắn tuân thủ Mô hình Dữ liệu Canonical vẫn có ý nghĩa. Điều này cung cấp cho chúng ta một cấp độ gián tiếp bổ sung. Chúng ta có thể sử dụng Bộ ánh xạ Tin nhắn để giải quyết các vấn đề như tham chiếu đối tượng và chuyển đổi kiểu dữ liệu, và để lại các ánh xạ cấu trúc cho một Bộ chuyển đổi Tin nhắn bên trong lớp tin nhắn. Giá mà chúng ta phải trả cho sự tách biệt bổ sung này là sự tạo ra một thành phần bổ sung và một chút hình phạt về hiệu suất. Ngoài ra, đôi khi dễ dàng hơn để thực hiện các chuyển đổi phức tạp bên trong ngôn ngữ lập trình của ứng dụng hơn là sử dụng "phần mềm kéo và thả" do nhà cung cấp tích hợp cung cấp.
Nếu chúng ta sử dụng cả Một Bộ Lập Bản Tin và Một Bộ Dịch Tin Nhắn, chúng ta sẽ có thêm một mức độ gián tiếp giữa định dạng dữ liệu chuẩn và các đối tượng miền. Người ta đã nói rằng khoa học máy tính là lĩnh vực mà mọi vấn đề có thể được giải quyết chỉ bằng cách thêm một mức độ gián tiếp nữa, vậy quy tắc này có đúng trong trường hợp này không? Sự gián tiếp bổ sung cho chúng ta khả năng bù đắp cho những thay đổi trong mô hình chuẩn bên trong lớp nhắn tin mà không cần phải chạm vào mã ứng dụng. Nó cũng cho phép chúng ta đơn giản hóa logic ánh xạ bên trong ứng dụng bằng cách để cho các ánh xạ trường tẻ nhạt và thay đổi kiểu dữ liệu (ví dụ: trường ZIP_Code dạng số sang trường Postal_Code dạng chữ và số) cho các công cụ ánh xạ của lớp nhắn tin mà được tối ưu hóa cho loại công việc này. Bộ Lập Bản Tin sẽ chủ yếu xử lý việc giải quyết tham chiếu đối tượng và loại bỏ các chi tiết không cần thiết của đối tượng miền. Nhược điểm rõ ràng của mức độ gián tiếp bổ sung là một thay đổi trong đối tượng miền bây giờ có thể yêu cầu thay đổi cả Bộ Lập Bản Tin và Bộ Dịch Tin Nhắn. Nếu chúng ta có thể tạo mã cho Bộ Lập Bản Tin, vấn đề này sẽ phần lớn không còn.
Kết hợp Mapper và Bộ dịch Tin nhắn

| Ví dụ: Bộ ánh xạ tin nhắn trong JMS Lớp AuctionAggregate trong ví dụ Aggregator JMS hoạt động như một Bộ chuyển đổi Tin nhắn giữa hệ thống tin nhắn JMS và lớp Bid. Các phương thức addMessage và getResultMessage chuyển đổi giữa các tin nhắn JMS và các đối tượng Bid. Cả hệ thống tin nhắn lẫn lớp Bid đều không biết về sự tương tác này. |
Một hệ thống nhắn tin, theo nhu cầu, sử dụng hành vi giao dịch bên trong. Có thể hữu ích cho một khách hàng bên ngoài để có thể kiểm soát phạm vi của các giao dịch ảnh hưởng đến hành vi của nó.
| Làm thế nào một khách hàng có thể kiểm soát các giao dịch của mình với hệ thống nhắn tin? |
Hệ thống nhắn tin phải sử dụng giao dịch nội bộ. Một Kênh Nhắn tin duy nhất có thể có nhiều người gửi và nhiều người nhận, vì vậy hệ thống nhắn tin phải phối hợp các tin nhắn để đảm bảo rằng các người gửi không ghi đè lên nhau, các người nhận Kênh Điểm-đến-Điểm không nhận cùng một tin nhắn, các người nhận Kênh Xuất-bản-Đăng-ký mỗi người nhận một bản sao của mỗi tin nhắn, và những điều tương tự. Để quản lý tất cả những điều này, các hệ thống nhắn tin trong nội bộ sử dụng giao dịch để đảm bảo rằng một tin nhắn được thêm vào hoặc không được thêm vào kênh, và được đọc hoặc không được đọc từ kênh. Các hệ thống nhắn tin cũng phải sử dụng giao dịch, tốt nhất là giao dịch phân tán hai pha, để sao chép một tin nhắn từ máy tính của người gửi sang máy tính của người nhận, sao cho vào bất kỳ thời điểm nào, tin nhắn "thực sự" chỉ nằm trên một máy tính hoặc máy tính kia.
Các điểm kết nối tin nhắn gửi và nhận tin nhắn đều mang tính giao dịch, ngay cả khi họ không nhận ra điều đó. Phương thức gửi mà thêm một tin nhắn vào một kênh thực hiện điều này trong một giao dịch để cô lập tin nhắn đó khỏi bất kỳ tin nhắn nào khác đang được thêm vào hoặc gỡ bỏ khỏi kênh đó đồng thời. Tương tự, phương thức nhận cũng sử dụng một giao dịch, điều này ngăn chặn các người nhận điểm tới điểm khác nhận cùng một tin nhắn và thậm chí đảm bảo rằng một người nhận theo mô hình xuất bản - đăng ký sẽ không đọc cùng một tin nhắn hai lần.
Giao dịch thường được mô tả là ACID: nguyên tử, nhất quán, cách ly và bền vững. Chỉ có các giao dịch cho Tin nhắn Đảm bảo mới là bền vững, và một tin nhắn về bản chất là nguyên tử. Nhưng tất cả các giao dịch tin nhắn đều phải nhất quán và cách ly. Một tin nhắn không thể ở trạng thái mập mờ trong kênh; nó either là hoặc không là. Ngoài ra, việc gửi và nhận tin nhắn của một ứng dụng phải được cách ly khỏi bất kỳ luồng và ứng dụng nào khác có thể đang gửi và nhận tin nhắn qua cùng một kênh.
Hệ thống nhắn tin có các giao dịch nội bộ đủ và tiện lợi cho một khách hàng chỉ muốn gửi hoặc nhận một tin nhắn đơn lẻ. Tuy nhiên, một ứng dụng có thể cần một giao dịch rộng hơn để phối hợp nhiều tin nhắn hoặc để phối hợp việc nhắn tin với các tài nguyên khác. Các tình huống phổ biến như vậy bao gồm
Gửi-Nhận Cặp Tin Nhắn Nhận một tin nhắn và gửi một tin nhắn khác, chẳng hạn như một kịch bản Yêu cầu-Phản hồi hoặc khi triển khai một bộ lọc tin nhắn như Router Tin Nhắn hoặc Biên dịch viên Tin Nhắn.
Nhóm Tin Nhắn Gửi hoặc nhận một nhóm các tin nhắn liên quan, chẳng hạn như một Chuỗi Tin Nhắn.
Đồng bộ thông điệp/Cơ sở dữ liệu Kết hợp việc gửi hoặc nhận một thông điệp với việc cập nhật cơ sở dữ liệu, chẳng hạn như với một Bộ điều hợp Kênh. Ví dụ, khi một ứng dụng nhận và xử lý một thông điệp để đặt hàng một sản phẩm, ứng dụng cũng cần cập nhật cơ sở dữ liệu tồn kho sản phẩm. Tương tự, người gửi Thông điệp Tài liệu có thể muốn xóa một tài liệu đã được lưu trữ, nhưng chỉ khi nó được gửi thành công; người nhận có thể muốn lưu trữ tài liệu trước khi thông điệp thực sự được coi là đã được tiêu thụ.
Phối hợp Tin nhắn/Quy trình Sử dụng một cặp tin nhắn Yêu cầu-Phản hồi để thực hiện một mục công việc, và sử dụng giao dịch để đảm bảo rằng mục công việc không được nhận nếu yêu cầu cũng không được gửi, và mục công việc không được hoàn thành hoặc hủy bỏ trừ khi phản hồi cũng được nhận.
Các kịch bản như thế này yêu cầu một giao dịch nguyên tử lớn hơn, liên quan đến nhiều hơn chỉ một thông điệp đơn và có thể liên quan đến các kho giao dịch khác ngoài hệ thống nhắn tin. Một giao dịch là cần thiết để nếu một phần của kịch bản hoạt động (như nhận thông điệp, ví dụ) nhưng một phần khác không (như cập nhật cơ sở dữ liệu hoặc gửi một thông điệp khác), tất cả các phần có thể được hoàn tác như thể chúng chưa từng xảy ra, và sau đó ứng dụng có thể thử lại.
Tuy nhiên, mô hình giao dịch nội bộ của một hệ thống nhắn tin là không đủ để cho phép một ứng dụng phối hợp xử lý một tin nhắn với các tin nhắn khác hoặc các tài nguyên khác. Điều cần thiết là một cách để ứng dụng có thể kiểm soát bên ngoài các giao dịch của hệ thống nhắn tin và kết hợp chúng với các giao dịch khác trong hệ thống nhắn tin hoặc ở nơi khác.
| Sử dụng một Khách hàng Giao dịch để tạo phiên làm việc của khách hàng với hệ thống nhắn tin theo cách giao dịch, để khách hàng có thể chỉ định ranh giới giao dịch.
|
Cả người gửi và người nhận đều có thể là giao dịch. Đối với người gửi, thông điệp thực sự không được thêm vào kênh cho đến khi người gửi xác nhận giao dịch. Đối với người nhận, thông điệp thực sự không được xóa khỏi kênh cho đến khi người nhận xác nhận giao dịch. Một người gửi sử dụng giao dịch rõ ràng có thể được sử dụng với một người nhận sử dụng giao dịch ngầm, và ngược lại. Một kênh đơn lẻ có thể có sự kết hợp của những người gửi giao dịch ngầm và rõ ràng; nó cũng có thể có sự kết hợp của các người nhận.
Chuỗi Nhận Giao Dịch

Với một bộ nhận giao dịch, một ứng dụng có thể nhận một thông điệp mà không thực sự loại bỏ thông điệp đó khỏi hàng đợi. Tại thời điểm này, nếu ứng dụng gặp sự cố, khi nó phục hồi, thông điệp vẫn sẽ còn trong hàng đợi; thông điệp sẽ không bị mất. Sau khi nhận được thông điệp, ứng dụng có thể xử lý nó. Khi ứng dụng hoàn tất với thông điệp và chắc chắn rằng nó muốn tiêu thụ thông điệp, ứng dụng sẽ cam kết giao dịch, điều này (nếu thành công) sẽ loại bỏ thông điệp khỏi kênh. Tại thời điểm này, nếu ứng dụng gặp sự cố, khi nó phục hồi, thông điệp sẽ không còn trên kênh, vì vậy ứng dụng cần thực sự hoàn tất với thông điệp.
Việc kiểm soát giao dịch của hệ thống nhắn tin từ bên ngoài giúp ứng dụng phối hợp nhiều nhiệm vụ như thế nào? Đây là những gì ứng dụng sẽ thực hiện trong các kịch bản đã được mô tả trước đó:
Cặp tin nhắn Gửi-Nhận
Cần làm gì: Bắt đầu một giao dịch, nhận và xử lý tin nhắn đầu tiên, tạo và gửi tin nhắn thứ hai, sau đó cam kết. (Hành vi này thường được triển khai như một phần của Yêu cầu-Trả lời, Bộ định tuyến Tin nhắn và Biên dịch Tin nhắn.)
Điều này giữ cho tin nhắn đầu tiên không bị xóa khỏi kênh của nó cho đến khi tin nhắn thứ hai được thêm thành công vào kênh của nó.
Loại giao dịch: Nếu hai tin nhắn được gửi qua các kênh trong cùng một hệ thống nhắn tin, giao dịch bao gồm hai kênh này là đơn giản. Tuy nhiên, nếu hai kênh được quản lý bởi hai hệ thống nhắn tin riêng biệt, chẳng hạn như với một Cầu Nhắn Tin, giao dịch sẽ là một giao dịch phân tán phối hợp giữa hai hệ thống nhắn tin.
Cảnh báo: Một giao dịch đơn chỉ hoạt động cho người nhận của một yêu cầu gửi phản hồi. Người gửi yêu cầu không thể sử dụng một giao dịch đơn để gửi yêu cầu và chờ đợi phản hồi. Nếu cố gắng làm điều này, yêu cầu sẽ không bao giờ thực sự được gửi vì giao dịch gửi không được thực hiện, do đó phản hồi sẽ không bao giờ được nhận.
Nhóm Tin Nhắn
Điều cần làm: Bắt đầu một giao dịch, gửi hoặc nhận tất cả các tin nhắn trong nhóm (chẳng hạn như một Chuỗi Tin nhắn), sau đó thực hiện cam kết.
Điều này có nghĩa: Khi gửi, không có tin nhắn nào trong nhóm sẽ được thêm vào kênh cho đến khi tất cả đều được gửi thành công. Khi nhận, không có tin nhắn nào sẽ bị xóa khỏi kênh cho đến khi tất cả đều được nhận.
Loại giao dịch: Vì tất cả các tin nhắn đều được gửi đến hoặc nhận từ một kênh duy nhất, kênh đó sẽ được quản lý bởi một hệ thống nhắn tin duy nhất, vì vậy giao dịch sẽ rất đơn giản. Ngoài ra, trong nhiều triển khai hệ thống nhắn tin, việc gửi một nhóm tin nhắn trong một giao dịch duy nhất đảm bảo rằng chúng sẽ được nhận ở đầu bên kia của kênh theo thứ tự chúng được gửi.
Điều phối Tin nhắn/Cơ sở dữ liệu
Cần làm gì: Bắt đầu một giao dịch, nhận một tin nhắn, cập nhật cơ sở dữ liệu và sau đó cam kết. Hoặc, cập nhật cơ sở dữ liệu và gửi một tin nhắn để báo cáo về việc cập nhật cho người khác, và sau đó cam kết. (Hành vi này thường được thực hiện bởi một Bộ chuyển đổi Kênh.)
Điều này có nghĩa là: Tin nhắn sẽ không được xóa trừ khi cơ sở dữ liệu được cập nhật (hoặc sự thay đổi trong cơ sở dữ liệu sẽ không được lưu nếu tin nhắn không thể được gửi).
Loại giao dịch: Vì hệ thống nhắn tin và cơ sở dữ liệu mỗi cái đều có trình quản lý giao dịch riêng, giao dịch để phối hợp chúng sẽ là một giao dịch phân tán.
Điều phối Thông điệp/Quy trình
Những gì cần làm: Sử dụng một cặp tin nhắn Yêu cầu-Trả lời để thực hiện một mục công việc. Bắt đầu một giao dịch, lấy mục công việc, gửi tin nhắn yêu cầu, và sau đó cam kết. Hoặc, bắt đầu một giao dịch khác, nhận tin nhắn trả lời, hoàn thành hoặc hủy bỏ mục công việc, rồi cam kết.
Điều này có nghĩa là: Mục công việc sẽ không được cam kết trừ khi yêu cầu được gửi; phản hồi sẽ không bị xóa trừ khi mục công việc được cập nhật.
Loại giao dịch: Vì hệ thống nhắn tin và động cơ quy trình làm việc mỗi cái đều có trình quản lý giao dịch riêng, nên giao dịch để phối hợp chúng sẽ là một giao dịch phân tán.
Theo cách này, ứng dụng có thể đảm bảo rằng nó sẽ không mất những tin nhắn mà nó nhận được hoặc quên gửi một tin nhắn mà nó cần gửi. Nếu có điều gì đó sai sót giữa chừng, ứng dụng có thể hoàn tác giao dịch và thử lại.
Khách hàng giao dịch sử dụng Người tiêu dùng dựa trên sự kiện có thể không hoạt động như mong đợi. Người tiêu dùng thường phải cam kết giao dịch để nhận tin nhắn trước khi chuyển tin nhắn cho ứng dụng. Sau đó, nếu ứng dụng kiểm tra tin nhắn và quyết định không muốn tiêu thụ nó, hoặc nếu ứng dụng gặp phải lỗi và muốn quay lại hành động tiêu thụ, thì nó không thể làm điều đó vì không có quyền truy cập vào giao dịch. Vì vậy, một người tiêu dùng dựa trên sự kiện có xu hướng hoạt động giống nhau dù khách hàng của nó có phải là giao dịch hay không.
Hệ thống nhắn tin có khả năng tham gia vào một giao dịch phân tán, mặc dù một số triển khai có thể không hỗ trợ điều này. Trong JMS, một nhà cung cấp có thể đóng vai trò như một tài nguyên XA và tham gia vào các giao dịch Java Transaction API [JTA]. Hành vi này được định nghĩa bởi các lớp XA trong gói javax.jms, đặc biệt là javax.jms.XASession, và bởi gói javax.transaction.xa. Đặc tả JMS khuyến nghị rằng các khách hàng JMS không nên cố gắng xử lý các giao dịch phân tán trực tiếp, vì vậy một ứng dụng nên sử dụng hỗ trợ giao dịch phân tán được cung cấp bởi một máy chủ ứng dụng J2EE. MSMQ cũng có thể tham gia vào một giao dịch XA; hành vi này được tiết lộ trong .NET bởi thuộc tính MessageQueue.Transactional và lớp MessageQueueTransaction.
Như đã thảo luận trước đó, Khách hàng Giao dịch có thể hữu ích như một phần của các mẫu khác, chẳng hạn như Yêu cầu-Trả lời, bộ lọc tin nhắn trong Ống và Bộ lọc, Chuỗi Tin nhắn và Bộ điều hợp Kênh. Tương tự, người nhận của một Tin nhắn Sự kiện có thể muốn hoàn tất xử lý sự kiện trước khi hoàn toàn xóa tin nhắn của mình khỏi kênh. Tuy nhiên, Khách hàng Giao dịch không hoạt động tốt với Người tiêu dùng Điều khiển Sự kiện hoặc Bộ phân phối Tin nhắn, có thể gây ra vấn đề cho các Người tiêu dùng Cạnh tranh, nhưng hoạt động tốt với một Người tiêu dùng Thăm dò duy nhất.
| Ví dụ: Phiên giao dịch JMS Trong JMS, một client tự làm cho mình trở thành giao dịch khi tạo phiên của nó [JMS 1.1], [Hapner]. Connection connection = // Get the connection Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); Buổi họp này là giao dịch bởi vì tham số đầu tiên của createSession được đặt thành true. Khi một khách hàng đang sử dụng phiên giao dịch, nó phải cam kết rõ ràng việc gửi và nhận để biến chúng thành thật. Queue queue = // Get the queue MessageConsumer consumer = session.createConsumer(queue); Message message = consumer.receive(); Tại thời điểm này, thông điệp chỉ được tiêu thụ trong cái nhìn giao dịch của người tiêu dùng. Nhưng đối với những người tiêu dùng khác với cái nhìn giao dịch riêng của họ, thông điệp vẫn còn khả dụng. session.commit(); Bây giờ, giả sử rằng thông điệp cam kết không phát sinh bất kỳ ngoại lệ nào, cái nhìn giao dịch của người tiêu dùng trở thành của hệ thống tin nhắn, mà giờ đây coi thông điệp đã được tiêu thụ. |
| Ví dụ: Hàng đợi giao dịch .NET Trong .NET, hàng đợi không phải là giao dịch theo mặc định, vì vậy để sử dụng một client giao dịch, hàng đợi phải được tạo ra với tính chất giao dịch. MessageQueue.Create("MyQueue", true); Một khi hàng đợi trở thành giao dịch, mỗi hành động của khách hàng (gửi hoặc nhận) trên hàng đợi có thể là giao dịch hoặc không phải giao dịch. Một lần nhận giao dịch trông như thế này: MessageQueue queue = new MessageQueue("MyQueue"); MessageQueueTransaction transaction = new MessageQueueTransaction(); transaction.Begin(); Message message = queue.Receive(transaction); transaction.Commit(); Mặc dù khách hàng đã nhận được tin nhắn, hệ thống nhắn tin không làm tin nhắn không khả dụng trong hàng đợi cho đến khi khách hàng hoàn tất giao dịch thành công [SysMsg]. |
| Ví dụ: Bộ lọc giao dịch với MSMQ Ví dụ sau đây cải thiện thành phần bộ lọc cơ bản đã được giới thiệu trong Pipes và Filters để sử dụng giao dịch. Ví dụ này thực hiện kịch bản Gửi-Nhận Cặp Tin Nhắn, nhận và gửi một tin nhắn trong cùng một giao dịch. Chúng ta thực sự chỉ cần thêm một vài dòng mã để làm cho bộ lọc trở thành giao dịch. Chúng ta sử dụng một biến kiểu MessageQueueTransaction để quản lý giao dịch. Chúng ta mở một giao dịch trước khi tiêu thụ tin nhắn đầu vào và cam kết sau khi chúng ta phát hành tin nhắn đầu ra. Nếu có bất kỳ ngoại lệ nào xảy ra, chúng ta hủy bỏ giao dịch, điều này sẽ hoàn tác tất cả các hành động tiêu thụ và phát hành tin nhắn và trả lại tin nhắn đầu vào vào hàng đợi để có sẵn cho những người tiêu thụ hàng đợi khác. [View full width] public class TransactionalFilter { protected MessageQueue inputQueue; protected MessageQueue outputQueue; protected Thread receiveThread; protected bool stopFlag = false; public TransactionalFilter (MessageQueue inputQueue, Làm thế nào để chúng tôi xác minh rằng Khách hàng Giao dịch của chúng tôi hoạt động như mong muốn? Chúng tôi tạo một lớp con của lớp Filtre Giao dịch cơ bản, lớp có tên là Filtre Thất bại Ngẫu nhiên. Đối với mỗi tin nhắn được tiêu thụ, bộ lọc này rút ra một số ngẫu nhiên từ 0 đến 10. Nếu số đó nhỏ hơn 3, nó sẽ ném ra một ngoại lệ tùy ý (Ngoại lệ Tham số Null có vẻ thuận tiện cho một ví dụ). Nếu chúng tôi triển khai bộ lọc này dựa trên bộ lọc không giao dịch cơ bản mà đã được mô tả trong Pipes và Filters, chúng tôi sẽ mất khoảng một trong ba tin nhắn. [View full width] public class RandomlyFailingFilter : TransactionalFilter { Random rand = new Random(); public RandomlyFailingFilter(MessageQueue inputQueue, Để đảm bảo rằng chúng tôi không mất bất kỳ tin nhắn nào với phiên bản giao dịch, chúng tôi đã thiết lập một bộ thử nghiệm đơn giản để phát một chuỗi tin nhắn vào hàng đợi đầu vào và đảm bảo rằng nó có thể nhận tất cả các tin nhắn theo đúng thứ tự từ hàng đợi đầu ra. Điều quan trọng cần nhớ là các tin nhắn đầu ra vẫn giữ thứ tự chỉ khi chúng tôi chạy một phiên bản duy nhất của bộ lọc giao dịch. Nếu chúng tôi chạy nhiều bộ lọc song song, các tin nhắn có thể (và sẽ) bị mất thứ tự. [View full width] public void RunTests() { MessageQueueTransaction myTransaction = new |
Một ứng dụng cần tiêu thụ các tin nhắn, nhưng nó muốn kiểm soát khi nào tiêu thụ mỗi tin nhắn.
| Làm thế nào một ứng dụng có thể tiêu thụ một thông điệp khi ứng dụng đã sẵn sàng? |
Người tiêu thụ tin nhắn thoát ra với một lý do để tiêu thụ tin nhắn. Các tin nhắn đại diện cho công việc cần phải được thực hiện, vì vậy người tiêu thụ cần phải tiêu thụ những tin nhắn đó và thực hiện công việc.
Nhưng làm thế nào để người tiêu dùng biết khi nào có một thông điệp mới? Cách đơn giản nhất là để người tiêu dùng kiểm tra liên tục kênh để xem có tin nhắn nào không. Khi có một thông điệp, họ tiêu thụ thông điệp đó và sau đó quay lại kiểm tra thông điệp tiếp theo. Quy trình này được gọi là polling.
Đặc điểm của việc polling là người tiêu dùng có thể yêu cầu tin nhắn tiếp theo khi nó đã sẵn sàng cho một tin nhắn khác. Do đó, người tiêu dùng tiếp nhận tin nhắn với tốc độ mà họ muốn chứ không phải với tốc độ mà chúng đến trong kênh.
| Ứng dụng nên sử dụng một Người tiêu dùng Theo dõi, một cái mà rõ ràng thực hiện một cuộc gọi khi nó muốn nhận một tin nhắn.
|
Điều này còn được gọi là một bộ thu đồng bộ, vì luồng bộ thu chặn cho đến khi một thông điệp được nhận. Chúng tôi gọi nó là Nhà tiêu thụ Polling vì bộ thu kiểm tra thông điệp, xử lý nó, rồi lại kiểm tra một cái khác. Như một sự thuận tiện, các API nhắn tin thường cung cấp một phương thức nhận chặn cho đến khi một thông điệp được giao bên cạnh các phương thức như receiveNoWait() và Receive(0) mà trả về ngay lập tức nếu không có thông điệp nào sẵn có. Sự khác biệt này chỉ rõ ràng khi bộ thu đang kiểm tra nhanh hơn tốc độ thông điệp đến.
Một Người Tiêu Thụ Đang Thăm Dò là một đối tượng mà một ứng dụng sử dụng để nhận thông điệp bằng cách yêu cầu rõ ràng chúng. Khi ứng dụng sẵn sàng nhận một thông điệp khác, nó sẽ thăm dò người tiêu thụ, người này sẽ lấy một thông điệp từ hệ thống nhắn tin và trả lại cho ứng dụng. (Cách mà người tiêu thụ nhận thông điệp từ hệ thống nhắn tin là tùy thuộc vào cách cài đặt và có thể có hoặc không có việc thăm dò. Tất cả những gì ứng dụng biết là nó sẽ không nhận được thông điệp cho đến khi nó yêu cầu rõ ràng một thông điệp.)
Dãy Thăm Dò Người Tiêu Dùng

Khi ứng dụng kiểm tra tin nhắn, người tiêu dùng sẽ chặn lại cho đến khi nhận được một tin nhắn để trả về (hoặc cho đến khi một điều kiện khác được thỏa mãn, chẳng hạn như thời gian giới hạn). Khi ứng dụng nhận được tin nhắn, nó có thể xử lý. Khi nó hoàn tất việc xử lý tin nhắn và muốn nhận một tin nhắn khác, ứng dụng có thể kiểm tra lại.
Bằng cách sử dụng Việc Tiêu thụ qua Cuộc thăm dò, một ứng dụng có thể kiểm soát số lượng tin nhắn được tiêu thụ đồng thời bằng cách giới hạn số lượng luồng đang thực hiện cuộc thăm dò. Điều này có thể giúp ngăn chặn ứng dụng nhận tin bị quá tải bởi quá nhiều yêu cầu; các tin nhắn thêm sẽ xếp hàng cho đến khi người nhận có thể xử lý chúng.
Một ứng dụng nhận thường sử dụng ít nhất một luồng cho mỗi kênh mà nó muốn giám sát, nhưng nó cũng có thể sử dụng một luồng duy nhất để giám sát nhiều kênh, điều này giúp tiết kiệm luồng khi giám sát các kênh thường xuyên trống. Để kiểm tra một kênh duy nhất, giả sử rằng luồng không có gì để làm cho đến khi có một tin nhắn đến, hãy sử dụng một phiên bản của hàm nhận (receive) chặn cho đến khi một tin nhắn đến. Để kiểm tra nhiều kênh với một luồng duy nhất, hoặc để thực hiện các công việc khác trong khi chờ đợi một tin nhắn đến, hãy sử dụng một phiên bản của hàm nhận với thời gian chờ (timeout) hoặc receiveNoWait() để nếu một kênh trống, luồng sẽ tiếp tục kiểm tra một kênh khác hoặc thực hiện các công việc khác.
Một người tiêu dùng quá nhiều truy vấn hoặc chặn các luồng quá lâu có thể không hiệu quả, trong trường hợp đó một Người Tiêu Dùng Dựa Trên Sự Kiện có thể hiệu quả hơn. Nhiều Người Tiêu Dùng Truy Vấn có thể là Những Người Tiêu Dùng Cạnh Tranh. Một Bộ Phận Tin Nhắn có thể được triển khai như một Người Tiêu Dùng Truy Vấn. Một Người Tiêu Dùng Truy Vấn có thể là một Người Tiêu Dùng Lựa Chọn; nó cũng có thể là một Người Đăng Ký Bền Vững. Một Người Tiêu Dùng Truy Vấn cũng có thể là một Khách Hàng Giao Dịch để người tiêu dùng có thể kiểm soát khi nào tin nhắn thực sự được xóa khỏi kênh.
| Ví dụ: Nhận JMS Trong JMS, một nhà tiêu thụ tin nhắn sử dụng MessageConsumer.receive để tiêu thụ một tin nhắn đồng bộ. `MessageConsumer có ba phương thức nhận khác nhau:`
Ví dụ, mã để tạo một người tiêu dùng và nhận một tin nhắn rất đơn giản: Destination dest = // Get the destination Session session = // Create the session MessageConsumer consumer = session.createConsumer(dest); Message message = consumer.receive(); |
| Ví dụ: .NET Nhận Trong .NET, một nhà tiêu thụ sử dụng MessageQueue.Receive để tiêu thụ một tin nhắn đồng bộ. Một khách hàng MessageQueue có nhiều biến thể của phương thức nhận. Hai biến thể đơn giản nhất là
Mã để nhận tin nhắn từ một hàng đợi hiện có khá đơn giản: MessageQueue queue = // Get the queue Message message = queue.Receive(); |
Một ứng dụng cần tiêu thụ các Tin nhắn ngay khi chúng được giao.
| Ứng dụng có thể tự động tiêu thụ các tin nhắn khi chúng trở nên khả dụng như thế nào? |
Vấn đề với việc lấy tin từ người tiêu dùng là khi kênh trống, người tiêu dùng sẽ chặn các luồng và/hoặc tiêu tốn thời gian xử lý trong khi đang tìm kiếm tin nhắn không có. Việc lấy tin cho phép khách hàng kiểm soát tốc độ tiêu thụ nhưng lại lãng phí tài nguyên khi không có gì để tiêu thụ.
Thay vì liên tục yêu cầu kênh xem có tin nhắn nào để tiêu thụ hay không, tốt hơn là kênh có thể thông báo cho khách hàng khi có tin nhắn có sẵn. Để làm điều đó, thay vì yêu cầu người tiêu thụ kiểm tra tin nhắn, hãy chỉ cần gửi tin nhắn cho người tiêu thụ ngay khi tin nhắn trở nên có sẵn.
| Ứng dụng nên sử dụng một Người tiêu thụ Dựa trên Sự kiện, một người tự động nhận các tin nhắn khi chúng được gửi đến kênh.
|
Điều này cũng được biết đến như một bộ nhận bất đồng bộ, vì bộ nhận không có một luồng đang chạy cho đến khi một luồng gọi lại truyền tải một thông điệp. Chúng tôi gọi nó là Người tiêu dùng dựa trên sự kiện vì bộ nhận hoạt động như thể việc chuyển phát thông điệp là một sự kiện kích hoạt bộ nhận hành động.
Một Người tiêu dùng Dựa trên Sự kiện là một đối tượng được gọi bởi hệ thống tin nhắn khi một tin nhắn đến trên kênh của người tiêu dùng. Người tiêu dùng truyền tin nhắn vào ứng dụng thông qua một hàm gọi lại trong API của ứng dụng. (Cách mà hệ thống tin nhắn nhận được tin nhắn là cụ thể cho từng triển khai và có thể hoặc không thể theo kiểu dựa trên sự kiện. Tất cả những gì người tiêu dùng biết là nó có thể nằm chờ mà không có luồng hoạt động nào cho đến khi nó được gọi bởi hệ thống tin nhắn gửi cho nó một tin nhắn.)
Một Người Tiêu Thụ Dựa Trên Sự Kiện được kích hoạt bởi hệ thống nhắn tin, nhưng nó lại gọi một callback cụ thể cho ứng dụng. Để cầu nối khoảng cách này, người tiêu thụ có một triển khai cụ thể cho ứng dụng tuân thủ một API đã biết được định nghĩa bởi hệ thống nhắn tin.
Mã cho một Người tiêu dùng Dựa trên Sự kiện bao gồm hai phần:
Khởi tạo Ứng dụng tạo ra một trình tiêu thụ đặc thù cho ứng dụng và liên kết nó với một Kênh Tin nhắn cụ thể. Sau khi đoạn mã này được chạy một lần, trình tiêu thụ đã sẵn sàng để nhận một loạt tin nhắn.
Tiêu thụ Người tiêu dùng nhận một thông điệp và chuyển nó cho ứng dụng để xử lý. Đoạn mã này được thực hiện một lần cho mỗi thông điệp được tiêu thụ.
Chuỗi người tiêu dùng dựa trên sự kiện

Ứng dụng tạo ra người tiêu dùng tùy chỉnh của nó và liên kết nó với kênh. Một khi người tiêu dùng được khởi tạo, nó (và ứng dụng) có thể ngủ đông, không có luồng đang chạy, chờ được kích hoạt khi một tin nhắn đến.
Khi một tin nhắn được gửi đi, hệ thống nhắn tin sẽ gọi phương thức sự kiện nhận tin nhắn của người tiêu dùng và truyền tin nhắn đó như một tham số. Người tiêu dùng sẽ truyền tin nhắn cho ứng dụng, bằng cách sử dụng API gọi lại của ứng dụng. Ứng dụng bây giờ đã có tin nhắn và có thể xử lý nó. Khi ứng dụng hoàn tất việc xử lý tin nhắn, nó và người tiêu dùng có thể lại trở về trạng thái ngủ cho đến khi tin nhắn tiếp theo đến. Thông thường, một hệ thống nhắn tin sẽ không chạy nhiều luồng qua một người tiêu dùng đơn, vì vậy người tiêu dùng chỉ có thể xử lý một tin nhắn tại một thời điểm.
Người tiêu dùng theo sự kiện tự động tiêu thụ tin nhắn khi chúng trở nên khả dụng. Để kiểm soát tỷ lệ tiêu thụ một cách chi tiết hơn, hãy sử dụng Người tiêu dùng theo kiểu Polling. Người tiêu dùng theo sự kiện có thể là Người tiêu dùng cạnh tranh. Một Bộ phát tin nhắn có thể được triển khai như một Người tiêu dùng theo sự kiện. Một Người tiêu dùng theo sự kiện có thể là Người tiêu dùng chọn lọc; nó cũng có thể là Người đăng ký bền vững. Các Khách hàng giao dịch có thể không hoạt động tốt như với Người tiêu dùng theo kiểu Polling; xem ví dụ về JMS.
| Ví dụ: JMS MessageListener Trong JMS, một Người tiêu dùng Theo sự kiện là một lớp triển khai giao diện MessageListener [Hapner]. Giao diện này tuyên bố một phương thức duy nhất, onMessage(Message). Người tiêu dùng triển khai onMessage để xử lý thông điệp. Dưới đây là một ví dụ về một người thực hiện JMS: public class MyEventDrivenConsumer implements MessageListener { public void onMessage(Message message) { // Process the message } } Phần khởi tạo của một Bộ tiêu thụ theo sự kiện sẽ tạo ra đối tượng thực hiện mong muốn (là một thể hiện của MessageListener) và liên kết nó với một bộ tiêu thụ tin nhắn cho kênh mong muốn. Destination destination = // Get the destination Session session = // Create the session MessageConsumer consumer = session.createConsumer(destination); MessageListener listener = new MyEventDrivenConsumer(); consumer.setMessageListener(listener); Bây giờ, khi một tin nhắn được gửi đến đích, nhà cung cấp JMS sẽ gọi MyEventDrivenConsumer.onMessage với tin nhắn là tham số. Lưu ý rằng trong JMS, một Người tiêu dùng dựa trên sự kiện cũng đồng thời là một Khách hàng Giao dịch sẽ không hoạt động như mong đợi. Thông thường, một giao dịch sẽ được hoàn lại khi mã trong giao dịch ném ra một ngoại lệ, nhưng chữ ký của MessageListener.onMessage không cho phép có một ngoại lệ nào được ném ra (chẳng hạn như JMSException), và một ngoại lệ thời gian chạy được coi là lỗi của lập trình viên. Nếu một ngoại lệ thời gian chạy xảy ra, nhà cung cấp JMS sẽ phản ứng bằng cách cung cấp tin nhắn tiếp theo, do đó tin nhắn gây ra ngoại lệ sẽ bị mất [JMS 1.1], [Hapner]. Để đạt được hành vi giao dịch, dựa trên sự kiện một cách thành công, hãy sử dụng EJB dựa trên tin nhắn [EJB 2.0], [Hapner]. |
| Ví dụ: Trình xử lý sự kiện Hoàn thành Nhận .NET Với .NET, phần thực hiện của một Người Tiêu Thụ Dựa Trên Sự Kiện triển khai một phương thức là một ủy quyền ReceiveCompletedEventHandler. Phương thức ủy quyền này phải chấp nhận hai tham số: một đối tượng là MessageQueue và một ReceiveCompletedEventArgs là các tham số từ sự kiện ReceiveCompleted [SysMsg]. Phương thức sử dụng các tham số để lấy tin nhắn từ hàng đợi và xử lý nó. Dưới đây là một ví dụ về một người thực hiện .NET: public static void MyEventDrivenConsumer(Object source, ReceiveCompletedEventArgs asyncResult) { MessageQueue mq = (MessageQueue) source; Message m = mq.EndReceive(asyncResult.AsyncResult); // Process the message mq.BeginReceive(); return; } Phần khởi tạo của một client dựa trên sự kiện chỉ ra rằng hàng đợi nên chạy phương thức delegate để xử lý sự kiện ReceiveCompleted: MessageQueue queue = // Get the queue queue.ReceiveCompleted += new ReceiveCompletedEventHandler(MyEventDrivenConsumer); queue.BeginReceive(); Bây giờ, khi một thông điệp được gửi đến hàng đợi, hàng đợi sẽ phát ra một sự kiện ReceiveCompleted, điều này sẽ chạy phương thức MyEventDrivenConsumer. |
Một ứng dụng đang sử dụng Nhắn tin. Tuy nhiên, nó không thể xử lý các tin nhắn nhanh như chúng đang được thêm vào kênh.
| Làm thế nào một khách hàng nhắn tin có thể xử lý nhiều tin nhắn đồng thời? |
Các tin nhắn đến qua Kênh Tin nhắn theo thứ tự, vì vậy xu hướng tự nhiên của một người tiêu dùng là xử lý chúng theo thứ tự. Tuy nhiên, việc tiêu thụ theo thứ tự có thể quá chậm, và các tin nhắn có thể bị tích tụ trên kênh, điều này khiến hệ thống nhắn tin trở thành nút thắt và ảnh hưởng đến tổng thông lượng của ứng dụng. Điều này có thể xảy ra do nhiều người gửi trên kênh, do sự cố mạng gây ra tồn đọng tin nhắn mà sau đó được gửi đến tất cả cùng một lúc, do một sự cố của người nhận gây ra tồn đọng, hoặc do mỗi tin nhắn tiêu tốn nhiều công sức hơn để tiêu thụ và thực hiện so với việc tạo và gửi.
Ứng dụng có thể sử dụng nhiều kênh, nhưng một kênh có thể trở thành điểm nghẽn trong khi một kênh khác thì trống rỗng, và người gửi sẽ không biết kênh tương đương nào để sử dụng. Tuy nhiên, việc có nhiều kênh sẽ mang lại lợi thế cho phép nhiều người tiêu dùng (mỗi kênh một người) xử lý tin nhắn đồng thời. Mặc dù vậy, ngay cả khi điều này hoạt động, số lượng kênh mà ứng dụng định nghĩa vẫn sẽ giới hạn năng suất.
Điều cần thiết là một cách để một kênh có nhiều người tiêu dùng.
| Tạo nhiều Người tiêu dùng Cạnh tranh trên một kênh duy nhất để các người tiêu dùng có thể xử lý nhiều tin nhắn đồng thời.
|
Người tiêu dùng cạnh tranh là nhiều người tiêu dùng được tạo ra để nhận các thông điệp từ một Kênh Điểm-đến-Điểm duy nhất. Khi kênh truyền tải một thông điệp, bất kỳ người tiêu dùng nào cũng có thể nhận được thông điệp đó. Cách thức triển khai của hệ thống nhắn tin sẽ quyết định người tiêu dùng nào thực sự nhận được thông điệp, nhưng về lý thuyết, các người tiêu dùng cạnh tranh với nhau để trở thành người nhận. Khi một người tiêu dùng nhận được một thông điệp, họ có thể ủy quyền cho phần còn lại của ứng dụng của mình để giúp xử lý thông điệp. (Giải pháp này chỉ hoạt động với các Kênh Điểm-đến-Điểm; nhiều người tiêu dùng trên một Kênh Xuất-bản-Đăng ký chỉ tạo ra nhiều bản sao cho mỗi thông điệp.)
Chuỗi Người tiêu dùng Cạnh tranh

Mỗi người tiêu dùng cạnh tranh chạy trong một luồng riêng để tất cả có thể tiêu thụ tin nhắn một cách đồng thời. Khi kênh truyền tải một tin nhắn, các điều khiển giao dịch của hệ thống nhắn tin đảm bảo rằng chỉ một trong số các người tiêu dùng nhận thành công tin nhắn. Trong khi người tiêu dùng đó đang xử lý tin nhắn, kênh có thể truyền tải các tin nhắn khác, mà các người tiêu dùng khác có thể tiêu thụ và xử lý đồng thời. Kênh điều phối các người tiêu dùng, đảm bảo rằng mỗi người nhận một tin nhắn khác nhau; các người tiêu dùng không cần phải phối hợp với nhau.
Mỗi người tiêu dùng xử lý một thông điệp khác nhau đồng thời, vì vậy nút thắt cổ chai trở thành tốc độ mà kênh có thể cung cấp các thông điệp cho những người tiêu dùng thay vì thời gian mà một người tiêu dùng mất để xử lý một thông điệp. Số lượng người tiêu dùng hạn chế vẫn có thể là một nút thắt cổ chai, nhưng việc tăng số lượng người tiêu dùng có thể giảm bớt rào cản đó miễn là có sẵn các tài nguyên máy tính.
Để chạy đồng thời, mỗi người tiêu dùng phải chạy trong luồng riêng của nó. Đối với người tiêu dùng Polling, điều này có nghĩa là mỗi người tiêu dùng phải có một luồng riêng để thực hiện việc polling đồng thời. Đối với người tiêu dùng Dựa trên Sự kiện, hệ thống nhắn tin phải sử dụng một luồng cho mỗi người tiêu dùng đồng thời; luồng đó sẽ được sử dụng để chuyển giao thông điệp cho người tiêu dùng và sẽ được người tiêu dùng sử dụng để xử lý thông điệp.
Một hệ thống tin nhắn tinh vi sẽ phát hiện các người tiêu dùng cạnh tranh trên một kênh và cung cấp một Trình Gửi Tin Nhắn nội bộ đảm bảo rằng mỗi tin nhắn chỉ được gửi đến một người tiêu dùng duy nhất. Điều này giúp tránh xung đột có thể xảy ra nếu nhiều người tiêu dùng đều nghĩ rằng họ là người tiêu dùng của một tin nhắn duy nhất. Một hệ thống tin nhắn kém tinh vi hơn sẽ cho phép nhiều người tiêu dùng cố gắng tiêu thụ cùng một tin nhắn. Khi điều này xảy ra, người tiêu dùng nào cam kết giao dịch trước sẽ thắng; sau đó, các người tiêu dùng khác sẽ không thể cam kết thành công và sẽ phải hoàn tác giao dịch của họ.
Một hệ thống nhắn tin cho phép nhiều người tiêu dùng cố gắng tiêu thụ cùng một thông điệp có thể làm cho một Khách hàng Giao dịch trở nên rất kém hiệu quả. Khách hàng nghĩ rằng nó có một thông điệp, tiêu thụ nó, dành công sức để xử lý thông điệp đó, sau đó cố gắng cam kết nhưng không thể (bởi vì thông điệp đã bị một đối thủ tiêu thụ trước đó). Việc thường xuyên thực hiện công việc chỉ để hoàn tác gây tổn hại đến thông lượng, trong khi mục tiêu của giải pháp này là tăng cường thông lượng. Do đó, hiệu suất của các người tiêu dùng giao dịch cạnh tranh nên được đo lường cẩn thận; nó có thể thay đổi đáng kể trên các triển khai và cấu hình hệ thống nhắn tin khác nhau.
Không chỉ có thể sử dụng Người tiêu dùng Cạnh tranh để phân phối tải trên nhiều luồng tiêu dùng trong một ứng dụng duy nhất; họ cũng có thể phân phối tải tiêu thụ trên nhiều ứng dụng (ví dụ, các tiến trình). Bằng cách này, nếu một ứng dụng không thể tiêu thụ các thông điệp đủ nhanh, thì nhiều ứng dụng tiêu dùng - có thể mỗi ứng dụng sử dụng nhiều luồng tiêu dùng - có thể giải quyết vấn đề. Khả năng có nhiều ứng dụng hoạt động trên nhiều máy tính sử dụng nhiều luồng để tiêu thụ thông điệp cung cấp khả năng xử lý thông điệp gần như không giới hạn, với giới hạn duy nhất là khả năng của hệ thống nhắn tin trong việc chuyển giao thông điệp từ kênh đến các người tiêu dùng.
Việc phối hợp giữa các người tiêu dùng cạnh tranh phụ thuộc vào cách triển khai của từng hệ thống nhắn tin. Nếu khách hàng muốn tự mình triển khai việc phối hợp này, họ nên sử dụng một Trình Phân Phối Thông Điệp. Các người tiêu dùng cạnh tranh có thể là Người Tiêu Dùng Polling, Người Tiêu Dùng Dựa Trên Sự Kiện, hoặc một sự kết hợp của cả hai. Các Khách Hàng Giao Dịch Cạnh Tranh có thể lãng phí đáng kể công sức để xử lý các thông điệp mà các hoạt động nhận không cam kết thành công và phải được hoàn tác.
| Ví dụ: Người tiêu dùng cạnh tranh JMS đơn giản Đây là một ví dụ đơn giản về cách triển khai một người tiêu dùng cạnh tranh trong Java. Một đối tượng điều khiển/bên ngoài (không được hiển thị) chạy một vài đối tượng như vậy. Nó chạy mỗi đối tượng trong một luồng riêng và gọi stopRunning() để làm cho nó dừng lại. Một phiên JMS phải được xử lý theo luồng đơn [JMS 1.1], [Hapner]. Một phiên duy nhất sẽ tuần tự hóa thứ tự tiêu thụ tin nhắn [JMS 1.1], [Hapner]. Vì vậy, để mỗi người tiêu thụ cạnh tranh có thể hoạt động đúng trong luồng riêng của nó, và để các người tiêu thụ có thể tiêu thụ tin nhắn song song, mỗi người tiêu thụ phải có riêng một Phiên (và do đó là một MessageConsumer riêng). Thông số kỹ thuật JMS không chỉ định ý nghĩa của cách các QueueReceivers đồng thời (ví dụ, Người tiêu thụ cạnh tranh) nên hoạt động, hoặc thậm chí yêu cầu rằng phương pháp này hoạt động. Do đó, các ứng dụng sử dụng kỹ thuật này không được xem là có khả năng chuyển đổi và có thể hoạt động khác nhau với các nhà cung cấp JMS khác nhau [JMS 1.1], [Hapner]. Lớp người tiêu dùng triển khai Runnable để có thể chạy trong luồng riêng của nó; điều này cho phép các người tiêu dùng chạy đồng thời. Tất cả các người tiêu dùng chia sẻ cùng một Kết nối, nhưng mỗi người tạo ra một Phiên riêng, điều này rất quan trọng, vì mỗi phiên chỉ có thể hỗ trợ một luồng duy nhất. Mỗi người tiêu dùng lặp đi lặp lại nhận một thông điệp từ hàng đợi và xử lý nó. [View full width] import javax.jms.Connection; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.Session; import javax.naming.NamingException; public class CompetingConsumer implements Runnable { private int performerID; private MessageConsumer consumer; private boolean isRunning; protected CompetingConsumer() { super(); } public static CompetingConsumer newConsumer(int id, Vì vậy, việc triển khai một Người tiêu dùng Cạnh tranh đơn giản là dễ dàng. Mẹo chính là làm cho người tiêu dùng trở thành một Runnable và chạy nó trong một luồng riêng. |
Một ứng dụng đang sử dụng Nhắn tin. Ứng dụng cần nhiều người tiêu dùng trên một Kênh Nhắn tin để hoạt động theo cách phối hợp.
| Làm thế nào mà nhiều người tiêu dùng trên một kênh duy nhất có thể phối hợp việc xử lý thông điệp của họ? |
Nhiều người tiêu dùng trên một Kênh Điểm-điểm duy nhất hoạt động như những Người tiêu dùng Cạnh tranh. Điều này là ổn khi các người tiêu dùng có thể hoán đổi cho nhau, nhưng nó không cho phép chuyên môn hóa các người tiêu dùng để một số người tiêu dùng có khả năng tiếp nhận một số thông điệp nhất định tốt hơn.
Nhiều trình tiêu thụ trên một Kênh Xuất-Biểu đơn sẽ không hoạt động như mong đợi. Thay vì phân phối tải thông điệp, những trình tiêu thụ này sẽ sao chép nỗ lực.
Người tiêu dùng chọn lọc có thể được sử dụng như những người tiêu dùng chuyên biệt. Tuy nhiên, không phải tất cả các hệ thống nhắn tin đều hỗ trợ tính năng này. Ngay cả trong số những hệ thống hỗ trợ, có thể chúng không hỗ trợ việc chọn lọc dựa trên các giá trị trong thân của tin nhắn. Các biểu thức giá trị chọn lọc của chúng có thể quá đơn giản để phân biệt đầy đủ giữa các tin nhắn, hoặc hiệu suất của việc đánh giá lại các biểu thức đó có thể chậm. Có thể có nhiều biểu thức cần được thiết kế cẩn thận theo cách phối hợp sao cho không trùng lặp nhưng cũng không để lại bất kỳ giá trị chọn lọc nào không được xử lý. Chúng có thể cần triển khai một trường hợp mặc định cho các giá trị chọn lọc không được xử lý bởi các người tiêu dùng khác hoặc các giá trị bất ngờ.
Các kênh kiểu dữ liệu có thể được sử dụng để giữ các loại tin nhắn khác nhau tách biệt và cho phép người tiêu dùng chuyên biệt cho các loại tin nhắn đó. Nhưng hệ thống kiểu có thể quá lớn và đa dạng để biện minh cho việc tạo ra một kênh riêng cho mỗi loại. Hoặc, các loại có thể dựa trên các tiêu chí thay đổi động, điều này rất khó xử lý với một tập hợp kênh tĩnh. Doanh nghiệp có thể đã yêu cầu một số lượng kênh khổng lồ, gây áp lực lên hệ thống nhắn tin, và việc nhân đôi nhiều kênh đó cho các loại tin nhắn khác nhau có thể đơn giản yêu cầu quá nhiều kênh.
Mỗi vấn đề này đều có thể được giải quyết nếu các người tiêu dùng có thể làm việc cùng nhau. Họ có thể tránh việc lặp lại công việc bằng cách biết được nếu một người tiêu dùng khác đã xử lý công việc đó. Họ có thể được chuyên môn hóa; nếu một người tiêu dùng nhận được loại thông điệp không phù hợp với chuyên môn của mình, họ có thể chuyển tiếp thông điệp đó cho một người tiêu dùng khác có chuyên môn phù hợp. Nếu một ứng dụng có quá nhiều kênh vào, nó có thể tiết kiệm kênh bằng cách để tất cả người tiêu dùng của nó chia sẻ một kênh duy nhất; họ sẽ phối hợp để đảm bảo rằng những thông điệp đúng được gửi đến những người tiêu dùng đúng.
Than ôi, người tiêu dùng là những đối tượng rất độc lập mà khó có thể phối hợp. Việc làm cho người tiêu dùng chuyên biệt đủ chung để xử lý bất kỳ thông điệp nào và chuyền tay sẽ tạo ra nhiều chi phí thiết kế và xử lý cho mỗi người tiêu dùng. Tất cả họ sẽ phải biết về nhau để có thể chuyền công việc, và họ sẽ cần biết ai trong số đó đang bận rộn để không giao cho một người tiêu dùng một thông điệp để xử lý trong khi họ đã đang xử lý một thông điệp khác. Việc làm cho các người tiêu dùng làm việc cùng nhau sẽ thay đổi hoàn toàn thiết kế người tiêu dùng điển hình.
Mẫu Mediator [GoF] cung cấp một số hỗ trợ. Một Mediator phối hợp một nhóm đối tượng để chúng không cần biết cách phối hợp với nhau. Điều chúng ta cần cho việc nhắn tin là một mediator phối hợp các người tiêu dùng cho một kênh. Sau đó, mỗi người tiêu dùng có thể tập trung vào việc xử lý một loại tin nhắn cụ thể, và người điều phối có thể đảm bảo rằng tin nhắn đúng đến tay người tiêu dùng đúng.
| Tạo một Trình Phân Phối Thông Điệp trên một kênh sẽ tiêu thụ thông điệp từ một kênh và phân phối chúng đến các người thực hiện.
|
Một Trình Gửi Thông Điệp bao gồm hai phần:
Người điều phối Đối tượng tiêu thụ thông điệp từ kênh và phân phối mỗi thông điệp đến một người thực hiện.
Người thực hiện Đối tượng nhận thông điệp từ bộ điều phối và xử lý nó.
Khi một Trình gửi tin nhắn nhận được một tin nhắn, nó sẽ lấy một người thực hiện và chuyển tin nhắn cho người thực hiện đó để xử lý. Một người thực hiện có thể ủy quyền cho phần còn lại của ứng dụng của mình để hỗ trợ xử lý tin nhắn. Người thực hiện có thể được tạo mới bởi trình gửi tin nhắn hoặc có thể được chọn từ một nhóm người thực hiện có sẵn. Mỗi người thực hiện có thể chạy trong luồng riêng của nó để xử lý tin nhắn đồng thời. Tất cả các người thực hiện có thể phù hợp cho tất cả các tin nhắn, hoặc trình gửi tin nhắn có thể ghép một tin nhắn với một người thực hiện chuyên biệt dựa trên các thuộc tính của tin nhắn.
Trình gửi tin nhắn theo thứ tự

Khi bộ điều phối nhận được một tin nhắn, nó phân công tin nhắn đó cho một người thực hiện có sẵn để xử lý. Nếu người thực hiện xử lý tin nhắn bằng cách sử dụng luồng của bộ điều phối, thì bộ điều phối sẽ bị chặn cho đến khi người thực hiện hoàn thành việc xử lý tin nhắn. Ngược lại, nếu người thực hiện xử lý tin nhắn trong luồng riêng của mình, thì khi bộ điều phối bắt đầu luồng đó, nó có thể ngay lập tức bắt đầu nhận các tin nhắn khác và phân công chúng cho các người thực hiện khác để các tin nhắn được xử lý đồng thời. Bằng cách này, các tin nhắn có thể được tiêu thụ nhanh như bộ điều phối có thể nhận và phân công chúng, bất kể mỗi tin nhắn mất bao lâu để xử lý.
Một bộ phận điều phối đóng vai trò như một kết nối từ một đến nhiều giữa một kênh đơn và một nhóm diễn viên. Các diễn viên thực hiện hầu hết công việc; bộ phận điều phối chỉ đóng vai trò như một người mai mối, ghép mỗi tin nhắn với một diễn viên sẵn có, và không bị chặn miễn là các diễn viên chạy trong các luồng riêng. Bộ phận điều phối nhận tin nhắn và sau đó gửi nó cho một diễn viên để xử lý. Bởi vì bộ phận điều phối thực hiện công việc tương đối ít và không bị chặn, nó có khả năng phân phối tin nhắn nhanh như hệ thống nhắn tin có thể cung cấp chúng và do đó tránh trở thành nút thắt cổ chai.
Mẫu này là một phiên bản đơn giản hơn, cụ thể cho thông điệp của mẫu Reactor [POSA2], trong đó bộ phân phối thông điệp là một Reactor và các trình thực thi thông điệp là các Trình xử lý Sự kiện Cụ thể. Kênh Thông điệp hoạt động như một Bộ giải mã Sự kiện Đồng bộ, cung cấp các thông điệp cho bộ phân phối một cách lần lượt. Các thông điệp tự nó giống như các Handle, nhưng đơn giản hơn nhiều. Một handle thực sự có xu hướng là một tham chiếu đến dữ liệu của một tài nguyên, trong khi một thông điệp thường chứa dữ liệu trực tiếp. (Tuy nhiên, thông điệp không nhất thiết phải lưu trữ dữ liệu trực tiếp. Nếu dữ liệu của một thông điệp được lưu trữ bên ngoài và thông điệp là một Claim Check, thì thông điệp chứa một tham chiếu đến dữ liệu, điều này giống như một handle Reactor hơn.) Các loại handle khác nhau chọn các trình xử lý sự kiện cụ thể khác nhau, trong khi Kênh Thông điệp là một Kênh Kiểu dữ liệu, vì vậy tất cả các thông điệp (handles) đều có cùng một loại, và thường chỉ có một loại trình xử lý sự kiện cụ thể.
Khi Kênh Kiểu Dữ Liệu thiết kế một kênh sao cho tất cả các tin nhắn đều có cùng một loại và tất cả các người tiêu dùng xử lý các tin nhắn của loại đó, thì mô hình Reactor chỉ ra một cơ hội để sử dụng Trình Phân Phối Tin Nhắns để hỗ trợ nhiều kiểu dữ liệu trên cùng một kênh và xử lý chúng bằng các người thực hiện cụ thể cho từng loại. Mỗi tin nhắn phải chỉ rõ loại của nó; trình phân phối phát hiện loại của tin nhắn và chuyển tiếp nó đến một người thực hiện cụ thể cho từng loại để xử lý. Bằng cách này, một trình phân phối với các người thực hiện chuyên biệt có thể hoạt động như một sự thay thế cho Các Kênh Kiểu Dữ Liệu và như một triển khai chuyên biệt của Người Tiêu Dùng Chọn Lọc.
Một khác biệt giữa Trình Gửi Tin Nhắn và Các Người Tiêu Thụ Đối Kháng là khả năng phân phối qua nhiều ứng dụng. Trong khi một tập hợp Các Người Tiêu Thụ Đối Kháng có thể được phân phối giữa nhiều quá trình (ví dụ: ứng dụng), một tập hợp các người thực hiện thường chạy trong cùng một quá trình với trình gửi tin (ngay cả khi chúng chạy trong các luồng khác nhau). Nếu một người thực hiện đang chạy trong một quá trình khác so với trình gửi tin của nó, thì trình gửi tin sẽ phải giao tiếp với người thực hiện theo cách phân tán, theo kiểu Gọi Thủ Tục Từ Xa, điều này chính xác là điều mà Tin Nhắn muốn tránh ngay từ đầu.
Vì một bộ điều phối là một người tiêu dùng đơn lẻ, nó hoạt động tốt với cả Kênh Điểm-Đến-Điểm và Kênh Xuất-Bản-Đăng-Ký. Với nhắn tin điểm-đến-điểm, một bộ điều phối có thể là một lựa chọn phù hợp thay thế cho Người Tiêu Dùng Cạnh Tranh; lựa chọn này có thể được ưa chuộng nếu hệ thống nhắn tin xử lý nhiều người tiêu dùng kém hoặc nếu việc xử lý nhiều người tiêu dùng trên các triển khai hệ thống nhắn tin khác nhau là không nhất quán.
Một bộ điều phối (dispatcher) làm cho các nghệ sĩ hoạt động giống như các Người tiêu dùng theo sự kiện (Event-Driven Consumers), mặc dù bộ điều phối bản thân có thể là một người tiêu dùng theo sự kiện hoặc một người tiêu dùng theo hình thức "polling". Do đó, việc triển khai một bộ điều phối như một phần của Khách hàng Giao dịch (Transactional Client) có thể khó khăn. Nếu khách hàng là giao dịch, lý tưởng là bộ điều phối nên cho phép nghệ sĩ xử lý một tin nhắn trước khi hoàn tất giao dịch. Chỉ khi nghệ sĩ thành công, bộ điều phối mới cam kết giao dịch. Nếu nghệ sĩ không xử lý được tin nhắn, bộ điều phối nên hoàn tác giao dịch. Vì mỗi nghệ sĩ có thể cần hoàn tác tin nhắn riêng của mình, bộ điều phối cần có một phiên cho mỗi nghệ sĩ và phải sử dụng phiên của nghệ sĩ đó để nhận tin nhắn của nghệ sĩ và hoàn tất giao dịch của mình. Vì các Người tiêu dùng theo sự kiện thường không hoạt động tốt với Khách hàng Giao dịch, nên bộ điều phối không nên là một Người tiêu dùng theo sự kiện, mà nên là một Người tiêu dùng theo hình thức "polling".
Việc triển khai các performer dưới dạng Người tiêu dùng Dựa trên Sự kiện có thể rất hữu ích. Trong JMS, điều này có nghĩa là triển khai performer dưới dạng một MessageListener. Một listener tin nhắn có một phương thức, onMessage(Message); nó chấp nhận một tin nhắn và thực hiện mọi xử lý cần thiết. Điều này tạo ra sự phân tách rõ ràng giữa bộ phân phối và performer. Tương tự, trong .NET, performer nên là một delegate ReceiveCompletedEventHandler, mặc dù bộ phân phối thực sự sẽ không phát ra các sự kiện ReceiveCompleted. Tuy nhiên, những cách tiếp cận dựa trên sự kiện này có thể không tương thích với API cần thiết để chạy một performer trong một luồng riêng biệt.
Để tránh nỗ lực thực hiện bộ Chuyển Tải Thông Điệp riêng của bạn, hãy xem xét việc sử dụng Người Tiêu Thụ Cạnh Tranh trên Kênh Dữ Liệu hoặc sử dụng Người Tiêu Thụ Chọn Lọc. Một Bộ Chuyển Tải Thông Điệp có thể là Người Tiêu Thụ Theo Dõi hoặc Người Tiêu Thụ Dựa Trên Sự Kiện. Một Bộ Chuyển Tải Thông Điệp không phải là một Khách Hàng Giao Dịch tốt.
| Ví dụ: Trình xử lý .NET Thông thường, một Trình Dispatch tin nhắn sẽ phân phối các tin nhắn đến các người thực hiện (xem ví dụ Java). .NET cung cấp một tùy chọn khác: Trình dispatch có thể sử dụng Peek để phát hiện một tin nhắn và lấy ID của nó, sau đó phân phối ID của tin nhắn (không phải tin nhắn đầy đủ) cho người thực hiện. Người thực hiện sau đó sử dụng ReceiveById để tiêu thụ tin nhắn cụ thể mà nó đã được giao. Bằng cách này, mỗi người thực hiện có thể chịu trách nhiệm không chỉ cho việc xử lý tin nhắn mà còn cho việc tiêu thụ nó, điều này có thể giúp giải quyết các vấn đề về đồng thời, đặc biệt khi các người tiêu thụ là Các Khách hàng Giao dịch. |
| Ví dụ: Trình phân phối Java đơn giản Đây là một ví dụ đơn giản về cách triển khai một bộ điều phối và người thực hiện trong Java. Một triển khai bộ điều phối tinh vi hơn có thể nhóm nhiều người thực hiện lại với nhau, theo dõi những người nào hiện đang available để xử lý tin nhắn, và sử dụng một nhóm luồng. Ví dụ đơn giản này bỏ qua những chi tiết đó nhưng chạy mỗi người thực hiện trong một luồng riêng để họ có thể chạy song song. Người lái xe/quản lý điều khiển bộ phân phối (không hiển thị) sẽ gọi hàm receiveSync() liên tục. Mỗi lần, bộ phân phối sẽ nhận() thông điệp tiếp theo, khởi tạo một phiên bản người thực hiện mới để xử lý thông điệp, và sau đó bắt đầu người thực hiện trong luồng riêng của nó. [View full width] import javax.jms.Connection; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.Session; import javax.naming.NamingException; public class MessageDispatcher { MessageConsumer consumer; int nextID = 1; protected MessageDispatcher() { super(); } public static MessageDispatcher newDispatcher(Connection Người thực hiện phải triển khai Runnable để nó có thể chạy trong luồng riêng của nó. Phương thức run() của runnable chỉ đơn giản gọi processMessage(). Khi điều này hoàn tất, người thực hiện sẽ trở thành đủ điều kiện để được thu gom rác. [View full width] import javax.jms.JMSException; import javax.jms.Message; public class Performer implements Runnable { private int performerID; private Message message; public Performer(int id, Message message) { performerID = id; this.message = message; } public void run() { try { processMessage(); } catch (Exception e) { e.printStackTrace(); } } private void processMessage() throws JMSException, Việc triển khai một bộ điều phối và người thực hiện đơn giản là dễ dàng. Mẹo chính là làm cho người thực hiện trở thành một Runnable và chạy nó trong luồng riêng của nó. |
Một ứng dụng đang sử dụng Tin nhắn. Nó tiêu thụ Tin nhắn từ một Kênh Tin nhắn, nhưng không nhất thiết phải tiêu thụ tất cả các tin nhắn trên kênh đó, chỉ một số trong số chúng.
| Làm thế nào một người tiêu thụ tin nhắn có thể chọn những tin nhắn mà họ muốn nhận? |
Mặc định, nếu một Kênh Tin nhắn chỉ có một người tiêu thụ, tất cả các Tin nhắn trên kênh đó sẽ được giao đến người tiêu thụ đó. Tương tự, nếu có nhiều Người tiêu thụ cạnh tranh trên kênh, bất kỳ tin nhắn nào có thể được gửi đến bất kỳ người tiêu thụ nào, và mỗi tin nhắn sẽ được gửi đến một người tiêu thụ nào đó. Một người tiêu thụ thường không có quyền chọn tin nhắn nào mà họ tiêu thụ; họ luôn nhận được tin nhắn tiếp theo.
Hành vi này là hợp lý miễn là người tiêu dùng muốn nhận bất kỳ và tất cả các tin nhắn trên kênh, điều này thường là đúng. Tuy nhiên, đây là một vấn đề khi một người tiêu dùng chỉ muốn tiêu thụ một số tin nhắn nhất định, vì một người tiêu dùng thường không có quyền kiểm soát đối với những tin nhắn nào trên một kênh mà họ nhận được. Tại sao người tiêu dùng lại muốn nhận chỉ một số tin nhắn nhất định? Hãy xem xét một ứng dụng xử lý các tin nhắn yêu cầu vay; nó có thể muốn xử lý các khoản vay lên đến 100.000 đô la khác với những khoản vay trên 100.000 đô la. Một cách tiếp cận là ứng dụng có hai loại người tiêu dùng khác nhau, một cho các khoản vay nhỏ và một cho các khoản vay lớn. Tuy nhiên, vì bất kỳ người tiêu dùng nào cũng có thể nhận được bất kỳ tin nhắn nào, làm thế nào ứng dụng có thể đảm bảo rằng các tin nhắn đúng đến tay người tiêu dùng đúng?
Cách tiếp cận đơn giản nhất có thể là mỗi thực thể tiêu thụ bất kỳ thông điệp nào nó nhận được. Nếu nó nhận được thông điệp sai loại, nó có thể theo cách nào đó chuyển thông điệp đó cho loại người tiêu dùng thích hợp. Tuy nhiên, điều này sẽ khó khăn; các phiên bản người tiêu dùng thường không biết về nhau, và việc tìm một phiên bản chưa bận xử lý thông điệp khác có thể rất khó. Có lẽ khi người tiêu dùng nhận ra rằng họ không muốn thông điệp đó, họ có thể đặt thông điệp lại trên kênh. Nhưng sau đó, khả năng cao là họ sẽ chỉ tiêu thụ thông điệp một lần nữa. Có lẽ mọi người tiêu dùng có thể nhận được một bản sao của mọi thông điệp và chỉ đơn giản là loại bỏ những cái họ không muốn. Điều này sẽ hoạt động nhưng sẽ gây ra rất nhiều sự trùng lặp thông điệp và rất nhiều việc xử lý lãng phí trên những thông điệp cuối cùng bị loại bỏ.
Có lẽ hệ thống nhắn tin có thể định nghĩa các kênh riêng cho từng loại tin nhắn. Sau đó, người gửi có thể đảm bảo gửi mỗi tin nhắn qua kênh thích hợp, và người nhận có thể chắc chắn rằng các tin nhắn họ nhận được từ một kênh cụ thể là loại mà họ mong muốn. Tuy nhiên, giải pháp này không được linh hoạt lắm. Người nhận có thể thay đổi tiêu chí lựa chọn của họ trong khi hệ thống đang chạy, điều này sẽ yêu cầu định nghĩa các kênh mới và phân phối lại các tin nhắn đã có trên các kênh. Nó cũng có nghĩa là người gửi phải biết tiêu chí lựa chọn của người nhận là gì và khi nào các tiêu chí đó thay đổi. Các tiêu chí cần phải là một thuộc tính của người nhận, không phải của các kênh, và các tin nhắn trên kênh cần phải chỉ rõ tiêu chí mà chúng đáp ứng.
Điều cần thiết là một cách để các thông điệp phù hợp với nhiều tiêu chí khác nhau được gửi qua cùng một kênh, để người tiêu dùng có thể chỉ định các tiêu chí mà họ quan tâm, và để mỗi người tiêu dùng chỉ nhận các thông điệp đáp ứng tiêu chí của họ.
| Biến người tiêu dùng thành một người tiêu dùng có chọn lọc, người mà lọc các thông điệp được truyền tải qua kênh của mình để chỉ nhận những thông điệp phù hợp với tiêu chí của họ.
|
Có ba phần trong quy trình lọc này:
Chỉ rõ Nhà sản xuất Chỉ rõ giá trị lựa chọn của tin nhắn trước khi gửi.
Giá trị Lựa Chọn Một hoặc nhiều giá trị được chỉ định trong tin nhắn cho phép người tiêu dùng quyết định xem có nên chọn tin nhắn hay không.
Người tiêu dùng chọn lọc chỉ nhận các tin nhắn đáp ứng tiêu chí chọn lọc của họ.
Người gửi tin nhắn chỉ định giá trị lựa chọn của mỗi tin nhắn trước khi gửi. Khi một tin nhắn đến, một Người tiêu thụ Lựa chọn sẽ kiểm tra giá trị lựa chọn của tin nhắn để xem liệu giá trị đó có đáp ứng tiêu chí lựa chọn của người tiêu thụ hay không. Nếu có, người tiêu thụ sẽ nhận được tin nhắn và chuyển nó đến ứng dụng để xử lý.
Chuỗi Người Tiêu Dùng Chọn Lọc

Khi người gửi tạo thông điệp, họ cũng thiết lập giá trị chọn lọc của thông điệp; sau đó họ gửi thông điệp. Khi hệ thống nhắn tin giao thông điệp, Người tiêu dùng Chọn lọc kiểm tra giá trị chọn lọc của thông điệp để xác định liệu có chọn thông điệp hay không. Nếu thông điệp được chấp nhận, người tiêu dùng nhận thông điệp và chuyển thông điệp cho ứng dụng, sử dụng một cuộc gọi lại.
Người tiêu dùng chọn lọc thường được sử dụng theo nhóm; một người tiêu dùng lọc theo một bộ tiêu chí, trong khi một người khác lọc theo một bộ khác, và cứ như vậy. Trong ví dụ về việc xử lý khoản vay, một người tiêu dùng sẽ chọn "số tiền <= 100.000 đô la" trong khi một người khác sẽ chọn "số tiền > 100.000 đô la." Sau đó, mỗi người tiêu dùng chỉ nhận được những loại khoản vay mà họ quan tâm.
Khi nhiều Người Tiêu Thụ Chọn Lọc được sử dụng với một Kênh Điểm-Đến-Điểm, chúng trở thành những Người Tiêu Thụ Cạnh Tranh mà cũng là chọn lọc. Nếu tiêu chí của hai người tiêu thụ chồng chéo lên nhau, và giá trị lựa chọn của một tin nhắn đáp ứng cả hai tiêu chí, thì bất kỳ người tiêu thụ nào cũng có thể tiêu thụ tin nhắn đó. Các người tiêu thụ nên được thiết kế để đảm bảo rằng ít nhất một trong số họ đủ điều kiện để tiêu thụ mọi giá trị lựa chọn hợp lệ. Nếu không, một tin nhắn có giá trị lựa chọn không phù hợp sẽ không bao giờ được tiêu thụ và sẽ làm rối kênh mãi mãi (hoặc ít nhất cho đến khi Xảy Ra Thời Hạn Tin Nhắn).
Khi nhiều Người tiêu dùng Lựa chọn được sử dụng với Kênh Phát hành-Đăng ký, mỗi tin nhắn sẽ được gửi đến từng người đăng ký, nhưng một người đăng ký sẽ đơn giản là bỏ qua bản sao của tin nhắn không phù hợp với tiêu chí của họ. Khi một người tiêu dùng quyết định bỏ qua một tin nhắn, hệ thống nhắn tin có thể loại bỏ tin nhắn đó, vì nó đã được gửi thành công và sẽ không bao giờ được tiêu thụ. Hệ thống nhắn tin có thể tối ưu hóa quy trình này bằng cách không gửi tin nhắn mà nó biết người tiêu dùng sẽ bỏ qua, từ đó giảm thiểu số lượng bản sao của tin nhắn cần được tạo ra và truyền đi. Hành vi này của việc loại bỏ các tin nhắn bị bỏ qua là độc lập với các cài đặt Đảm bảo Giao hàng, Người đăng ký Bền vững và/hoặc Thời gian Hết hạn Tin nhắn mà được sử dụng.
Người tiêu dùng chọn lọc làm cho một kênh đơn hoạt động như nhiều kênh dữ liệu khác nhau. Các loại thông điệp khác nhau có thể có các giá trị chọn lựa khác nhau, để một người tiêu dùng chuyên biệt cho một loại nhất định chỉ nhận được thông điệp của loại đó. Điều này có thể giúp gửi một số lượng lớn các loại thông điệp bằng cách sử dụng một số lượng nhỏ kênh. Cách tiếp cận này cũng có thể tiết kiệm kênh trong một doanh nghiệp cần nhiều kênh hơn khả năng hỗ trợ của hệ thống nhắn tin.
Người tiêu dùng cạnh tranh, có chọn lọc

Việc sử dụng người tiêu dùng chọn lọc để mô phỏng các kênh kiểu dữ liệu không phải là một cách tiếp cận tốt khi cố gắng ẩn giấu tin nhắn của một loại nhất định từ các ứng dụng tiêu dùng nhất định. Trong khi hệ thống nhắn tin có thể đảm bảo chỉ những ứng dụng được ủy quyền mới có thể nhận tin nhắn thành công từ một kênh, chúng thường không xác thực tiêu chí lựa chọn của một người tiêu dùng, vì vậy một người tiêu dùng độc hại được ủy quyền truy cập vào kênh có thể truy cập vào các tin nhắn không được ủy quyền bằng cách thay đổi tiêu chí của mình. Các kênh kiểu dữ liệu riêng biệt là cần thiết để khóa an toàn các ứng dụng.
Một sự thay thế cho việc sử dụng Người tiêu dùng Chọn lọc là sử dụng Trình phát tin nhắn. Các tiêu chí lựa chọn được xây dựng vào trình phát, sau đó sử dụng chúng để xác định người thực hiện cho mỗi thông điệp. Nếu một thông điệp không đáp ứng bất kỳ tiêu chí nào của người thực hiện, thay vì để nó làm rối kênh hoặc loại bỏ nó, trình phát có thể chuyển hướng thông điệp không khớp đến Kênh Thông điệp Không hợp lệ. Giống như sự cân nhắc giữa Trình phát tin nhắn và Người tiêu dùng Cạnh tranh, câu hỏi thực sự là liệu bạn có muốn để hệ thống nhắn tin thực hiện việc phân phối hay bạn muốn tự mình thực hiện. Nếu một hệ thống nhắn tin không hỗ trợ Người tiêu dùng Chọn lọc như một tính năng, bạn không còn lựa chọn nào khác ngoài việc tự mình thực hiện nó bằng cách sử dụng Trình phát tin nhắn.
Như đã đề cập trước đó, nếu không có người tiêu dùng chọn lọc nào trên một kênh khớp với giá trị chọn lọc của thông điệp, thông điệp sẽ bị bỏ qua như thể kênh đó không có người nhận. Một vấn đề tương tự trong lập trình tuần tự là một câu lệnh case mà không có trường hợp nào khớp với giá trị đang được kiểm tra. Do đó, một câu lệnh case có thể có một trường hợp mặc định khớp với các giá trị không được khớp bởi bất kỳ trường hợp nào khác. Áp dụng phương pháp này vào thông điệp, có thể có vẻ hấp dẫn để tạo ra một loại người tiêu dùng mặc định cho các thông điệp mà không có người tiêu dùng khớp nào khác. Tuy nhiên, một người tiêu dùng mặc định như vậy sẽ không hoạt động như mong muốn vì nó sẽ yêu cầu một biểu thức khớp với tất cả các giá trị chọn lọc, do đó nó sẽ cạnh tranh với tất cả các người tiêu dùng khác. Thay vào đó, để thực hiện một người tiêu dùng mặc định, hãy sử dụng một Bộ Giao Nhận Thông Điệp (Message Dispatcher) mà thực hiện một câu lệnh case với một tùy chọn mặc định cho các trường hợp không được xử lý mà sử dụng người tiêu dùng mặc định.
Một lựa chọn khác cho Người tiêu dùng chọn lọc là Bộ lọc tin nhắn. Chúng đạt được mục tiêu tương tự, nhưng theo những cách khác nhau. Với Người tiêu dùng chọn lọc, tất cả các tin nhắn đều được gửi đến người nhận, nhưng mỗi người nhận sẽ bỏ qua những tin nhắn không mong muốn. Bộ lọc tin nhắn ngồi giữa kênh từ người gửi và kênh đến người nhận và chỉ chuyển các tin nhắn mong muốn từ kênh của người gửi đến kênh của người nhận. Do đó, các tin nhắn không mong muốn thậm chí không bao giờ được gửi đến kênh của người nhận, vì vậy người nhận không có gì để bỏ qua. Bộ lọc tin nhắn hữu ích để loại bỏ các tin nhắn mà không ai trong số người nhận muốn. Người tiêu dùng chọn lọc hữu ích khi một người nhận muốn bỏ qua một số tin nhắn nhưng những người nhận khác muốn nhận các tin nhắn đó.
Một lựa chọn khác cần xem xét là Router Dựa trên Nội dung. Loại router này, như một bộ lọc, đảm bảo rằng một kênh chỉ nhận được những tin nhắn mà những người nhận muốn, điều này có thể tăng cường bảo mật và nâng cao hiệu suất của người tiêu dùng. Người tiêu dùng Lựa chọn linh hoạt hơn, tuy nhiên, vì mỗi tùy chọn lọc chỉ yêu cầu một người tiêu dùng mới (dễ dàng tạo ra trong khi hệ thống đang chạy), trong khi mỗi tùy chọn mới với Router Dựa trên Nội dung yêu cầu một kênh đầu ra mới (không dễ dàng để tạo và sử dụng trong khi hệ thống đang chạy) cũng như một người tiêu dùng mới cho kênh mới. Hãy xem xét một thay đổi yêu cầu nơi bạn muốn xử lý các khoản vay có kích thước trung bình (50.000 đô la đến 150.000 đô la) khác với các khoản vay nhỏ và lớn. Với Router Dựa trên Nội dung, bạn cần tạo một kênh mới cho các khoản vay trung bình, cũng như một người tiêu dùng trên kênh mới đó, và điều chỉnh cách router phân tách các khoản vay. Bạn cũng cần lo lắng về những gì xảy ra khi thay đổi bắt đầu có hiệu lực, vì một số tin nhắn đã được định tuyến vào các kênh ban đầu có thể chưa được tiêu thụ và có thể bây giờ đang ở trên kênh sai. Với Người tiêu dùng Lựa chọn, bạn chỉ cần thay thế hai loại người tiêu dùng (dưới 100.000 đô la và lớn hơn 100.000 đô la) bằng ba loại (dưới 50.000 đô la, 50.000 đến 150.000 đô la và lớn hơn 150.000 đô la). Router Dựa trên Nội dung là một phương pháp tĩnh hơn nhiều, trong khi Người tiêu dùng Lựa chọn có thể linh hoạt hơn nhiều.
Lý tưởng nhất, giá trị lựa chọn của một tin nhắn nên được chỉ định trong tiêu đề của nó, chứ không phải trong nội dung, để một Người tiêu dùng Lựa chọn có thể xử lý giá trị mà không cần phải phân tích (và biết cách phân tích) nội dung của tin nhắn.
Người tiêu dùng chọn lọc làm cho một kênh đơn lẻ hoạt động như nhiều kênh dữ liệu khác nhau. Họ cho phép tin nhắn được cung cấp cho những người nhận khác, trong khi Bộ lọc tin nhắn ngăn chặn các tin nhắn không mong muốn được chuyển đến bất kỳ người nhận nào, và chúng có thể được sử dụng linh hoạt hơn so với Bộ định tuyến dựa trên nội dung. Một người tiêu dùng chọn lọc có thể được triển khai như một người tiêu dùng theo chế độ polling hay theo sự kiện và có thể là một phần của Khách hàng giao dịch. Để triển khai hành vi lọc này một cách tự mình, hãy sử dụng Bộ phân phối tin nhắn.
| Ví dụ: Phân loại các loại Hệ thống giao dịch chứng khoán với số lượng kênh giới hạn có thể cần sử dụng một kênh cho cả báo giá và giao dịch. Bộ nhận cho việc thực hiện một báo giá rất khác biệt so với bộ nhận cho giao dịch, vì vậy bộ nhận đúng cần đảm bảo tiêu thụ thông điệp chính xác. Người gửi sẽ thiết lập giá trị bộ chọn trên một thông điệp báo giá thành QUOTE, và Bộ Tiêu thụ Chọn lọc cho báo giá chỉ tiêu thụ các thông điệp có giá trị bộ chọn đó. Các thông điệp giao dịch sẽ có giá trị bộ chọn TRADE riêng mà người gửi và người nhận của chúng sẽ sử dụng. Bằng cách này, hai loại thông điệp có thể chia sẻ thành công một kênh duy nhất. |
| Ví dụ: Bộ chọn Thông điệp JMS Trong JMS, một MessageConsumer (QueueReceiver hoặc TopicSubscriber) có thể được tạo ra với một chuỗi chọn lựa tin nhắn để lọc các tin nhắn dựa trên giá trị thuộc tính của chúng [JMS 1.1], [Hapner]. Đầu tiên, một người gửi thiết lập giá trị của một thuộc tính trong tin nhắn mà người nhận có thể lọc theo: Session session = // get the session TextMessage message = session.createTextMessage(); message.setText("<quote>SUNW</quote>"); message.setStringProperty("req_type", "quote"); Destination destination = //get the destination MessageProducer producer = session.createProducer(destination); producer.send(message); Thứ hai, một bộ nhận thiết lập bộ chọn thông điệp của nó để lọc cho giá trị đó: Session session = // get the session Destination destination = //get the destination String selector = "req_type = 'quote'"; MessageConsumer consumer = session.createConsumer(destination, selector); Bộ nhận này sẽ bỏ qua tất cả các tin nhắn có thuộc tính loại yêu cầu không được đặt thành báo giá, như thể các tin nhắn đó chưa bao giờ được gửi đến điểm đến. |
| Ví dụ: .NET Peek, NhậnTheoId và NhậnTheoMãLiênQuan Trong .NET, MessageQueue.Receive không hỗ trợ các bộ chọn tin nhắn kiểu JMS. Thay vào đó, một người nhận có thể sử dụng MessageQueue.Peek để xem một tin nhắn. Nếu nó đáp ứng các tiêu chí mong muốn, thì có thể sử dụng MessageQueue.Receive để đọc nó từ hàng đợi. Tuy nhiên, điều này có thể không hoạt động rất đáng tin cậy, vì tin nhắn được trả về bởi lệnh gọi Receive có thể không nhất thiết là cùng một tin nhắn đã được xem. Do đó, hãy sử dụng ReceiveById, khi đó người tiêu dùng sẽ chỉ định giá trị thuộc tính ID của tin nhắn mà họ muốn nhận (thay vì chỉ định Receive) để đảm bảo nhận được cùng một tin nhắn đã được xem. Một tùy chọn khác trong .NET là phương thức ReceiveByCorrelationId, với phương thức này, người tiêu dùng chỉ định giá trị thuộc tính CorrelationId của thông điệp mà họ muốn nhận. Người gửi một thông điệp yêu cầu cụ thể có thể sử dụng ReceiveByCorrelationId để nhận thông điệp trả lời cụ thể cho yêu cầu đó (xem Request-Reply và Correlation Identifier). |
Một ứng dụng đang nhận tin nhắn trên kênh Đăng Bảng-Đăng Ký.
| Làm thế nào để một người đăng ký tránh bị bỏ lỡ tin nhắn trong khi không lắng nghe chúng? |
Tại sao điều này lại là vấn đề? Khi một tin nhắn được thêm vào một kênh, nó sẽ ở đó cho đến khi nó bị tiêu thụ, hết hạn (xem Hết hạn tin nhắn), hoặc hệ thống gặp sự cố (trừ khi bạn đang sử dụng Giao hàng Đảm bảo). Điều này đúng với một tin nhắn trên Kênh Điểm-đến-Điểm, nhưng Kênh Đăng ký-Phát hành hoạt động hơi khác biệt.
Khi một tin nhắn được công bố trên một Kênh Xuất Bản-Đăng Ký, hệ thống nhắn tin phải chuyển tin nhắn đến từng người đăng ký. Cách thức thực hiện điều này phụ thuộc vào cách cài đặt: Nó có thể giữ tin nhắn cho đến khi danh sách các người đăng ký chưa nhận tin nhắn trở nên trống rỗng, hoặc nó có thể sao chép và gửi tin nhắn đến từng người đăng ký. Dù ở trường hợp nào, việc ai nhận được tin nhắn hoàn toàn phụ thuộc vào ai đã đăng ký kênh vào thời điểm tin nhắn được công bố. Nếu một người nhận không đăng ký khi tin nhắn được công bố, ngay cả khi người đó đăng ký ngay sau đó, họ sẽ không nhận được tin nhắn đó. (Cũng có một vấn đề về thời gian xảy ra khi một người đăng ký đăng ký và một tin nhắn được công bố trên cùng một kênh vào "khoảng" cùng một thời điểm. Liệu người đăng ký có nhận được tin nhắn không? Cách giải quyết vấn đề này phụ thuộc vào cách cài đặt của hệ thống nhắn tin. Để an toàn, người đăng ký nên đảm bảo đăng ký trước khi các tin nhắn liên quan được công bố.)
Về mặt thực tiễn, một người đăng ký hủy đăng ký từ một kênh bằng cách đóng kết nối của mình với kênh đó. Do đó, không cần hành động hủy đăng ký một cách rõ ràng; người đăng ký chỉ cần đóng kết nối của mình.
Thường thì, một ứng dụng thích bỏ qua các thông điệp được xuất bản sau khi nó ngắt kết nối, vì việc ngắt kết nối có nghĩa là ứng dụng không quan tâm đến những gì có thể được xuất bản. Ví dụ, một ứng dụng B2B/C bán gạch có thể đăng ký một kênh nơi khách hàng có thể yêu cầu gạch. Nếu ứng dụng ngừng bán gạch, hoặc tạm thời hết gạch, nó có thể quyết định ngắt kết nối khỏi kênh để tránh nhận các yêu cầu mà nó không thể đáp ứng.
Tuy nhiên, hành vi này có thể gây bất lợi, vì cách tiếp cận "ngủ quên thì mất" có thể khiến một ứng dụng bỏ lỡ những tin nhắn mà nó cần. Nếu một ứng dụng bị lỗi hoặc phải dừng lại để bảo trì, nó có thể muốn biết những tin nhắn nào mà nó đã bỏ lỡ trong thời gian không hoạt động. Toàn bộ ý tưởng của việc nhắn tin là làm cho việc giao tiếp trở nên đáng tin cậy ngay cả khi các ứng dụng gửi và nhận cũng như mạng không hoạt động cùng một lúc.
Vì vậy, đôi khi các ứng dụng ngắt kết nối vì không muốn nhận tin nhắn từ kênh đó nữa. Nhưng đôi khi các ứng dụng phải ngắt kết nối trong một thời gian ngắn, và khi chúng kết nối lại, chúng muốn có quyền truy cập vào tất cả các tin nhắn đã được công bố trong thời gian ngắt kết nối. Một người đăng ký thường ở trạng thái kết nối (đã đăng ký) hoặc ngắt kết nối (chưa đăng ký), nhưng một trạng thái thứ ba có thể xảy ra là không hoạt động, trạng thái của một người đăng ký đang ngắt kết nối nhưng vẫn được đăng ký vì nó muốn nhận các tin nhắn được công bố trong khi nó đang ngắt kết nối.
Nếu một người đăng ký đã kết nối với một Kênh Xuất Bản - Đăng Ký nhưng bị ngắt kết nối khi một tin nhắn được xuất bản, thì hệ thống nhắn tin biết như thế nào để lưu tin nhắn cho người đăng ký nhằm có thể gửi tin nhắn khi người đăng ký kết nối lại? Tức là, làm thế nào hệ thống nhắn tin biết được một người đăng ký bị ngắt kết nối là không hoạt động hay đã hủy đăng ký? Cần phải có hai loại đăng ký, loại kết thúc khi người đăng ký ngắt kết nối và loại vẫn tồn tại ngay cả khi ứng dụng ngắt kết nối và chỉ bị hủy khi ứng dụng rõ ràng hủy đăng ký.
Mặc định, một đăng ký chỉ tồn tại lâu như kết nối của nó. Vì vậy, điều cần thiết là một loại đăng ký khác tồn tại sau khi ngắt kết nối bằng cách trở thành không hoạt động.
| Sử dụng một Người đăng ký Bền vững để hệ thống nhắn tin lưu trữ các tin nhắn được phát hành trong khi người đăng ký đang ngắt kết nối.
|
Một đăng ký bền vững lưu trữ các tin nhắn cho một người đăng ký không hoạt động và gửi các tin nhắn đã lưu khi người đăng ký kết nối lại. Bằng cách này, người đăng ký không mất bất kỳ tin nhắn nào ngay cả khi họ đã ngắt kết nối. Một đăng ký bền vững không ảnh hưởng đến hành vi của người đăng ký hoặc hệ thống nhắn tin trong khi người đăng ký đang hoạt động (ví dụ: đang kết nối). Một người đăng ký đang kết nối hoạt động như nhau dù đăng ký của họ là bền vững hay không bền vững. Sự khác biệt nằm ở cách mà hệ thống nhắn tin hoạt động khi người đăng ký bị ngắt kết nối.
Một người đăng ký bền vững đơn giản là một người đăng ký trên kênh Đăng-Tin. Tuy nhiên, khi người đăng ký ngắt kết nối khỏi hệ thống nhắn tin, họ trở nên không hoạt động và hệ thống nhắn tin sẽ lưu trữ bất kỳ tin nhắn nào được công bố trên kênh của mình cho đến khi họ trở lại hoạt động. Trong khi đó, những người đăng ký khác cùng kênh có thể không phải là bền vững; họ là những người đăng ký không bền vững.
Chuỗi Đăng ký Bền vững

Để trở thành một người đăng ký, Người Đăng Ký Bền Vững phải thiết lập việc đăng ký của mình với kênh. Khi điều đó hoàn tất, khi nó đóng kết nối của mình, nó trở thành không hoạt động. Trong khi người đăng ký đang không hoạt động, nhà phát hành phát hành một tin nhắn. Nếu người đăng ký là không bền vững, nó sẽ bỏ lỡ tin nhắn này; nhưng vì nó là bền vững, hệ thống nhắn tin lưu giữ tin nhắn này cho người đăng ký này. Khi người đăng ký đăng ký lại, trở thành hoạt động một lần nữa, hệ thống nhắn tin sẽ gửi tin nhắn đã được xếp hàng (và bất kỳ tin nhắn nào khác được lưu cho người đăng ký này). Người đăng ký nhận được tin nhắn và xử lý nó (có thể ủy quyền tin nhắn cho ứng dụng). Khi người đăng ký đã hoàn tất việc xử lý tin nhắn, nếu nó không muốn nhận thêm tin nhắn nào nữa, nó sẽ đóng kết nối của mình, trở thành không hoạt động một lần nữa. Vì nó không muốn hệ thống nhắn tin lưu giữ tin nhắn cho nó nữa, nó cũng sẽ hủy đăng ký.
Một điều thú vị cần xem xét là, điều gì sẽ xảy ra nếu một người đăng ký bền vững không bao giờ hủy đăng ký? Đăng ký bền vững không hoạt động sẽ tiếp tục giữ lại các tin nhắn, tức là hệ thống nhắn tin sẽ lưu tất cả các tin nhắn đã được phát đi cho đến khi người đăng ký kết nối lại. Nhưng nếu người đăng ký không kết nối lại trong một thời gian dài, số lượng tin nhắn được lưu trữ có thể trở nên quá lớn. Thời gian hết hạn tin nhắn có thể giúp giảm bớt vấn đề này. Hệ thống nhắn tin cũng có thể muốn giới hạn số lượng tin nhắn có thể được lưu cho một đăng ký không hoạt động.
| Ví dụ: Giao dịch chứng khoán Hệ thống giao dịch chứng khoán có thể sử dụng Kênh Phát hành-Nhận thông tin để phát sóng các thay đổi trong giá cổ phiếu; mỗi khi giá cổ phiếu thay đổi, một thông điệp được phát hành. Một người đăng ký có thể là một giao diện người dùng (GUI) hiển thị giá hiện tại của một số cổ phiếu nhất định. Một người đăng ký khác có thể là một cơ sở dữ liệu lưu trữ phạm vi giao dịch trong ngày cho một số cổ phiếu nhất định. Cả hai ứng dụng nên là thuê bao của kênh thay đổi giá để được thông báo khi giá cổ phiếu thay đổi. Đăng ký của GUI có thể không bền vững vì nó chỉ hiển thị giá hiện tại. Nếu GUI bị treo và mất kết nối với kênh, thì không có lý do gì để lưu giữ các thay đổi giá mà GUI không thể hiển thị. Ngược lại, cơ sở dữ liệu khoảng giá nên sử dụng Thuê Bao Bền Vững. Trong khi nó đang hoạt động, nó có thể hiển thị khoảng giá cho đến thời điểm đó. Nếu nó mất kết nối, khi nó kết nối lại, nó có thể xử lý các thay đổi giá đã xảy ra và cập nhật khoảng giá khi cần thiết. |
| Ví dụ: Đăng ký bền vững JMS JMS hỗ trợ các đăng ký bền vững cho Người đăng ký Chủ đề [JMS 1.1], [Hapner]. Một thách thức với các đăng ký bền vững là phân biệt giữa một người đăng ký cũ đang kết nối lại và một người đăng ký hoàn toàn mới. Trong JMS, một đăng ký bền vững được xác định bởi ba tiêu chí:
ID khách hàng của kết nối là một thuộc tính của nhà máy kết nối, được thiết lập khi nhà máy kết nối được tạo ra bằng công cụ quản trị của hệ thống nhắn tin. Tên đăng ký phải là duy nhất cho mỗi người đăng ký (cho một chủ đề và ID khách hàng cụ thể). Một thuê bao bền vững được tạo ra bằng cách sử dụng phương thức Session.createDurableSubscriber: [View full width] ConnectionFactory factory = // obtain the factory // the factory has the client ID Connection connection = factory.createConnection(); // the connection has the same client ID as the factory Topic topic = // obtain the topic String clientID = connection.getClientID(); // just in case Người đăng ký này hiện đã hoạt động. Nó sẽ nhận được tin nhắn khi chúng được công bố trên chủ đề (giống như một người đăng ký không bền vững). Để làm cho nó không còn hoạt động, hãy đóng lại, như thế này: subscriber.close(); Người đăng ký hiện đã ngắt kết nối và do đó không còn hoạt động. Mọi tin nhắn được phát hành đến chủ đề của họ sẽ được lưu cho người đăng ký này và sẽ được gửi khi họ kết nối lại. Để kích hoạt lại đăng ký, bạn phải tạo một người đăng ký bền vững mới với cùng một chủ đề, ID khách hàng và tên đăng ký. Mã vẫn giống như trước, chỉ cần nhà máy kết nối, chủ đề và tên đăng ký phải giống như trước. Bởi vì mã để thiết lập một đăng ký bền vững và để kết nối lại với nó là giống nhau, chỉ hệ thống nhắn tin mới biết liệu đăng ký bền vững này đã được thiết lập hay là một cái mới. Một hệ quả thú vị là ứng dụng kết nối lại với một đăng ký có thể không phải là ứng dụng giống như đã ngắt kết nối trước đó. Miễn là ứng dụng mới sử dụng cùng một chủ đề, cùng một nhà máy kết nối (và do đó cùng một ID khách), và cùng một tên đăng ký như ứng dụng cũ, hệ thống nhắn tin sẽ không thể phân biệt giữa hai ứng dụng và sẽ chuyển tất cả các tin nhắn tới ứng dụng mới mà chưa được chuyển tới ứng dụng cũ trước khi nó ngắt kết nối. Một khi ứng dụng có một đăng ký bền vững trên một chủ đề, nó sẽ có cơ hội nhận tất cả các tin nhắn được xuất bản cho chủ đề đó, ngay cả khi người đăng ký đóng kết nối của mình (hoặc nếu nó gặp sự cố và hệ thống nhắn tin đóng kết nối của người đăng ký cho nó). Để ngăn hệ thống nhắn tin xếp hàng các tin nhắn cho người đăng ký không hoạt động này, ứng dụng phải rõ ràng hủy đăng ký đăng ký bền vững của nó. subscriber.close(); // subscriber is now inactive, messages will be saved session.unsubscribe(subscriptionName); // subscription is removed Khi người đăng ký hủy đăng ký, gói đăng ký sẽ bị xoá khỏi chủ đề và các tin nhắn sẽ không còn được gửi đến người đăng ký này nữa. |
Ngay cả khi một ứng dụng gửi tin nhắn chỉ một lần, ứng dụng nhận có thể nhận được tin nhắn nhiều hơn một lần.
| Làm thế nào một người nhận tin nhắn có thể xử lý các tin nhắn trùng lặp? |
Các mẫu kênh trong Chương 3, "Hệ thống Tin nhắn", thảo luận về cách làm cho các kênh tin nhắn đáng tin cậy bằng cách sử dụng Giao hàng Đảm bảo. Tuy nhiên, ngay cả một số triển khai tin nhắn đáng tin cậy cũng có thể tạo ra các tin nhắn trùng lặp. Trong các kịch bản khác, Giao hàng Đảm bảo có thể không khả dụng vì giao tiếp dựa vào các giao thức vốn không đáng tin cậy. Đây là trường hợp trong nhiều kịch bản tích hợp B2B (doanh nghiệp đến doanh nghiệp), nơi các tin nhắn phải được gửi qua Internet bằng HTTP. Trong những trường hợp này, việc giao hàng tin nhắn thường chỉ có thể được đảm bảo bằng cách gửi lại tin nhắn cho đến khi có phản hồi xác nhận từ người nhận. Tuy nhiên, nếu phản hồi xác nhận bị mất do kết nối không đáng tin cậy, người gửi có thể gửi lại một tin nhắn mà người nhận đã nhận trước đó (xem hình).
Tin nhắn bị trùng lặp do vấn đề gửi xác nhận

Nhiều hệ thống nhắn tin tích hợp các cơ chế tích hợp sẵn để loại bỏ các tin nhắn trùng lặp, vì vậy ứng dụng không cần phải lo lắng về vấn đề này. Tuy nhiên, việc loại bỏ các tin nhắn trùng lặp bên trong hạ tầng nhắn tin gây ra thêm chi phí. Nếu người nhận vốn đã có khả năng chống chịu tốt với các tin nhắn trùng lặp - chẳng hạn như một người nhận không trạng thái xử lý các Tin Nhắn Lệnh kiểu truy vấn - thì thông lượng nhắn tin có thể được tăng cường nếu cho phép tồn tại các tin nhắn trùng lặp. Vì lý do này, một số hệ thống nhắn tin chỉ cung cấp chế độ giao hàng ít nhất một lần và để ứng dụng xử lý các tin nhắn trùng lặp. Những hệ thống khác cho phép ứng dụng chỉ định xem có xử lý các tin nhắn trùng lặp hay không (ví dụ, đặc tả JMS định nghĩa một chế độ DUPS_OK_ACKNOWLEDGE).
Một kịch bản khác có thể tạo ra các thông điệp trùng lặp là một giao dịch phân tán không thành công. Nhiều ứng dụng đóng gói được kết nối với hạ tầng nhắn tin qua các bộ kết nối thương mại không thể tham gia đúng cách vào cam kết hai giai đoạn phân tán. Khi một thông điệp được gửi đến nhiều ứng dụng và thông điệp đó khiến một hoặc nhiều ứng dụng này bị lỗi, có thể rất khó để phục hồi từ trạng thái không nhất quán này. Nếu những người nhận được thiết kế để bỏ qua các thông điệp trùng lặp, người gửi có thể đơn giản gửi lại thông điệp đến tất cả các người nhận. Những người nhận đã nhận và xử lý thông điệp gốc sẽ đơn giản bỏ qua việc gửi lại. Những ứng dụng không thể tiêu thụ thông điệp gốc một cách đúng đắn sẽ áp dụng thông điệp đã được gửi lại.
| Thiết kế một bộ thu để trở thành Bộ thu Idempotent, một bộ thu có thể an toàn nhận cùng một thông điệp nhiều lần. |
Thuật ngữ "idempotent" được sử dụng trong toán học để mô tả một hàm tạo ra kết quả giống nhau khi nó được áp dụng cho chính nó: f(x) = f(f(x)). Trong lĩnh vực tin nhắn, khái niệm này được dịch thành một thông điệp có tác động giống nhau dù nó được nhận một lần hay nhiều lần. Điều này có nghĩa là một thông điệp có thể được gửi lại một cách an toàn mà không gây ra bất kỳ vấn đề nào ngay cả khi người nhận nhận được các bản sao của cùng một thông điệp.
Tính đồng nhất có thể đạt được thông qua hai phương pháp chính:
Xóa bỏ rõ ràng các bản sao, tức là loại bỏ các tin nhắn trùng lặp.
Xác định ngữ nghĩa thông điệp để hỗ trợ tính bất biến.
Người nhận có thể loại bỏ các tin nhắn trùng lặp một cách rõ ràng (giả sử "de-dupe" là một từ tiếng Anh hợp lệ) bằng cách theo dõi các tin nhắn mà họ đã nhận được. Một mã định danh tin nhắn duy nhất giúp đơn giản hóa nhiệm vụ này và giúp phát hiện những trường hợp mà hai tin nhắn hợp lệ có cùng nội dung tin nhắn đến. Bằng cách sử dụng một trường riêng biệt, mã định danh tin nhắn, chúng ta không ràng buộc ngữ nghĩa của một tin nhắn trùng lặp với nội dung của tin nhắn. Sau đó, chúng ta gán một mã định danh tin nhắn duy nhất cho mỗi tin nhắn. Nhiều hệ thống nhắn tin, chẳng hạn như các công cụ nhắn tin tương thích với JMS, tự động gán mã định danh tin nhắn duy nhất cho mỗi tin nhắn mà không cần các ứng dụng phải lo lắng về chúng.
Để phát hiện và loại bỏ các tin nhắn trùng lặp dựa trên mã định danh của tin nhắn, người nhận tin nhắn cần giữ một danh sách các mã định danh của tin nhắn đã nhận. Một trong những quyết định thiết kế quan trọng là giữ lịch sử của các tin nhắn trong bao lâu và liệu có nên lưu trữ lịch sử này vào bộ nhớ vĩnh viễn như đĩa hay không. Quyết định này chủ yếu phụ thuộc vào hợp đồng giữa người gửi và người nhận. Trong trường hợp đơn giản nhất, người gửi gửi một tin nhắn tại một thời điểm, chờ đợi sự xác nhận của người nhận sau mỗi tin nhắn. Trong kịch bản này, người nhận chỉ cần so sánh mã định danh của bất kỳ tin nhắn đến nào với mã định danh của tin nhắn trước đó. Sau đó, họ sẽ bỏ qua tin nhắn mới nếu các mã định danh là giống nhau. Hiệu quả là người nhận giữ lại lịch sử của một tin nhắn duy nhất. Trong thực tế, kiểu giao tiếp này có thể rất kém hiệu quả, đặc biệt nếu thời gian trễ (thời gian mà tin nhắn di chuyển từ người gửi đến người nhận) là đáng kể so với thông lượng tin nhắn mong muốn. Trong những tình huống này, người gửi có thể muốn gửi một tập hợp các tin nhắn mà không cần chờ đợi sự xác nhận cho từng tin nhắn. Tuy nhiên, điều này có nghĩa là người nhận phải giữ một lịch sử dài hơn về các mã định danh của các tin nhắn đã nhận. Kích thước "ký ức" của người nhận phụ thuộc vào số lượng tin nhắn mà người gửi có thể gửi mà không nhận được sự xác nhận từ người nhận. Vấn đề này giống với các yếu tố đã được trình bày trong Resequencer.
Việc loại bỏ các tin nhắn trùng lặp là một ví dụ khác cho thấy chúng ta có thể học hỏi được nhiều điều bằng cách xem xét kỹ lưỡng giao thức TCP/IP cấp thấp. Khi các gói mạng IP được định tuyến qua mạng, các gói trùng lặp có thể được tạo ra. Giao thức TCP/IP đảm bảo việc loại bỏ các gói trùng lặp bằng cách gán một định danh duy nhất cho mỗi gói. Người gửi và người nhận thương lượng một "kích thước cửa sổ" mà người nhận phân bổ để phát hiện các gói trùng lặp. Để thảo luận chi tiết về cách TCP/IP thực hiện cơ chế này, xem [Stevens].
Trong một số trường hợp, có thể có sự cám dỗ khi sử dụng khóa kinh doanh làm định danh tin nhắn và để lớp lưu trữ xử lý việc loại bỏ bản sao. Ví dụ, hãy giả sử rằng một ứng dụng lưu trữ các đơn hàng đến trong cơ sở dữ liệu. Nếu mỗi đơn hàng chứa một số đơn hàng duy nhất, và chúng ta cấu hình cơ sở dữ liệu để sử dụng khóa duy nhất trên trường số đơn hàng, thì thao tác chèn vào cơ sở dữ liệu sẽ thất bại nếu một tin nhắn đơn hàng trùng lặp được nhận. Giải pháp này trông có vẻ thanh lịch vì chúng ta đã ủy thác việc kiểm tra các bản sao cho hệ thống cơ sở dữ liệu, rất hiệu quả trong việc phát hiện các khóa trùng lặp. Nhưng chúng ta phải cẩn thận vì đã kết hợp hai ngữ nghĩa vào một trường duy nhất. Cụ thể, chúng ta đã liên kết các ngữ nghĩa liên quan đến hạ tầng (một tin nhắn trùng lặp) với một trường kinh doanh (số đơn hàng). Hãy tưởng tượng rằng các yêu cầu kinh doanh thay đổi để khách hàng có thể sửa đổi các đơn hàng hiện có bằng cách gửi một tin nhắn khác với cùng một số đơn hàng (điều này khá phổ biến). Chúng ta giờ đây sẽ phải thực hiện các thay đổi trong cấu trúc tin nhắn, vì chúng ta đã liên kết định danh tin nhắn duy nhất với một trường kinh doanh. Do đó, tốt nhất là nên tránh việc gán hai ngữ nghĩa cho một trường duy nhất.
Sử dụng cơ sở dữ liệu để buộc loại bỏ bản sao đôi khi được thực hiện với các trình kết nối cơ sở dữ liệu do các nhà cung cấp hạ tầng nhắn tin cung cấp. Trong nhiều trường hợp, các trình kết nối này không có khả năng loại bỏ các bản sao, vì vậy chức năng này phải được ủy thác cho cơ sở dữ liệu.
Một cách tiếp cận thay thế để đạt được tính bất biến là định nghĩa ngữ nghĩa của một thông điệp sao cho việc gửi lại thông điệp không ảnh hưởng đến hệ thống. Ví dụ, thay vì định nghĩa một thông điệp là "Thêm 10 đô la vào tài khoản 12345," chúng ta có thể thay đổi thông điệp thành "Đặt số dư của tài khoản 12345 thành 110 đô la." Cả hai thông điệp đều đạt được cùng một kết quả nếu số dư tài khoản hiện tại là 100 đô la. Thông điệp thứ hai là bất biến vì việc nhận nó hai lần sẽ không có bất kỳ tác động nào. Thú thật, ví dụ này bỏ qua các tình huống đồng thời, chẳng hạn như trường hợp một thông điệp khác, "Đặt số dư của tài khoản 12345 thành 150 đô la," đến giữa thông điệp gốc và thông điệp trùng lặp.
| Ví dụ: Microsoft IDL (MIDL) Ngôn ngữ Định nghĩa Giao diện Microsoft (MIDL) hỗ trợ khái niệm tính idempotent như một phần của ngữ nghĩa cuộc gọi từ xa. Một thủ tục từ xa có thể được khai báo là idempotent bằng cách sử dụng thuộc tính [idempotent]. Đặc tả MIDL quy định rằng thuộc tính "[idempotent] chỉ ra rằng một hoạt động không thay đổi thông tin trạng thái và trả về cùng một kết quả mỗi khi nó được thực hiện. Thực hiện quy trình nhiều lần có tác động giống như thực hiện nó một lần." interface IFoo; [ uuid(5767B67C-3F02-40ba-8B85-D8516F20A83B), pointer_default(unique) ] interface IFoo { [idempotent] bool GetCustomerName ( [in] int CustomerID, [out] char *Name ); } |
Một ứng dụng có một dịch vụ mà nó muốn cung cấp cho các ứng dụng khác.
| Làm thế nào để một ứng dụng thiết kế một dịch vụ có thể được gọi cả thông qua các công nghệ nhắn tin khác nhau và thông qua các kỹ thuật không nhắn tin? |
Một ứng dụng có thể không muốn phải chọn xem một dịch vụ (một thao tác trong Lớp Dịch vụ [EAA]) có thể được gọi đồng bộ hay bất đồng bộ: Nó có thể muốn hỗ trợ cả hai phương pháp cho cùng một dịch vụ. Tuy nhiên, các công nghệ có thể dường như ép buộc phải lựa chọn. Ví dụ, một ứng dụng được triển khai bằng EJB có thể cần sử dụng một session bean để hỗ trợ các khách hàng đồng bộ, nhưng lại cần một MDB để hỗ trợ các khách hàng tin nhắn.
Cảm ơn Mark Weitzel vì ví dụ này.
Các nhà phát triển thiết kế một ứng dụng để làm việc với các ứng dụng khác, chẳng hạn như một ứng dụng B2B, có thể không biết các ứng dụng khác mà họ đang giao tiếp và cách thức mà các giao tiếp khác nhau sẽ hoạt động. Có quá nhiều công nghệ nhắn tin và định dạng dữ liệu khác nhau để cố gắng hỗ trợ mọi thứ chỉ trong trường hợp cần thiết.
Cảm ơn Luke Hohmann vì ví dụ này.
Việc nhận và xử lý một tin nhắn liên quan đến một số bước; tách biệt những bước này có thể khó khăn và không cần thiết phức tạp. Tuy nhiên, mã Điểm cuối tin nhắn mà trộn lẫn những nhiệm vụ này - nhận tin nhắn, trích xuất nội dung của nó và hành động dựa trên những nội dung đó để thực hiện công việc - có thể khó tái sử dụng.
Khi thiết kế các client cho nhiều kiểu giao tiếp khác nhau, có thể sẽ thấy cần thiết phải triển khai lại dịch vụ cho từng kiểu. Điều này làm cho việc hỗ trợ mỗi kiểu mới trở nên rắc rối và tạo ra rủi ro rằng mỗi kiểu có thể không sản xuất ra cùng một hành vi. Điều cần thiết là một cách để một dịch vụ duy nhất có thể hỗ trợ nhiều kiểu giao tiếp khác nhau.
| Thiết kế một Trình kích hoạt Dịch vụ kết nối các tin nhắn trên kênh với dịch vụ đang được truy cập.
|
Một Bộ Kích Hoạt Dịch Vụ có thể là một chiều (chỉ yêu cầu) hoặc hai chiều (Yêu cầu-Trả lời). Dịch vụ có thể đơn giản như một cuộc gọi phương thức đồng bộ và không từ xa, có thể là một phần của Lớp Dịch Vụ [EAA]. Bộ kích hoạt có thể được mã cứng để luôn gọi cùng một dịch vụ, hoặc nó có thể sử dụng phản chiếu để gọi dịch vụ được chỉ định bởi thông điệp. Bộ kích hoạt xử lý tất cả các chi tiết nhắn tin và gọi dịch vụ như bất kỳ khách hàng nào khác, để dịch vụ thậm chí không biết rằng nó đang được gọi thông qua nhắn tin.
Chuỗi Kích Hoạt Dịch Vụ cho Yêu Cầu-Phản Hồi

Bộ kích hoạt dịch vụ xử lý việc nhận thông điệp yêu cầu (dưới dạng Người tiêu dùng theo định kỳ hoặc Người tiêu dùng theo sự kiện). Nó biết định dạng của thông điệp và xử lý thông điệp để trích xuất thông tin cần thiết để biết dịch vụ nào cần được gọi và giá trị tham số nào cần được truyền vào. Sau đó, bộ kích hoạt gọi dịch vụ tương tự như bất kỳ khách hàng nào khác của dịch vụ và chặn lại trong khi dịch vụ đang thực thi. Khi dịch vụ hoàn thành và trả về một giá trị, bộ kích hoạt có thể tùy chọn tạo một thông điệp trả lời chứa giá trị đó và trả lại cho người yêu cầu. (Thông điệp trả lời làm cho việc gọi dịch vụ trở thành một ví dụ về thông điệp Yêu cầu-Phản hồi.)
Một Bộ Kích Hoạt Dịch Vụ cho phép một dịch vụ được viết như thể nó luôn được gọi đồng bộ. Bộ kích hoạt nhận tin nhắn bất đồng bộ, xác định dịch vụ nào cần được gọi và dữ liệu nào cần truyền đến, sau đó gọi dịch vụ đó một cách đồng bộ. Dịch vụ này được thiết kế để hoạt động mà không cần tin nhắn, nhưng bộ kích hoạt cho phép nó dễ dàng được kích hoạt thông qua tin nhắn.
Nếu Bộ Kích Hoạt Dịch Vụ không thể xử lý thông điệp thành công, thông điệp đó không hợp lệ và nên được chuyển đến Kênh Thông Điệp Không Hợp Lệ. Nếu thông điệp có thể được xử lý và dịch vụ được kích hoạt thành công, thì bất kỳ lỗi nào xảy ra trong quá trình thực thi dịch vụ đều là lỗi ngữ nghĩa trong ứng dụng và nên được ứng dụng xử lý.
Các nhà phát triển vẫn có thể không dự đoán được mọi cách mà các đối tác có thể muốn truy cập vào dịch vụ của họ, nhưng ít nhất họ biết dịch vụ nào mà ứng dụng của họ sẽ cung cấp và có thể triển khai những dịch vụ đó. Sau đó, việc triển khai các kích hoạt mới cho các công nghệ và định dạng khác nhau khi cần thiết là khá dễ dàng.
Mô hình Kích hoạt Dịch vụ này cũng được tài liệu hóa trong [CoreJ2EE], nơi mô hình này được đặt tên ban đầu. Phiên bản của mô hình đó có phần khác biệt so với phiên bản này, vì nó giả định rằng kích hoạt là một Người tiêu dùng Dựa trên Sự kiện và rằng dịch vụ đã tồn tại để kích hoạt có thể được thêm vào dịch vụ, nhưng cả hai phiên bản đều đề xuất cùng một giải pháp cho cùng một vấn đề theo cách rất tương tự. Kích hoạt Dịch vụ liên quan đến mô hình Bán đồng bộ/Bán không đồng bộ [POSA2], phân tách quá trình dịch vụ thành các lớp đồng bộ và không đồng bộ.
Một Bộ Kích Hoạt Dịch Vụ thường nhận các Tin Nhắn Lệnh, mô tả dịch vụ nào cần được kích hoạt. Bộ Kích Hoạt Dịch Vụ hoạt động như một Cổng Giao Tiếp, tách biệt chi tiết giao tiếp khỏi dịch vụ. Bộ kích hoạt có thể là một Người Tiêu Thụ Định Kỳ hoặc một Người Tiêu Thụ Dựa Trên Sự Kiện. Nếu dịch vụ là giao dịch, bộ kích hoạt nên là một Khách Hàng Giao Dịch để việc tiêu thụ tin nhắn có thể tham gia vào cùng một giao dịch với việc gọi dịch vụ. Nhiều bộ kích hoạt có thể là Những Người Tiêu Thụ Cạnh Tranh hoặc được phối hợp bởi một Trình Gửi Tin Nhắn. Nếu một Bộ Kích Hoạt Dịch Vụ không thể xử lý một tin nhắn thành công, nó nên gửi tin nhắn đến một Kênh Tin Nhắn Không Hợp Lệ.
| Ví dụ: J2EE Java Beans Doanh Nghiệp Xem xét, chẳng hạn như EJB trong J2EE: Bao encapsulate dịch vụ như một session bean, sau đó triển khai MDB cho các tình huống nhắn tin khác nhau: một cho một điểm đến JMS sử dụng tin nhắn của một định dạng; một khác cho một điểm đến khác sử dụng một định dạng khác; một khác cho một dịch vụ web / tin nhắn SOAP; và như vậy. Mỗi MDB xử lý tin nhắn bằng cách gọi dịch vụ là một Service Activator. Các client muốn gọi dịch vụ một cách đồng bộ có thể truy cập trực tiếp vào session bean. |
Giới thiệu
Bus điều khiển
Đường vòng
Nghe lén
Lịch sử Tin nhắn
Cửa hàng tin nhắn
Proxy thông minh
Thông báo thử nghiệm
Kênh làm sạch
Trong khi phát triển một giải pháp nhắn tin không phải là một nhiệm vụ dễ dàng, việc vận hành một giải pháp như vậy trong môi trường sản xuất cũng đầy thách thức: Một giải pháp tích hợp dựa trên tin nhắn có thể tạo, định tuyến và chuyển đổi hàng nghìn hoặc thậm chí hàng triệu tin nhắn trong một ngày. Chúng tôi phải đối mặt với các ngoại lệ, các điểm nghẽn hiệu suất và những thay đổi trong các hệ thống tham gia. Để làm mọi thứ trở nên khó khăn hơn, các thành phần được phân tán trên nhiều nền tảng và máy móc có thể nằm ở nhiều địa điểm khác nhau.
Ngoài những phức tạp và quy mô vốn có của việc tích hợp các ứng dụng đóng gói và tùy chỉnh phân tán, các lợi ích kiến trúc của việc kết nối lỏng thực sự làm cho việc kiểm thử và gỡ lỗi một hệ thống trở nên khó khăn hơn. Martin Fowler gọi đây là triệu chứng "giấc mơ của kiến trúc sư, cơn ác mộng của lập trình viên": Các nguyên tắc kiến trúc của sự kết nối lỏng và sự gián tiếp giảm bớt những giả định mà các hệ thống tạo ra về nhau và do đó cung cấp tính linh hoạt. Tuy nhiên, việc kiểm thử một hệ thống mà trong đó một nhà sản xuất tin nhắn không biết ai là người tiêu thụ tin nhắn có thể là thách thức. Thêm vào đó, các khía cạnh bất đồng bộ và tạm thời của việc nhắn tin khiến mọi thứ trở nên phức tạp hơn. Ví dụ, giải pháp nhắn tin có thể không được thiết kế để nhà sản xuất tin nhắn nhận được tin nhắn trả lời từ các bên nhận. Tương tự, hạ tầng nhắn tin thường đảm bảo việc giao tin nhắn nhưng không đảm bảo thời gian giao hàng. Điều này làm cho việc phát triển các trường hợp kiểm thử phụ thuộc vào kết quả của việc giao tin nhắn trở nên khó khăn.
Khi giám sát một giải pháp tin nhắn, chúng ta có thể theo dõi dòng chảy của các tin nhắn ở hai cấp độ trừu tượng khác nhau. Một giải pháp quản lý hệ thống điển hình giám sát số lượng tin nhắn đang được gửi đi hoặc thời gian cần thiết để xử lý một tin nhắn. Những giải pháp giám sát này không kiểm tra dữ liệu tin nhắn ngoại trừ có thể một số trường trong tiêu đề tin nhắn như định danh tin nhắn hoặc Lịch sử Tin nhắn. Ngược lại, các giải pháp giám sát hoạt động kinh doanh (BAM) tập trung vào dữ liệu payload chứa trong tin nhắn, ví dụ, giá trị đô la của tất cả các đơn hàng được đặt trong giờ qua. Nhiều mẫu được trình bày trong phần này đủ chung để có thể được sử dụng cho cả hai mục đích. Tuy nhiên, vì BAM là một lĩnh vực hoàn toàn mới và chia sẻ nhiều phức tạp với kho dữ liệu (một vấn đề mà chúng tôi chưa đề cập đến), chúng tôi quyết định thảo luận về các mẫu trong bối cảnh quản lý hệ thống.
Các mẫu quản lý hệ thống được thiết kế để giải quyết các yêu cầu này và cung cấp các công cụ để duy trì một hệ thống dựa trên tin nhắn phức tạp hoạt động. Các mẫu trong chương này được chia thành ba loại: giám sát và kiểm soát, quan sát và phân tích lưu lượng tin nhắn, và thử nghiệm và gỡ lỗi.
Một Bus Điều Khiển cung cấp một điểm kiểm soát duy nhất để quản lý và giám sát một giải pháp phân phối. Nó kết nối nhiều thành phần với một bảng điều khiển quản lý trung tâm có thể hiển thị trạng thái của từng thành phần và giám sát lưu lượng tin nhắn qua các thành phần. Bảng điều khiển cũng có thể được sử dụng để gửi lệnh điều khiển đến các thành phần, ví dụ, để thay đổi dòng chảy của tin nhắn.
Chúng ta có thể muốn định tuyến thông điệp qua các bước bổ sung, chẳng hạn như xác thực hoặc ghi log. Vì những bước này có thể gây ra tải trọng hiệu suất, chúng ta có thể muốn có khả năng bật và tắt chúng thông qua bus điều khiển. Một Detour mang lại cho chúng ta khả năng này.
Đôi khi, chúng ta muốn kiểm tra nội dung của một thông điệp mà không ảnh hưởng đến dòng chảy chính của thông điệp. Một Wire Tap cho phép chúng ta nghe lén lưu lượng tin nhắn.
Khi chúng ta gỡ lỗi một hệ thống dựa trên tin nhắn, việc biết được một tin nhắn cụ thể đã đi qua đâu là một trợ giúp lớn. Lịch sử Tin nhắn giữ một bản ghi của tất cả các thành phần mà tin nhắn đã ghé thăm mà không tạo ra sự phụ thuộc giữa các thành phần.
Khi Lịch sử Tin nhắn liên quan đến một tin nhắn cá nhân, một Kho Tin nhắn trung tâm có thể cung cấp một tài khoản hoàn chỉnh về mọi tin nhắn đã di chuyển qua hệ thống. Kết hợp với Lịch sử Tin nhắn, Kho Tin nhắn có thể phân tích tất cả các con đường có thể mà tin nhắn có thể đi qua hệ thống.
Máy nghe lén, Lịch sử Tin nhắn và Kho lưu trữ Tin nhắn giúp chúng ta phân tích luồng tin nhắn bất đồng bộ. Để theo dõi các tin nhắn gửi đến các dịch vụ yêu cầu-phản hồi, chúng ta cần chèn một Proxy Thông minh vào luồng tin nhắn.
Việc thử nghiệm một hệ thống nhắn tin trước khi triển khai vào sản xuất là một ý tưởng rất hay. Tuy nhiên, việc kiểm tra không nên dừng lại ở đó. Bạn nên thường xuyên xác minh rằng hệ thống nhắn tin đang chạy vẫn tiếp tục hoạt động đúng cách. Bạn có thể làm điều này bằng cách định kỳ gửi một Tin Nhắn Kiểm Tra vào hệ thống và xác minh kết quả.
Khi một thành phần gặp sự cố hoặc hoạt động không đúng, dễ dàng có được những thông điệp không mong muốn trên một kênh. Trong quá trình kiểm tra, việc xóa tất cả các thông điệp còn lại trên một kênh là rất hữu ích để các thành phần đang được kiểm tra không nhận được các thông điệp "thừa". Một Bộ làm sạch Kênh sẽ thực hiện điều đó cho chúng ta.
Tự nhiên, các hệ thống tích hợp doanh nghiệp là phân tán. Thực tế, một trong những phẩm chất định nghĩa của hệ thống nhắn tin doanh nghiệp là cho phép giao tiếp giữa các hệ thống khác nhau. Các hệ thống nhắn tin cho phép thông tin được định tuyến và chuyển đổi để dữ liệu có thể được trao đổi giữa các hệ thống này. Trong hầu hết các trường hợp, các ứng dụng này được phân bổ trên nhiều mạng, tòa nhà, thành phố hoặc châu lục.
| Làm thế nào chúng ta có thể quản lý một hệ thống nhắn tin hiệu quả khi nó được phân tán trên nhiều nền tảng và nhiều khu vực địa lý rộng lớn? |
Một kiến trúc phân tán, lỏng lẻo cho phép tính linh hoạt và khả năng mở rộng. Đồng thời, nó cũng đặt ra những thách thức nghiêm trọng cho việc quản lý và kiểm soát một hệ thống như vậy. Chẳng hạn, làm thế nào bạn có thể biết liệu tất cả các thành phần đều hoạt động hay không? Một trạng thái quá trình đơn giản sẽ không đủ, vì các quá trình được phân bổ trên nhiều máy khác nhau. Ngoài ra, nếu bạn không thể lấy trạng thái từ một máy từ xa, điều đó có nghĩa là máy từ xa không hoạt động, hay có thể là giao tiếp với máy từ xa bị gián đoạn?
Ngoài việc chỉ biết liệu một hệ thống hoặc một thành phần đang hoạt động hay không, bạn cũng cần theo dõi hành vi động của hệ thống. Thông lượng tin nhắn là bao nhiêu? Có bất kỳ sự chậm trễ bất thường nào không? Các kênh có đang bị đầy không? Một số thông tin này yêu cầu theo dõi thời gian di chuyển của tin nhắn giữa các thành phần hoặc thông qua các thành phần. Điều này đòi hỏi việc thu thập và kết hợp thông tin từ hơn một máy.
Ngoài ra, chỉ việc đọc thông tin từ các thành phần có thể không đủ. Thường thì bạn cần phải thực hiện các điều chỉnh hoặc thay đổi cài đặt cấu hình khi hệ thống đang hoạt động. Ví dụ, bạn có thể cần bật hoặc tắt các tính năng ghi log trong khi hệ thống đang chạy. Nhiều ứng dụng sử dụng các tệp thuộc tính và nhật ký lỗi để đọc thông tin cấu hình và báo cáo điều kiện lỗi. Cách tiếp cận này thường hoạt động tốt miễn là ứng dụng chỉ bao gồm một máy đơn hoặc có thể là một số ít máy. Trong một giải pháp lớn, phân tán, các tệp thuộc tính sẽ phải được sao chép đến các máy từ xa bằng cách sử dụng một số cơ chế truyền tệp, điều này yêu cầu hệ thống tệp trên mỗi máy phải có thể truy cập từ xa. Điều này có thể gây ra rủi ro về bảo mật và có thể gặp nhiều thách thức nếu các máy được kết nối qua Internet hoặc một mạng diện rộng mà có thể không hỗ trợ các giao thức ánh xạ tệp. Ngoài ra, các phiên bản của các tệp thuộc tính cục bộ cũng sẽ phải được quản lý cẩn thận - một cơn ác mộng trong quản lý đang chờ xảy ra.
Có vẻ như việc tận dụng hạ tầng nhắn tin để thực hiện một số nhiệm vụ này là điều tự nhiên. Ví dụ, chúng ta có thể gửi một tin nhắn đến một thành phần để thay đổi cấu hình của nó. Tin nhắn điều khiển này có thể được vận chuyển và định tuyến như một tin nhắn thông thường. Điều này sẽ giải quyết hầu hết các vấn đề giao tiếp nhưng cũng đặt ra những thách thức mới. Các tin nhắn cấu hình nên phải tuân theo các chính sách bảo mật nghiêm ngặt hơn so với các tin nhắn ứng dụng thông thường. Chẳng hạn, một tin nhắn điều khiển bị định dạng sai có thể dễ dàng làm cho một thành phần ngừng hoạt động. Thêm vào đó, sẽ ra sao nếu các tin nhắn bị xếp hàng trên một kênh nhắn tin vì một thành phần đang hoạt động không đúng? Nếu chúng ta gửi một tin nhắn điều khiển để đặt lại thành phần, tin nhắn điều khiển này sẽ bị xếp hàng cùng với tất cả các tin nhắn khác và không đến được với thành phần đang gặp vấn đề. Một số hệ thống nhắn tin hỗ trợ sự ưu tiên của tin nhắn, điều này có thể giúp đưa các tin nhắn điều khiển lên phía trước trong hàng đợi. Tuy nhiên, không phải tất cả các hệ thống đều cung cấp khả năng này, và sự ưu tiên có thể không giúp ích nếu một hàng đợi đã đầy và từ chối chấp nhận thêm tin nhắn. Tương tự, một số tin nhắn điều khiển có ưu tiên thấp hơn so với các tin nhắn ứng dụng. Nếu chúng ta có các thành phần phát hành tin nhắn trạng thái định kỳ, việc trì hoãn hoặc mất một tin nhắn điều khiển "Tôi đang hoạt động" có thể ít gây phiền toái hơn so với việc trì hoãn hoặc mất tin nhắn "Đơn hàng trị giá 1 triệu đô la".
| Sử dụng Bus Điều Khiển để quản lý một hệ thống tích hợp doanh nghiệp. Bus Điều Khiển sử dụng cùng một cơ chế nhắn tin được sử dụng bởi dữ liệu ứng dụng nhưng sử dụng các kênh riêng biệt để truyền dữ liệu liên quan đến việc quản lý các thành phần tham gia vào dòng nhắn.
|
Mỗi thành phần trong hệ thống hiện đang được kết nối với hai hệ thống nhắn tin:
Luồng Tin Nhắn Ứng Dụng
"Xe buýt điều khiển"
Dòng chảy tin nhắn ứng dụng vận chuyển tất cả các tin nhắn liên quan đến ứng dụng. Các thành phần đăng ký và phát hành trên các kênh này giống như họ sẽ làm trong một kịch bản không được quản lý. Ngoài ra, mỗi thành phần cũng gửi và nhận tin nhắn từ các kênh tạo thành Bus Điều khiển. Các kênh này kết nối đến một thành phần quản lý trung tâm.
Xe buýt điều khiển rất phù hợp để mang theo các loại thông điệp sau đây:
Cấu hình Mỗi thành phần liên quan trong luồng tin nhắn nên có các tham số có thể cấu hình, có thể thay đổi theo yêu cầu. Các tham số này bao gồm địa chỉ kênh, định dạng dữ liệu tin nhắn, thời gian chờ, và nhiều thứ khác. Các thành phần sử dụng Control Bus thay vì các tệp thuộc tính để truy xuất thông tin này từ một kho trung tâm, cho phép một điểm cấu hình trung tâm và khả năng cấu hình lại giải pháp tích hợp trong thời gian thực. Ví dụ, bảng định tuyến bên trong một Router dựa trên nội dung có thể cần được cập nhật một cách động dựa trên các điều kiện của hệ thống, chẳng hạn như quá tải hoặc sự cố thành phần.
Nhịp tim Mỗi thành phần có thể gửi một thông điệp nhịp tim định kỳ trên Bus Điều khiển tại các khoảng thời gian được chỉ định để ứng dụng bảng điều khiển trung tâm có thể xác minh rằng thành phần đang hoạt động bình thường. Nhịp tim này cũng có thể bao gồm các chỉ số về thành phần, chẳng hạn như số lượng thông điệp đã xử lý và lượng bộ nhớ khả dụng trên máy.
Tin Nhắn Kiểm Tra Các tin nhắn nhịp tim cho biết rằng một thành phần vẫn còn hoạt động, nhưng chúng có thể cung cấp thông tin hạn chế về khả năng của thành phần trong việc xử lý chính xác các tin nhắn. Ngoài việc yêu cầu các thành phần phát các tin nhắn nhịp tim định kỳ đến Bus Kiểm Soát, chúng ta có thể chèn các tin nhắn kiểm tra vào dòng tin nhắn mà các thành phần sẽ xử lý. Chúng ta sẽ trích xuất tin nhắn sau đó để xem liệu thành phần có xử lý tin nhắn một cách chính xác hay không. Vì phương pháp này làm mờ định nghĩa của Bus Kiểm Soát và dòng tin nhắn ứng dụng, chúng tôi đã định nghĩa một mô hình riêng cho nó (xem Tin Nhắn Kiểm Tra).
Ngoại lệ Mỗi thành phần có thể chuyển tiếp các điều kiện ngoại lệ đến Bus Điều khiển để được đánh giá. Các ngoại lệ nghiêm trọng có thể làm cho người vận hành được cảnh báo. Các quy tắc để xác định xử lý ngoại lệ nên được quy định trong một bộ xử lý trung tâm.
Thống kê Mỗi thành phần có thể thu thập thông tin thống kê về số lượng tin nhắn đã được xử lý, thông lượng trung bình, thời gian trung bình để xử lý một tin nhắn, và các thông tin khác. Một số dữ liệu này có thể được phân tách theo loại tin nhắn, vì vậy chúng ta có thể xác định xem liệu tin nhắn của một loại nhất định có đang làm ngập hệ thống hay không. Vì loại tin nhắn này có xu hướng có độ ưu tiên thấp hơn so với các loại tin nhắn khác, có khả năng là Bus Điều khiển sử dụng các kênh không đảm bảo hoặc kênh có độ ưu tiên thấp hơn cho loại dữ liệu này.
Bảng điều khiển trực tiếp Hầu hết các chức năng được đề cập ở đây có thể được tổng hợp để hiển thị trong một bảng điều khiển trung tâm. Từ đây, các nhà điều hành có thể đánh giá tình trạng hoạt động của hệ thống nhắn tin và thực hiện các hành động khắc phục nếu cần.
Nhiều chức năng mà Bus điều khiển hỗ trợ giống như các chức năng quản lý mạng truyền thống được sử dụng để giám sát và duy trì bất kỳ giải pháp mạng nào. Bus điều khiển cho phép chúng ta triển khai các chức năng quản lý tương đương ở mức hệ thống nhắn tin, về cơ bản nâng chúng từ cấp mạng IP thấp xuống mức nhắn tin phong phú hơn. Cung cấp chức năng quản lý là điều cần thiết cho hoạt động thành công của một hạ tầng nhắn tin cũng như cho một hạ tầng mạng. Thật không may, sự thiếu vắng các tiêu chuẩn quản lý cho các giải pháp nhắn tin khiến cho việc xây dựng các giải pháp quản lý có thể tái sử dụng trên toàn doanh nghiệp cho các hệ thống nhắn tin trở nên khó khăn.
Khi chúng tôi thiết kế các thành phần xử lý tin nhắn, chúng tôi cấu trúc bộ xử lý lõi xung quanh ba giao diện (xem hình). Giao diện dữ liệu vào nhận tin nhắn đến từ kênh tin nhắn. Giao diện dữ liệu ra gửi các tin nhắn đã được xử lý đến kênh xuất. Giao diện điều khiển gửi và nhận tin nhắn điều khiển từ và đến Bus Điều khiển.
Các Giao Diện Chính của Một Thành Phần Gửi Tin Nhắn

| Ví dụ: Thiết lập ví dụ về Người môi giới vay vốn Trong Chương 12, "Interlude: Ví dụ Quản lý Hệ thống," chúng tôi trình bày cách sử dụng Bus Kiểm soát để thực hiện ví dụ về trung gian cho vay từ Chương 9, "Interlude: Gửi tin nhắn Phức hợp." Việc thực hiện bao gồm một bảng điều khiển quản lý đơn giản hiển thị trạng thái của các thành phần theo thời gian thực (xem "Quản lý Hệ thống Trung gian cho vay" trong Chương 12). |
Đôi khi, chúng ta muốn điều chỉnh lộ trình mà các tin nhắn đi theo dựa trên các yếu tố bên ngoài.
| Làm thế nào bạn có thể chuyển tiếp một tin nhắn qua các bước trung gian để thực hiện các chức năng xác thực, kiểm tra hoặc gỡ lỗi? |
Việc thực hiện xác thực trên các tin nhắn di chuyển giữa các thành phần có thể là một công cụ gỡ lỗi rất hữu ích. Tuy nhiên, những bước bổ sung này có thể không phải lúc nào cũng cần thiết và sẽ làm chậm hệ thống nếu chúng luôn được thực hiện.
Việc có thể bao gồm hoặc bỏ qua những bước này dựa trên một cài đặt trung tâm có thể là một công cụ rất hiệu quả để gỡ lỗi hoặc tinh chỉnh hiệu suất. Ví dụ, trong khi chúng tôi kiểm tra một hệ thống, chúng tôi có thể muốn truyền các thông điệp qua các bước xác thực bổ sung. Việc bỏ qua những bước này trong môi trường sản xuất có thể cải thiện hiệu suất. Chúng tôi có thể so sánh những xác thực này với các câu lệnh khẳng định trong mã nguồn được thực thi trong cấu hình gỡ lỗi nhưng không trong cấu hình phát hành của tệp thực thi.
Tương tự, trong quá trình khắc phục sự cố, việc định tuyến thông điệp qua các bước bổ sung để ghi lại hoặc giám sát có thể hữu ích. Việc có khả năng bật và tắt các bước ghi lại này cho phép chúng ta tối đa hóa khả năng truyền tải thông điệp trong các tình huống bình thường.
| Xây dựng một Đường vòng với một Bộ định tuyến dựa trên ngữ cảnh được điều khiển qua Bảng điều khiển. Trong một trạng thái, bộ định tuyến sẽ chuyển tiếp các tin nhắn đến thông qua các bước bổ sung, trong khi trong trạng thái khác, nó sẽ chuyển tiếp các tin nhắn trực tiếp đến kênh đích.
|
Detour sử dụng một bộ định tuyến dựa trên ngữ cảnh đơn giản với hai kênh đầu ra. Một kênh đầu ra truyền tin nhắn không thay đổi đến đích gốc. Khi được chỉ định bởi Bus Điều khiển, Detour định tuyến các tin nhắn đến một kênh khác. Kênh này gửi tin nhắn đến các thành phần bổ sung có thể kiểm tra và/hoặc sửa đổi tin nhắn. Cuối cùng, các thành phần này định tuyến tin nhắn đến cùng một đích.
Nếu lộ trình đi vòng chỉ chứa một thành phần duy nhất, có thể hiệu quả hơn khi kết hợp công tắc Detour và thành phần đó thành một bộ lọc duy nhất. Tuy nhiên, giải pháp này giả định rằng thành phần trong đường đi vòng có thể được sửa đổi để bao gồm logic đi vòng được kiểm soát qua Bus Điều Khiển.
Sức mạnh của việc điều khiển các Đường vòng qua Bus Kiểm soát là nhiều Đường vòng có thể được kích hoạt hoặc hủy kích hoạt đồng thời với một lệnh duy nhất trên Bus Kiểm soát bằng cách sử dụng Kênh Xuất-Báo từ bảng điều khiển đến tất cả các Đường vòng.
Các Kênh Điểm-Đến-Điểm thường được sử dụng cho Thông Điệp Tài Liệu vì chúng đảm bảo rằng chỉ có một người tiêu thụ sẽ tiêu thụ mỗi thông điệp. Tuy nhiên, để kiểm tra, giám sát hoặc khắc phục sự cố, có thể hữu ích khi có khả năng kiểm tra tất cả các thông điệp đi qua kênh.
| Làm thế nào bạn kiểm tra các thông điệp mà di chuyển trên một kênh Điểm-đến-Điểm? |
Việc xem các thông điệp di chuyển qua một kênh có thể rất hữu ích, ví dụ, cho mục đích gỡ lỗi đơn giản hoặc để lưu trữ các thông điệp trong Kho Lưu Trữ Thông Điệp. Bạn không thể chỉ đơn giản thêm một trình lắng nghe khác vào Kênh Điểm-đến-Điểm, vì điều đó sẽ tiêu thụ các thông điệp ra khỏi kênh và ngăn chặn người nhận dự kiến có thể tiêu thụ thông điệp.
Ngoài ra, bạn có thể làm cho người gửi hoặc người nhận chịu trách nhiệm công bố thông điệp lên một kênh riêng biệt để kiểm tra. Tuy nhiên, điều này sẽ buộc chúng ta phải sửa đổi một tập hợp lớn các thành phần. Hơn nữa, nếu chúng ta đang xử lý các ứng dụng đã được đóng gói, chúng ta có thể thậm chí không thể sửa đổi ứng dụng.
Bạn cũng có thể xem xét việc thay đổi kênh thành Kênh Phát-Hợp. Điều này sẽ cho phép người nghe bổ sung kiểm tra các tin nhắn mà không làm gián đoạn dòng chảy của các tin nhắn. Tuy nhiên, Kênh Phát-Hợp thay đổi ngữ nghĩa của kênh. Ví dụ, nhiều Người Tiêu Thụ Cạnh Tranh có thể đang tiêu thụ các tin nhắn từ kênh, dựa vào thực tế rằng chỉ có một người tiêu thụ có thể nhận một tin nhắn cụ thể. Việc thay đổi kênh thành Kênh Phát-Hợp sẽ khiến mỗi người tiêu thụ nhận mỗi tin nhắn. Điều này có thể rất không mong muốn, chẳng hạn như nếu các tin nhắn đến đại diện cho các đơn đặt hàng mà bây giờ bị xử lý nhiều lần. Ngay cả khi chỉ có một người tiêu thụ lắng nghe trên kênh, việc sử dụng Kênh Phát-Hợp có thể kém hiệu quả hơn hoặc kém tin cậy hơn so với việc sử dụng Kênh Điểm-Đến-Điểm.
Nhiều hệ thống nhắn tin cung cấp một phương thức xem trước cho phép một thành phần kiểm tra các thông điệp bên trong Kênh Điểm-đến-Điểm mà không tiêu thụ thông điệp. Tuy nhiên, phương pháp này có một giới hạn quan trọng: Khi người tiêu thụ dự định tiêu thụ thông điệp, phương thức xem trước không còn khả năng nhìn thấy thông điệp đó nữa. Do đó, phương pháp này không cho phép chúng ta phân tích các thông điệp sau khi chúng đã được tiêu thụ.
Bạn có thể chèn một thành phần vào kênh (một dạng "bộ chặn") thực hiện bất kỳ kiểm tra cần thiết nào. Thành phần này sẽ tiêu thụ một thông điệp từ kênh đến, kiểm tra thông điệp và chuyển thông điệp không thay đổi tới kênh đầu ra. Tuy nhiên, loại kiểm tra thường phụ thuộc vào thông điệp từ nhiều kênh hơn một (ví dụ: để đo thời gian chạy của thông điệp), vì vậy chức năng này không thể được triển khai bởi một bộ lọc đơn lẻ trong một kênh duy nhất.
| Chèn một thiết bị nghe lén vào kênh, một danh sách người nhận đơn giản sẽ xuất bản mỗi tin nhắn đến kênh chính cũng như đến một kênh phụ.
|
Wire Tap (còn được gọi là tee) là một Danh sách Người nhận cố định với hai kênh đầu ra. Nó tiêu thụ các thông điệp từ kênh đầu vào và xuất bản thông điệp không bị sửa đổi đến cả hai kênh đầu ra. Để chèn Wire Tap vào một kênh, bạn cần tạo một kênh bổ sung và thay đổi người nhận đích để tiêu thụ kênh thứ hai. Vì quá trình phân tích được thực hiện bởi một thành phần riêng biệt, chúng ta có thể chèn một Wire Tap chung vào bất kỳ kênh nào mà không lo ngại về việc vô tình làm thay đổi hành vi của kênh chính. Điều này cải thiện khả năng tái sử dụng và giảm thiểu rủi ro về các hiệu ứng phụ không mong muốn khi thực hiện công cụ trên một giải pháp hiện có.
Có thể sẽ hữu ích nếu làm cho chương trình Wire Tap có thể lập trình qua Bus Điều Khiển để kênh thứ cấp (cái "tap") có thể được bật hoặc tắt. Bằng cách này, Wire Tap có thể được yêu cầu chỉ phát tán các tin nhắn đến kênh thứ cấp trong quá trình thử nghiệm hoặc gỡ lỗi.
Nhược điểm chính của Wire Tap là độ trễ bổ sung do việc tiêu thụ và tái xuất bản một tin nhắn. Nhiều bộ công cụ tích hợp tự động giải mã một tin nhắn ngay cả khi nó được xuất bản sang một kênh khác mà không có bất kỳ sửa đổi nào. Ngoài ra, tin nhắn mới sẽ nhận được một ID tin nhắn mới và các thời gian dấu thời gian mới khác với tin nhắn gốc. Các thao tác này có thể tạo thêm chi phí và khiến các cơ chế hiện có bị hỏng. Ví dụ, nếu dòng tin nhắn gốc sử dụng ID tin nhắn của tin nhắn gốc như là một Chỉ thị Tương quan, thì giải pháp sẽ bị hỏng vì ID tin nhắn của tin nhắn tái xuất bản là khác với ID tin nhắn của tin nhắn gốc. Đây là một trong những lý do mà nói chung không nên sử dụng ID tin nhắn như là một Chỉ thị Tương quan.
Vì Wire Tap xuất bản hai thông điệp riêng biệt, nên quan trọng không nên liên kết giữa các thông điệp này bằng ID thông điệp của chúng. Mặc dù kênh chính và kênh phụ nhận các thông điệp giống hệt nhau, hầu hết các hệ thống nhắn tin tự động gán một ID thông điệp mới cho mỗi thông điệp trong hệ thống. Điều này có nghĩa là thông điệp gốc và thông điệp "bị trùng" có ID thông điệp khác nhau.
Một Broker Tin nhắn hiện có có thể dễ dàng được mở rộng để hoạt động như một Thiết bị Ghi Âm vì tất cả các tin nhắn đã đi qua thành phần trung tâm này.
Một hạn chế quan trọng của Wire Tap là nó không thể thay đổi dòng tin nhắn đang chạy qua kênh. Nếu bạn cần có khả năng thao tác tin nhắn, hãy sử dụng Detour thay thế.
| Ví dụ: Môi giới cho vay Trong Chương 12, "Phần giữa: Ví dụ về Quản lý Hệ thống," chúng tôi nâng cao ví dụ về môi giới cho vay để bao gồm một Giám sát Kênh (Wire Tap) trên kênh yêu cầu đến cơ quan cấp tín dụng nhằm ghi lại tất cả các yêu cầu được gửi đến dịch vụ bên ngoài này (xem "Quản lý Hệ thống Môi giới Cho vay" trong Chương 12). |
| Ví dụ: Sử dụng nhiều điểm rờ để đo thời gian chạy của tin nhắn Một trong những sức mạnh của Wire Tap là chúng ta có thể kết hợp nhiều Wire Tap để gửi bản sao của các tin nhắn đến một thành phần trung tâm để phân tích. Thành phần đó có thể là Kho lưu trữ Tin nhắn hoặc một thành phần khác phân tích mối quan hệ giữa các tin nhắn, chẳng hạn như khoảng thời gian giữa hai tin nhắn liên quan (xem hình). Khi phân tích thời gian thực của tin nhắn, chúng ta nên dựa vào thời gian mà các tin nhắn phụ được gửi để đảm bảo rằng phép tính không bị lệch bởi thời gian di chuyển của các tin nhắn phụ. Sử dụng một bộ đầu dò để phân tích thời gian chạy của thông điệp
|
Một trong những lợi ích chính của hệ thống dựa trên thông điệp là sự kết nối lỏng lẻo giữa các thành phần tham gia; người gửi và người nhận thông điệp không có (hoặc ít) giả định về danh tính của nhau. Nếu một người nhận thông điệp lấy một thông điệp từ kênh thông điệp, họ thường không biết hoặc không quan tâm đến ứng dụng nào đã đưa thông điệp lên kênh. Thông điệp theo định nghĩa là tự chứa và không được gắn liền với một người gửi cụ thể. Đây là một trong những điểm mạnh kiến trúc của các hệ thống dựa trên thông điệp.
Tuy nhiên, tính chất này có thể khiến việc gỡ lỗi và phân tích các phụ thuộc trở nên rất khó khăn. Nếu chúng ta không chắc một thông điệp đi đâu, làm thế nào chúng ta có thể đánh giá tác động của một sự thay đổi trong định dạng thông điệp? Tương tự, nếu chúng ta không biết ứng dụng nào đã công bố một thông điệp cụ thể, thật khó để khắc phục một vấn đề với thông điệp đó.
| Làm thế nào để chúng ta có thể phân tích và gỡ lỗi hiệu quả dòng chảy của các thông điệp trong một hệ thống lỏng lẻo? |
Buss Điều Khiển giám sát trạng thái của từng thành phần xử lý tin nhắn, nhưng không quan tâm đến lộ trình của từng tin nhắn cụ thể. Bạn có thể điều chỉnh từng thành phần để công bố mã định danh duy nhất của mỗi tin nhắn đi qua nó tới Buss Điều Khiển. Thông tin này sau đó có thể được tập hợp vào một cơ sở dữ liệu chung, một Cửa Lưu Tin. Cách tiếp cận này yêu cầu một lượng hạ tầng đáng kể, bao gồm một kho dữ liệu riêng biệt. Ngoài ra, nếu một thành phần cần kiểm tra lịch sử của một tin nhắn, nó sẽ phải thực hiện một truy vấn trên một cơ sở dữ liệu trung tâm, với rủi ro biến cơ sở dữ liệu thành một nút thắt cổ chai.
Theo dõi luồng thông điệp qua một hệ thống không đơn giản như nó có vẻ. Có vẻ tự nhiên khi sử dụng ID thông điệp duy nhất liên kết với mỗi thông điệp. Tuy nhiên, khi một thành phần (ví dụ, Bộ định tuyến thông điệp) xử lý một thông điệp và phát hành nó vào kênh đầu ra, thông điệp kết quả sẽ nhận được một định danh thông điệp mới không liên kết với thông điệp mà thành phần đã tiêu thụ. Do đó, chúng ta cần xác định một khóa mới được sao chép từ thông điệp đến để thông điệp đi ra có thể được liên kết lại sau này. Điều này có thể hoạt động khá tốt nếu thành phần phát hành đúng một thông điệp cho mỗi thông điệp mà nó tiêu thụ. Tuy nhiên, điều này không đúng với nhiều thành phần, chẳng hạn như Danh sách người nhận, Bộ tập hợp hoặc Quản lý quy trình, thường phát hành nhiều thông điệp để đáp ứng một thông điệp đầu vào duy nhất.
Thay vì xác định con đường của từng tin nhắn bằng cách gán nhãn cho các tin nhắn, chính tin nhắn có thể thu thập một danh sách các thành phần mà nó đã đi qua. Nếu mỗi thành phần trong hệ thống nhắn tin mang một định danh duy nhất, mỗi thành phần có thể thêm định danh của nó vào từng tin nhắn mà nó xuất bản.
| Đính kèm Lịch sử Tin nhắn vào tin nhắn. Lịch sử Tin nhắn là một danh sách tất cả các ứng dụng hoặc thành phần mà tin nhắn đã đi qua kể từ khi nó được tạo ra.
|
Lịch sử Tin nhắn duy trì một danh sách tất cả các thành phần mà tin nhắn đã đi qua. Mỗi thành phần xử lý tin nhắn (bao gồm cả người khởi tạo) thêm một mục vào danh sách. Lịch sử Tin nhắn nên là một phần của tiêu đề tin nhắn vì nó chứa thông tin điều khiển cụ thể của hệ thống. Giữ thông tin này trong tiêu đề tách biệt nó khỏi thân tin nhắn chứa dữ liệu cụ thể của ứng dụng.
Không phải mọi thông điệp mà một thành phần phát hành đều là kết quả của một thông điệp đơn lẻ. Ví dụ, một Bộ tổng hợp phát hành một thông điệp duy nhất mang thông tin được thu thập từ nhiều thông điệp khác nhau, mỗi thông điệp đều có thể có lịch sử riêng của nó. Nếu chúng ta muốn đại diện cho kịch bản này trong Lịch sử thông điệp, chúng ta có hai lựa chọn. Nếu chúng ta muốn theo dõi toàn bộ lịch sử, chúng ta có thể cải tiến Lịch sử thông điệp để nó được lưu trữ dưới dạng cấu trúc cây phân cấp. Nhờ tính chất đệ quy của cấu trúc cây, chúng ta có thể lưu trữ nhiều lịch sử thông điệp dưới một nút duy nhất. Mặt khác, chúng ta có thể giữ một danh sách đơn giản và chỉ giữ lịch sử của một thông điệp đến duy nhất. Cách tiếp cận này có thể hoạt động tốt nếu một thông điệp đến duy nhất quan trọng hơn so với các thông điệp phụ trợ khác. Ví dụ, trong một kịch bản đấu giá, chúng ta có thể chọn chỉ phát tán lịch sử của thông điệp "thắng" mà thôi.
Lịch sử Tin nhắn sẽ hữu ích hơn nếu một chuỗi tin nhắn chảy qua một số bộ lọc khác nhau mà cùng thực hiện một chức năng hoặc quy trình kinh doanh cụ thể. Nếu việc quản lý con đường mà một tin nhắn đi qua là quan trọng, thì Quản lý Quy trình có thể hữu ích. Quản lý Quy trình tạo ra một phiên bản quy trình cho mỗi tin nhắn kích hoạt đến. Luồng tin nhắn qua các thành phần khác nhau giờ đây được quản lý một cách trung tâm, giảm bớt nhu cầu gán thẻ cho mỗi tin nhắn với lịch sử của nó.
| Ví dụ: Tránh Vòng Lặp Vô Hạn Việc trang bị cho một thông điệp với lịch sử của nó có một lợi ích quan trọng khác khi sử dụng Các Kênh Xuất Bản-Đăng Ký để truyền bá sự kiện. Giả sử chúng ta triển khai một hệ thống truyền bá thay đổi địa chỉ đến nhiều hệ thống thông qua Các Kênh Xuất Bản-Đăng Ký. Mỗi thay đổi địa chỉ sẽ được phát đi đến tất cả các hệ thống quan tâm để họ có thể cập nhật hồ sơ của mình. Cách tiếp cận này rất linh hoạt đối với việc thêm các hệ thống mới — hệ thống mới sẽ tự động nhận được thông điệp phát ra mà không cần bất kỳ thay đổi nào đối với hệ thống nhắn tin hiện tại. Giả sử hệ thống chăm sóc khách hàng là một trong những hệ thống lưu trữ địa chỉ trong cơ sở dữ liệu ứng dụng. Mỗi thay đổi đối với các trường cơ sở dữ liệu sẽ kích hoạt một thông điệp để thông báo cho tất cả các hệ thống về sự thay đổi. Theo bản chất của mô hình xuất bản-đăng ký, tất cả các hệ thống đăng ký vào kênh thay đổi địa chỉ sẽ nhận được sự kiện này. Tuy nhiên, chính hệ thống chăm sóc khách hàng cũng phải đăng ký vào kênh này để nhận được các cập nhật được thực hiện trong các hệ thống khác, ví dụ, thông qua một trang web tự phục vụ. Điều này có nghĩa là hệ thống chăm sóc khách hàng sẽ nhận được thông điệp mà nó vừa phát hành. Thông điệp nhận được này sẽ dẫn đến một cập nhật cơ sở dữ liệu, điều này sẽ lại kích hoạt một thông điệp thay đổi địa chỉ khác. Chúng ta có thể rơi vào một vòng lặp vô hạn của các thông điệp thay đổi địa chỉ. Để tránh vòng lặp vô hạn như vậy, các ứng dụng đăng ký có thể kiểm tra Lịch Sử Thông Điệp để xác định xem thông điệp có xuất phát từ chính hệ thống đó hay không và bỏ qua thông điệp đến nếu đúng như vậy. |
| Ví dụ: TIBCO ActiveEnterprise Nhiều bộ tích hợp EAI bao gồm hỗ trợ cho Lịch sử Tin nhắn. Ví dụ, tiêu đề tin nhắn của mỗi tin nhắn TIBCO ActiveEnterprise đều bao gồm một trường theo dõi duy trì danh sách tất cả các thành phần mà tin nhắn đã đi qua. Trong bối cảnh này, điều quan trọng cần lưu ý là một thành phần TIBCO ActiveEnterprise gán cho các tin nhắn đi ra cùng một ID tin nhắn như tin nhắn đã được tiêu thụ. Điều này giúp việc theo dõi các tin nhắn qua nhiều thành phần trở nên dễ dàng hơn, nhưng cũng có nghĩa là ID tin nhắn không phải là thuộc tính duy nhất trên toàn hệ thống, vì nhiều tin nhắn cá nhân chia sẻ cùng một ID. Ví dụ, khi thực hiện một Danh sách Người Nhận, TIBCO ActiveEnterprise chuyển ID của tin nhắn đã tiêu thụ cho mỗi tin nhắn đi ra. Ví dụ sau đây cho thấy nội dung của một tin nhắn đã qua nhiều thành phần khác nhau, bao gồm hai quy trình IntegrationManager, được đặt tên là OrderProcess và VerifyCustomerStub. [View full width] tw.training.customer.verify.response { RVMSG_INT 2 ^pfmt^ 10 RVMSG_INT 2 ^ver^ 30 RVMSG_INT 2 ^type^ 1 RVMSG_RVMSG 108 ^data^ { RVMSG_STRING 23 ^class^ "VerifyCustomerResponse" RVMSG_INT 4 ^idx^ 1 RVMSG_STRING 6 CUSTOMER_ID "12345" RVMSG_STRING 6 ORDER_ID "22222" RVMSG_INT 4 RESULT 0 } RVMSG_RVMSG 150 ^tracking^ { RVMSG_STRING 28 ^id^ "4OEaDEoiBIpcYk6qihzzwB5Uzzw" RVMSG_STRING 41 ^1^ |
Như lược sử thông điệp mô tả, nguyên tắc kiến trúc của việc liên kết lỏng lẻo cho phép linh hoạt trong giải pháp nhưng có thể khiến việc hiểu rõ hành vi động của giải pháp tích hợp trở nên khó khăn.
| Làm thế nào chúng ta có thể báo cáo thông tin về tin nhắn mà không làm ảnh hưởng đến tính chất lỏng lẻo và tạm thời của một hệ thống nhắn tin? |
Các thuộc tính mà làm cho việc nhắn tin trở nên mạnh mẽ cũng có thể khiến việc quản lý trở nên khó khăn. Nhắn tin không đồng bộ đảm bảo việc giao hàng nhưng không đảm bảo thời gian giao hàng. Đối với nhiều ứng dụng thực tiễn, thời gian phản hồi của một hệ thống có thể rất quan trọng. Ngoài ra, trong khi nhắn tin không đồng bộ xem xét từng thông điệp một cách riêng lẻ, thông tin trải dài qua nhiều thông điệp—ví dụ, số lượng thông điệp qua hệ thống trong một khoảng thời gian nhất định—có thể rất hữu ích.
Mô hình Lịch sử Tin nhắn minh họa sự hữu ích của việc có thể xác định "nguồn" của một tin nhắn. Từ dữ liệu này, chúng ta có thể rút ra những thông tin thú vị về thông lượng và thống kê thời gian chạy của tin nhắn. Điểm trừ duy nhất là thông tin được chứa trong mỗi tin nhắn riêng lẻ. Không có cách dễ dàng để báo cáo về thông tin này, vì nó phân tán qua nhiều tin nhắn. Hơn nữa, thời gian sống của một tin nhắn có thể rất ngắn. Khi tin nhắn đã được tiêu thụ, Lịch sử Tin nhắn có thể không còn khả dụng nữa.
Để thực hiện báo cáo có ý nghĩa, chúng tôi cần lưu trữ dữ liệu tin nhắn một cách bền vững và ở một vị trí trung tâm.
| Sử dụng một Kho Tin Nhắn để lưu trữ thông tin về mỗi tin nhắn ở một vị trí trung tâm.
|
Khi sử dụng một Kho Tin Nhắn, chúng ta có thể tận dụng tính chất bất đồng bộ của hạ tầng nhắn tin. Khi chúng ta gửi một tin nhắn đến một kênh, chúng ta gửi một bản sao của tin nhắn đến một kênh đặc biệt để được thu thập bởi Kho Tin Nhắn. Điều này có thể được thực hiện bởi chính thành phần đó, hoặc chúng ta có thể chèn một Wire Tap vào kênh. Chúng ta có thể xem kênh thứ cấp mang một bản sao của tin nhắn như một phần của Bus Điều Khiển. Gửi một tin nhắn thứ hai theo chế độ "gửi và quên" sẽ không làm chậm dòng chảy của các tin nhắn ứng dụng chính. Tuy nhiên, điều này sẽ tăng lưu lượng mạng. Đó là lý do tại sao chúng ta có thể không lưu trữ toàn bộ tin nhắn mà chỉ lưu một vài trường khóa cần thiết cho việc phân tích sau này, chẳng hạn như ID tin nhắn hoặc kênh mà tin nhắn được gửi kèm với dấu thời gian.
Bao nhiêu chi tiết để lưu trữ thực sự là một yếu tố quan trọng cần xem xét. Rõ ràng, càng nhiều dữ liệu chúng ta có về mỗi tin nhắn, khả năng báo cáo của chúng ta càng tốt hơn. Các yếu tố chống lại là lưu lượng mạng và khả năng lưu trữ của Kho tin nhắn. Ngay cả khi chúng ta lưu trữ tất cả dữ liệu tin nhắn, khả năng báo cáo của chúng ta vẫn có thể bị hạn chế. Các tin nhắn thường chia sẻ cùng một cấu trúc tiêu đề tin nhắn, nhưng nội dung tin nhắn được cấu trúc khác nhau cho mỗi loại tin nhắn và có thể khó truy cập bởi các ứng dụng bên ngoài (ví dụ, nội dung tin nhắn có thể chứa một đối tượng Java đã được tuần tự hóa). Điều này có thể làm cho việc báo cáo các yếu tố dữ liệu có trong nội dung tin nhắn trở nên khó khăn.
Vì dữ liệu bên trong thân tin nhắn có thể được định dạng khác nhau cho từng loại tin nhắn, chúng ta cần xem xét các tùy chọn lưu trữ khác nhau. Nếu chúng ta tạo một sơ đồ lưu trữ riêng biệt (ví dụ: bảng) để phù hợp với cấu trúc dữ liệu nội bộ của mỗi loại tin nhắn, chúng ta có thể áp dụng các chỉ mục và thực hiện các tìm kiếm phức tạp trên nội dung tin nhắn. Tuy nhiên, điều này giả định rằng chúng ta có một cấu trúc lưu trữ riêng biệt cho mỗi loại tin nhắn. Điều này có thể nhanh chóng trở thành gánh nặng bảo trì. Thay vào đó, chúng ta có thể lưu trữ dữ liệu tin nhắn dưới dạng dữ liệu phi cấu trúc trong định dạng XML trong một trường ký tự dài. Điều này cho phép chúng ta sử dụng một sơ đồ lưu trữ tổng quát. Chúng ta vẫn có thể truy vấn theo các trường tiêu đề nhưng sẽ không thể báo cáo theo các trường trong thân tin nhắn. Tuy nhiên, một khi chúng ta xác định được một tin nhắn cụ thể, chúng ta có thể tái tạo nội dung tin nhắn dựa trên tài liệu XML được lưu trữ trong Lưu trữ Tin nhắn. Ngoài ra, chúng ta có thể sử dụng một kho lưu trữ XML để lưu trữ các tin nhắn. Các loại kho lưu trữ này lập chỉ mục các tài liệu XML để truy xuất và phân tích sau này.
Kho lưu trữ tin nhắn có thể trở nên rất lớn, vì vậy có khả năng chúng ta sẽ cần giới thiệu một cơ chế xóa. Cơ chế này có thể chuyển các nhật ký tin nhắn cũ vào một cơ sở dữ liệu sao lưu hoặc xóa chúng hoàn toàn.
| Ví dụ: Công cụ EAI thương mại Một số công cụ tích hợp doanh nghiệp cung cấp một Kho Tin nhắn. Ví dụ, MSMQ cho phép hàng đợi tự động lưu trữ các tin nhắn đã gửi hoặc nhận trong một Hàng đợi Nhật ký. Microsoft BizTalk tùy chọn lưu trữ tất cả các tài liệu (tin nhắn) trong cơ sở dữ liệu SQL Server để phân tích sau này. |
Một cặp Wire Taps có thể được sử dụng để theo dõi các thông điệp chảy qua một thành phần, nhưng cách tiếp cận này giả định rằng thành phần xuất bản thông điệp tới một kênh đầu ra cố định. Tuy nhiên, nhiều thành phần kiểu dịch vụ xuất bản thông điệp phản hồi tới kênh được chỉ định bởi Địa Chỉ Trả về bao gồm trong thông điệp yêu cầu.
| Làm thế nào bạn có thể theo dõi các tin nhắn trên một dịch vụ gửi tin nhắn phản hồi đến Địa chỉ Trả lại được chỉ định bởi người yêu cầu? |
Để theo dõi luồng tin nhắn trong một dịch vụ, chúng ta cần ghi lại cả tin nhắn yêu cầu và tin nhắn phản hồi. Việc chặn một tin nhắn yêu cầu bằng cách sử dụng Wire Tap thì dễ dàng. Việc chặn tin nhắn phản hồi thì khó khăn hơn vì dịch vụ công bố tin nhắn phản hồi đến các kênh khác nhau dựa trên Địa Chỉ Trả Lại mà người yêu cầu ưa chuộng.
Hỗ trợ địa chỉ trả về là cần thiết cho hầu hết các dịch vụ Yêu cầu-Trả lời để người yêu cầu có thể chỉ định kênh mà tin nhắn trả lời nên được gửi đến. Việc thay đổi dịch vụ để gửi tin nhắn trả lời đến một kênh cố định sẽ khiến cho mỗi người yêu cầu khó khăn trong việc trích xuất các tin nhắn trả lời đúng. Một số hệ thống nhắn tin cho phép người tiêu dùng xem trước các tin nhắn cụ thể trong một hàng đợi trả lời duy nhất, nhưng cách tiếp cận đó là tùy thuộc vào cách triển khai và không hoạt động trong những trường hợp mà tin nhắn trả lời không quay trở lại người yêu cầu mà đến một bên thứ ba.
Như đã thảo luận trong Wire Tap, việc điều chỉnh thành phần để kiểm tra thông điệp không phải lúc nào cũng khả thi hoặc thực tiễn. Nếu chúng ta đang xử lý một ứng dụng đóng gói, chúng ta có thể không thể thay đổi mã ứng dụng và có thể phải triển khai một giải pháp bên ngoài ứng dụng. Tương tự, chúng ta có thể không muốn yêu cầu mỗi ứng dụng phải triển khai logic kiểm tra thông điệp, đặc biệt là vì tính chất của logic có thể thay đổi tùy thuộc vào việc chúng ta hoạt động ở chế độ kiểm tra hay chế độ sản xuất. Giữ các chức năng kiểm tra trong một thành phần riêng biệt, tự chứa cải thiện tính linh hoạt, khả năng tái sử dụng và khả năng kiểm thử.
| Sử dụng một Smart Proxy để lưu trữ Địa chỉ Trả về được cung cấp bởi người yêu cầu ban đầu và thay thế nó bằng địa chỉ của Smart Proxy. Khi dịch vụ gửi tin nhắn phản hồi, hãy định tuyến nó tới Địa chỉ Trả về ban đầu.
|
Smart Proxy chặn các tin nhắn được gửi trên kênh yêu cầu tới dịch vụ Yêu cầu-Phản hồi. Đối với mỗi tin nhắn đến, Smart Proxy lưu trữ Địa chỉ Trả về được chỉ định bởi người gửi gốc. Sau đó, nó thay thế Địa chỉ Trả về trong tin nhắn bằng kênh phản hồi mà Smart Proxy đang lắng nghe. Khi một tin nhắn phản hồi đến kênh đó, Smart Proxy thực hiện bất kỳ chức năng phân tích nào mong muốn, truy xuất Địa chỉ Trả về đã lưu và chuyển tiếp tin nhắn phản hồi chưa được sửa đổi tới kênh phản hồi gốc bằng cách sử dụng một Bộ định tuyến Tin nhắn.
Bộ Proxy Thông Minh cũng hữu ích trong các trường hợp mà một dịch vụ bên ngoài không hỗ trợ Địa Chỉ Trả lại mà thay vào đó trả lời qua một kênh trả lời cố định. Chúng ta có thể ủy quyền cho một dịch vụ như vậy bằng một Bộ Proxy Thông Minh để cung cấp hỗ trợ cho Địa Chỉ Trả lại. Trong trường hợp này, Bộ Proxy Thông Minh không thực hiện bất kỳ chức năng phân tích nào mà chỉ đơn giản chuyển tiếp tin nhắn phản hồi đến kênh chính xác.
Smart Proxy cần lưu trữ Địa chỉ Trả về được cung cấp bởi người yêu cầu ban đầu theo cách mà nó có thể liên kết các tin nhắn trả lời đến và Địa chỉ Trả về và chuyển tiếp tin nhắn trả lời đến kênh chính xác. Smart Proxy có thể lưu trữ dữ liệu này ở hai nơi:
Bên trong thông điệp
Inside the Smart Proxy: Bên trong Proxy Thông Minh
Để lưu trữ Địa chỉ Trả về bên trong tin nhắn, Smart Proxy có thể thêm một trường tin nhắn mới cùng với Địa chỉ Trả về vào tin nhắn. Dịch vụ Yêu cầu-Trả lời cần phải sao chép trường này vào tin nhắn trả lời. Tất cả những gì Smart Proxy cần làm là trích xuất trường tin nhắn đặc biệt từ tin nhắn trả lời, xóa trường đó khỏi tin nhắn và chuyển tiếp tin nhắn đến kênh được chỉ định bởi trường đó. Giải pháp này giữ cho Smart Proxy đơn giản, nhưng yêu cầu sự hợp tác từ dịch vụ Yêu cầu-Trả lời. Nếu dịch vụ Yêu cầu-Trả lời là một thành phần không thể sửa đổi, tùy chọn này có thể không khả dụng.
Ngoài ra, Smart Proxy có thể lưu trữ Địa Chỉ Trả về trong kho lưu trữ chuyên dụng, chẳng hạn như trong một cấu trúc bộ nhớ hoặc cơ sở dữ liệu quan hệ. Bởi vì mục đích của Smart Proxy là theo dõi các thông điệp giữa thông điệp yêu cầu và thông điệp trả về, Smart Proxy thường phải lưu trữ dữ liệu từ thông điệp yêu cầu để tương quan nó với thông điệp trả về, để cả hai thông điệp có thể được phân tích cùng nhau. Cách tiếp cận này yêu cầu Smart Proxy có khả năng tương quan thông điệp trả về với thông điệp phản hồi. Hầu hết các dịch vụ Yêu cầu-Trả về hỗ trợ một Định danh Tương quan mà dịch vụ sao chép từ thông điệp yêu cầu sang thông điệp trả về. Nếu Smart Proxy không thể sửa đổi định dạng thông điệp gốc, nó có thể sử dụng (hoặc lạm dụng) trường này để tương quan các thông điệp yêu cầu và trả về.
Tuy nhiên, tốt hơn cho Smart Proxy là tự xây dựng mã nhận diện tương quan của riêng mình, vì không phải tất cả các yêu cầu đều sẽ chỉ định mã nhận diện tương quan và cũng vì mã nhận diện tương quan được cung cấp chỉ cần phải duy nhất trong các yêu cầu được thực hiện bởi một yêu cầu duy nhất và có thể không duy nhất giữa nhiều yêu cầu khác nhau. Vì hàng đợi phản hồi từ dịch vụ đến Smart Proxy hiện đang mang thông điệp từ nhiều yêu cầu, việc sử dụng mã nhận diện tương quan gốc là không đáng tin cậy. Do đó, Smart Proxy lưu trữ mã nhận diện tương quan gốc cùng với địa chỉ trả gốc và thay thế mã nhận diện tương quan gốc bằng mã nhận diện tương quan của riêng mình để có thể truy xuất mã nhận diện tương quan gốc và địa chỉ trả khi tin nhắn phản hồi đến.
Một số dịch vụ sử dụng ID tin nhắn của tin nhắn yêu cầu làm Mã danh tính Tương quan cho tin nhắn trả lời. Điều này gây ra một vấn đề khác. Dịch vụ sẽ sao chép ID tin nhắn của tin nhắn yêu cầu mà nó nhận được từ Smart Proxy vào tin nhắn trả lời gửi cho Smart Proxy. Smart Proxy cần thay thế Mã danh tính Tương quan này trong tin nhắn trả lời bằng ID tin nhắn của tin nhắn yêu cầu ban đầu để người yêu cầu có thể liên kết đúng giữa các tin nhắn yêu cầu và trả lời. Hình minh họa ở trang tiếp theo sẽ mô tả quá trình này.
Điều quan trọng cần lưu ý là tất cả bốn tin nhắn đều có ID tin nhắn riêng biệt mặc dù chúng liên quan đến luồng của một "tin nhắn" logic duy nhất.
Lưu trữ và Thay thế Định danh Tương quan và Địa chỉ Trả về

| Ví dụ: Proxy Thông Minh Đơn Giản trong MSMQ và C# Việc triển khai một Proxy Thông Minh không phức tạp như nó nghe có vẻ. Đoạn mã sau đây thực hiện một kịch bản giải pháp bao gồm hai yêu cầu, một Proxy Thông Minh và một dịch vụ đơn giản. Proxy Thông Minh sẽ truyền thời gian xử lý tin nhắn tới bus điều khiển để hiển thị trên bảng điều khiển. Chúng tôi muốn cho phép các yêu cầu có thể tương quan bằng cách sử dụng biệt danh tin nhắn hoặc thuộc tính AppSpecific số mà đối tượng Tin nhắn cung cấp. Ví dụ về Proxy Thông Minh Đơn Giản
Để thuận tiện cho việc lập trình của chúng tôi, chúng tôi định nghĩa một lớp cơ sở MessageConsumer, lớp này đóng gói mã cần thiết để tạo ra một trình tiêu thụ tin nhắn dựa trên sự kiện. Các lớp kế thừa có thể dễ dàng ghi đè phương thức ảo ProcessMessage để thực hiện bất kỳ xử lý tin nhắn cần thiết nào, và họ không phải lo lắng về cấu hình của hàng đợi tin nhắn hoặc xử lý dựa trên sự kiện. Việc tách mã này thành một lớp cơ sở chung giúp dễ dàng tạo ra các khách hàng thử nghiệm và một dịch vụ Request-Reply giả lập chỉ với vài dòng mã. MessageConsumer[View full width]public class MessageConsumer { protected MessageQueue inputQueue; public MessageConsumer (MessageQueue inputQueue) { this.inputQueue = inputQueue; SetupQueue(this.inputQueue); Console.WriteLine(this.GetType().Name + ": Processing Bắt đầu với lớp MessageConsumer, chúng ta có thể tạo ra một Smart Proxy. Một Smart Proxy chứa hai MessageConsumers, một để xử lý các tin nhắn yêu cầu từ phía người yêu cầu (SmartProxyRequestConsumer) và một để xử lý các tin nhắn phản hồi được trả về bởi dịch vụ Yêu cầu-Phản hồi (SmartProxyReplyConsumer). Smart Proxy cũng định nghĩa một Hashtable để lưu trữ dữ liệu tin nhắn giữa các tin nhắn yêu cầu và phản hồi. SmartProxy[View full width]public class SmartProxyBase { protected SmartProxyRequestConsumer requestConsumer; protected SmartProxyReplyConsumer replyConsumer; protected Hashtable messageData; public SmartProxyBase(MessageQueue inputQueue, MessageQueue serviceRequestQueue, MessageQueue serviceReplyQueue) { messageData = Hashtable.Synchronized(new Hashtable()); requestConsumer = new SmartProxyRequestConsumer SmartProxyRequestConsumer tương đối đơn giản. Nó lưu trữ thông tin liên quan từ tin nhắn yêu cầu (ID tin nhắn, Địa chỉ Trả lại, thuộc tính Riêng Ứng dụng và thời gian hiện tại) trong bảng băm, được lập chỉ mục theo ID tin nhắn của tin nhắn yêu cầu mới gửi đến dịch vụ thực. Dịch vụ yêu cầu-đáp ứng hỗ trợ Nhận diện Tương quan bằng cách sao chép ID tin nhắn này vào trường CorrelationID của tin nhắn phản hồi dịch vụ. Điều này cho phép Smart Proxy truy xuất dữ liệu tin nhắn đã lưu khi tin nhắn phản hồi đến. SmartProxyRequestConsumer cũng thay thế Địa chỉ Trả lại với hàng đợi mà Smart Proxy lắng nghe cho các tin nhắn hồi đáp. Chúng tôi đã bao gồm một phương thức ảo AnalyzeMessage trong lớp này để các lớp con có thể thực hiện bất kỳ phân tích nào mà họ mong muốn. SmartProxyRequestConsumer[View full width]public class SmartProxyRequestConsumer : MessageConsumer { protected Hashtable messageData; protected MessageQueue serviceRequestQueue; protected MessageQueue serviceReplyQueue; public SmartProxyRequestConsumer(MessageQueue requestQueue, MessageQueue Người tiêu dùng Smart-ProxyReply lắng nghe trên kênh phản hồi dịch vụ. Phương thức ProcessMessage của lớp này lấy dữ liệu tin nhắn cho tin nhắn yêu cầu liên quan được lưu trữ bởi Smart-ProxyRequestConsumer và gọi phương thức mẫu AnalyzeMessage. Sau đó, nó sao chép các thuộc tính CorrelationID và AppSpecific vào tin nhắn phản hồi mới và chuyển tiếp nó đến Địa chỉ Trả về được chỉ định trong tin nhắn yêu cầu ban đầu. SmartProxyReplyConsumer[View full width]public class SmartProxyReplyConsumer : MessageConsumer { protected Hashtable messageData; public SmartProxyReplyConsumer(MessageQueue replyQueue, Hashtable messageData) : base Để thu thập các chỉ số và gửi chúng đến bus điều khiển, chúng tôi đã tạo lớp con từ cả hai lớp SmartProxy và SmartProxyReplyConsumer. Lớp MetricsSmartProxy mới khởi tạo SmartProxyReplyConsumerMetrics như là lớp tiêu thụ các tin nhắn phản hồi. Lớp này bao gồm một triển khai đơn giản của phương thức AnalyzeMessage, tính toán thời gian chạy của tin nhắn giữa yêu cầu và phản hồi, và gửi dữ liệu này cùng với số lượng tin nhắn còn lại đến hàng đợi Bus Điều Khiển. Chúng tôi có thể dễ dàng nâng cấp phương thức này để thực hiện các phép tính phức tạp hơn. Hàng đợi Bus Điều Khiển được kết nối với một trình ghi tệp đơn giản, ghi lại mỗi tin nhắn đến vào một tệp. MetricsSmartProxy[View full width]public class MetricsSmartProxy : SmartProxyBase { public MetricsSmartProxy(MessageQueue inputQueue, MessageQueue serviceRequestQueue, MessageQueue serviceReplyQueue, MessageQueue controlBus) : base (inputQueue, serviceRequestQueue, SmartProxyReplyConsumerMetrics[View full width]public class SmartProxyReplyConsumerMetrics : SmartProxyReplyConsumer { MessageQueue controlBus; public SmartProxyReplyConsumerMetrics(MessageQueue replyQueue, Hashtable messageData, MessageQueue controlBus) : base(replyQueue, messageData) { this.controlBus = controlBus; } protected override void AnalyzeMessage(MessageData data, Biểu đồ lớp dưới đây cho thấy mối quan hệ giữa các lớp cá nhân: Biểu Đồ Lớp Ví Dụ Proxy Thông Minh
Để kiểm tra proxy, chúng tôi đã tạo một dịch vụ gửi-nhận giả mà chỉ chờ đợi trong khoảng thời gian ngẫu nhiên từ 0 đến 200 ms. Chúng tôi cung cấp Smart Proxy từ hai yêu cầu, mỗi yêu cầu xuất bản 30 tin nhắn trong khoảng thời gian 100 ms. Chúng tôi ghi lại các tin nhắn trên hàng đợi Control Bus vào một tệp nhật ký. Để trình diễn, chúng tôi đã tải tệp control bus kết quả vào một bảng tính Microsoft Excel và tạo một biểu đồ đẹp mắt. “Thống kê Thời gian Phản hồi Được Thu thập bởi Proxy Thông minh và Được Trực quan Hóa bởi Bảng Điều khiển Kiểm soát”
Chúng ta có thể thấy rằng kích thước hàng đợi và thời gian phản hồi tăng đều cho đến khi có 13 tin nhắn được xếp hàng. Vào thời điểm đó, những người yêu cầu ngừng gửi tin nhắn mới, vì vậy kích thước hàng đợi giảm đều. Thời gian phản hồi cũng giảm, nhưng vẫn dao động xung quanh 1 giây vì các tin nhắn hiện đang được xử lý đã nằm trong hàng đợi yêu cầu trong thời gian đó. |
Bus Kiểm Soát mô tả một số phương pháp để giám sát sức khỏe của hệ thống xử lý tin nhắn. Mỗi thành phần trong hệ thống có thể công bố các tin nhắn nhịp tim định kỳ đến Bus Kiểm Soát để giữ cho cơ chế giám sát được thông báo rằng thành phần đó vẫn đang hoạt động. Các tin nhắn nhịp tim có thể chứa các thống kê quan trọng của thành phần, chẳng hạn như số lượng tin nhắn đã được xử lý, thời gian trung bình cần thiết để xử lý một tin nhắn, hoặc tỷ lệ phần trăm sử dụng CPU trên máy.
| Điều gì sẽ xảy ra nếu một thành phần đang xử lý tin nhắn một cách tích cực nhưng lại làm rối tung các tin nhắn ra ngoài do một lỗi nội bộ? |
Một cơ chế nhịp tim đơn giản sẽ không phát hiện ra điều kiện lỗi này vì nó chỉ hoạt động ở mức thành phần và không nhận thức được định dạng thông điệp ứng dụng.
| Tiêm một tin nhắn thử nghiệm vào dòng tin nhắn để xác nhận tình trạng của các thành phần xử lý tin nhắn.
|
Mẫu Thông báo Kiểm tra dựa vào các thành phần sau:
Bộ tạo dữ liệu kiểm tra tạo ra các thông điệp được gửi đến thành phần để thử nghiệm. Dữ liệu kiểm tra có thể là hằng số, được điều khiển bởi một tệp dữ liệu kiểm tra, hoặc được tạo ra ngẫu nhiên.
Bộ tiêm tin nhắn thử nghiệm chèn dữ liệu thử nghiệm vào dòng dữ liệu tin nhắn thường được gửi đến thành phần. Vai trò chính của bộ tiêm là đánh dấu các tin nhắn để phân biệt tin nhắn ứng dụng thực tế với tin nhắn thử nghiệm. Điều này có thể được thực hiện bằng cách chèn một trường tiêu đề đặc biệt. Nếu chúng ta không có quyền kiểm soát cấu trúc tin nhắn, chúng ta có thể cố gắng sử dụng các giá trị đặc biệt để chỉ định tin nhắn thử nghiệm (ví dụ: OrderID = 999999). Điều này thay đổi ngữ nghĩa của dữ liệu ứng dụng bằng cách sử dụng cùng một trường để đại diện cho dữ liệu ứng dụng (số đơn hàng thực tế) và thông tin điều khiển (đây là một tin nhắn thử nghiệm). Do đó, cách tiếp cận này chỉ nên được sử dụng như một phương án cuối cùng.
Bộ tách Thông điệp Kiểm tra trích xuất kết quả của các thông điệp kiểm tra từ luồng đầu ra. Điều này thường có thể được thực hiện bằng cách sử dụng Bộ định tuyến Dựa trên Nội dung.
Bộ xác minh dữ liệu kiểm tra so sánh kết quả thực tế với kết quả mong đợi và đánh dấu một ngoại lệ nếu phát hiện ra sự khác biệt. Tùy thuộc vào tính chất của dữ liệu kiểm tra, bộ xác minh có thể cần quyền truy cập vào dữ liệu kiểm tra gốc.
Một Bộ Phân Tách Thông Điệp Kiểm Tra rõ ràng có thể không cần thiết nếu thành phần đang được kiểm tra hỗ trợ Địa Chỉ Trả Lại. Trong trường hợp này, Trình Tạo Dữ Liệu Kiểm Tra có thể bao gồm một kênh kiểm tra đặc biệt làm Địa Chỉ Trả Lại để các thông điệp kiểm tra không được truyền qua phần còn lại của hệ thống. Thực tế, Địa Chỉ Trả Lại hoạt động như một thẻ phân biệt các thông điệp kiểm tra với các thông điệp ứng dụng.
Tin nhắn Kiểm tra được coi là một cơ chế giám sát chủ động. Không giống như các cơ chế thụ động, các cơ chế chủ động không phụ thuộc vào thông tin được tạo ra bởi các thành phần (ví dụ: tệp nhật ký hoặc tin nhắn nhịp tim) mà sẽ chủ động kiểm tra thành phần. Lợi thế là giám sát chủ động thường đạt được mức độ kiểm tra sâu hơn, vì dữ liệu được xử lý thông qua cùng một bước xử lý như các tin nhắn ứng dụng. Nó cũng hoạt động tốt với các thành phần không được thiết kế để hỗ trợ giám sát thụ động.
Một nhược điểm có thể của việc giám sát chủ động là gánh nặng bổ sung đặt lên đơn vị xử lý. Chúng ta cần tìm ra sự cân bằng giữa tần suất kiểm tra và việc giảm thiểu tác động đến hiệu suất. Giám sát chủ động cũng có thể phát sinh chi phí nếu chúng ta bị tính phí cho việc sử dụng một thành phần theo hình thức trả tiền theo số lần sử dụng. Đây là trường hợp của nhiều thành phần bên ngoài; ví dụ, nếu chúng ta yêu cầu báo cáo tín dụng cho khách hàng của mình từ một cơ quan đánh giá tín dụng bên ngoài.
Giám sát chủ động không hoạt động với tất cả các thành phần. Các thành phần có trạng thái có thể không phân biệt được dữ liệu thử nghiệm với dữ liệu thực và có thể tạo ra các mục cơ sở dữ liệu cho dữ liệu thử nghiệm. Chúng ta có thể không muốn có các đơn hàng thử nghiệm được bao gồm trong báo cáo doanh thu hàng năm của mình!
| Ví dụ: Môi giới vay vốn: Kiểm tra Cơ quan Xếp hạng Tín dụng Trong Chương 12, "Chương giữa: Ví dụ về Quản lý Hệ thống," chúng tôi sử dụng một Thông điệp Kiểm tra để theo dõi tích cực văn phòng tín dụng bên ngoài. |
Khi chúng tôi làm việc với ví dụ yêu cầu-phản hồi JMS (xem Chương 6, "Giữa chừng: Gửi tin nhắn đơn giản"), chúng tôi đã gặp phải một vấn đề đơn giản nhưng thú vị. Ví dụ này bao gồm một người yêu cầu gửi một tin nhắn đến một người phản hồi và chờ đợi phản hồi. Ví dụ sử dụng hai Kênh Điểm-đến-Điểm, RequestQueue và ReplyQueue (xem hình).

Chúng tôi đã khởi động chương trình trả lời trước, sau đó là chương trình yêu cầu. Rồi, một điều rất kỳ lạ đã xảy ra. Cửa sổ console của chương trình yêu cầu tuyên bố rằng nó đã nhận được phản hồi trước khi chương trình trả lời thừa nhận đã nhận yêu cầu. Có phải là sự chậm trễ trong đầu ra console? Thiếu ý tưởng hay, chúng tôi quyết định tắt chương trình trả lời, và chạy lại chương trình yêu cầu. Thật kỳ lạ, chúng tôi vẫn nhận được phản hồi cho yêu cầu của mình! Phép thuật? Không, chỉ là một tác dụng phụ của việc nhắn tin liên tục. Một thông điệp thừa đã có mặt trên ReplyQueue, có lẽ là do một sự cố trước đó. Mỗi khi chúng tôi khởi động chương trình yêu cầu, nó đã đặt một thông điệp mới trên RequestQueue và sau đó ngay lập tức lấy lại thông điệp phản hồi thừa đang nằm trên ReplyQueue. Chúng tôi đã không nhận ra rằng thông điệp này không phải là phản hồi cho yêu cầu mà chương trình yêu cầu vừa mới thực hiện! Khi chương trình trả lời nhận được thông điệp yêu cầu mới, nó đã đặt một thông điệp phản hồi mới lên ReplyQueue để “phép thuật” lặp lại trong thử nghiệm tiếp theo. Thật đáng ngạc nhiên (hoặc cực kỳ frustrating) về cách mà nhắn tin liên tục, bất đồng bộ có thể chơi đùa với bạn ngay cả trong những kịch bản đơn giản nhất!
| Làm thế nào bạn có thể giữ cho các tin nhắn còn lại trong một kênh không làm gián đoạn các bài kiểm tra hoặc các hệ thống đang chạy? |
Các Kênh Tin Nhắn được thiết kế để gửi tin nhắn một cách đáng tin cậy ngay cả khi thành phần nhận không khả dụng. Để làm được điều này, kênh phải duy trì tin nhắn trên đường đi. Tính năng hữu ích này có thể gây ra những tình huống khó hiểu trong quá trình kiểm tra hoặc nếu một trong các thành phần hoạt động sai (và không sử dụng việc tiêu thụ và sản xuất tin nhắn giao dịch). Chúng ta có thể nhanh chóng gặp phải những tin nhắn dư thừa mắc kẹt trên các kênh, như đã mô tả trước đó. Những tin nhắn này khiến việc truyền dữ liệu kiểm tra vào hệ thống trở nên không thể cho đến khi các tin nhắn đang chờ được tiêu thụ. Nếu các tin nhắn đang chờ là đơn hàng trị giá vài triệu đô la, thì đây là một điều tốt. Nhưng nếu chúng ta đang kiểm tra hoặc gỡ lỗi một hệ thống và có một kênh đầy tin nhắn truy vấn hoặc tin nhắn phản hồi, điều này có thể gây ra khá nhiều phiền phức cho chúng ta.
Trong ví dụ đơn giản của chúng tôi, một số khó khăn trong việc gỡ lỗi có thể đã được giảm bớt nếu chúng tôi sử dụng một Bộ Nhận Diện Tương Quan. Bằng cách sử dụng bộ nhận diện này, người yêu cầu sẽ nhận ra rằng thông điệp đến không phải là phản hồi cho yêu cầu mà họ vừa gửi. Họ có thể loại bỏ thông điệp phản hồi cũ hoặc chuyển nó đến Kênh Thông Điệp Không Hợp Lệ, điều này sẽ hiệu quả trong việc loại bỏ thông điệp "bị kẹt". Trong các tình huống khác, việc phát hiện thông điệp trùng lặp hoặc không mong muốn không dễ dàng như vậy. Ví dụ, nếu một thông điệp cụ thể bị sai cấu trúc và gây ra lỗi cho người nhận thông điệp, người nhận sẽ không thể khởi động lại cho đến khi thông điệp lỗi được loại bỏ, bởi vì họ sẽ gặp lỗi ngay lập tức một lần nữa. Tất nhiên, ví dụ này yêu cầu phải sửa chữa khuyết điểm trong người nhận (không thông điệp bị sai cấu trúc nào nên gây ra lỗi cho thành phần), nhưng việc loại bỏ thông điệp có thể giúp hệ thống hoạt động nhanh chóng cho đến khi khuyết điểm được sửa chữa.
Một cách khác để tránh các tin nhắn dư thừa trong các kênh là sử dụng các kênh tạm thời (ví dụ: JMS cung cấp phương thức createTemporaryQueue cho mục đích này). Những kênh này được thiết kế cho các ứng dụng yêu cầu - phản hồi và sẽ mất tất cả các tin nhắn khi ứng dụng đóng kết nối với hệ thống nhắn tin. Nhưng một lần nữa, phương pháp này chỉ giới hạn trong một ví dụ yêu cầu - phản hồi đơn giản và không bảo vệ khỏi các tin nhắn khác còn lại trên các kênh khác cần được lưu trữ.
Có thể dễ dàng giả định rằng quản lý giao dịch có thể loại bỏ tình huống tin nhắn dư thừa vì việc tiêu thụ tin nhắn, xử lý tin nhắn và phát hành tin nhắn được thực hiện trong một giao dịch duy nhất. Vì vậy, nếu một thành phần bị hủy giữa chừng trong quá trình xử lý một tin nhắn, tin nhắn đó sẽ không được coi là đã tiêu thụ. Tương tự, một tin nhắn phản hồi sẽ không được phát hành cho đến khi thành phần đó báo hiệu cam kết cuối cùng để gửi tin nhắn. Tuy nhiên, chúng ta cần nhớ rằng các giao dịch không bảo vệ chúng ta khỏi lỗi lập trình. Trong ví dụ yêu cầu-phản hồi đơn giản của chúng ta, một lỗi lập trình có thể đã khiến người yêu cầu không đọc được phản hồi từ kênh ReplyQueue. Kết quả là, bất chấp khả năng giao dịch, một tin nhắn bị kẹt trên kênh đó, gây ra các triệu chứng đã được mô tả trước đó.
| Sử dụng Công cụ Xóa Kênh để loại bỏ các tin nhắn không mong muốn khỏi một kênh.
|
Một trình xóa kênh cơ bản chỉ đơn giản là xóa tất cả các tin nhắn khỏi một kênh. Điều này có thể đủ cho các kịch bản thử nghiệm nơi chúng ta muốn đặt lại hệ thống về trạng thái nhất quán. Nếu chúng ta đang gỡ lỗi một hệ thống sản xuất, chúng ta có thể cần xóa một tin nhắn cá nhân hoặc một tập hợp các tin nhắn dựa trên các tiêu chí cụ thể, chẳng hạn như ID tin nhắn hoặc các giá trị của các trường tin nhắn cụ thể.
Trong nhiều trường hợp, việc để Bộ lọc Kênh đơn giản xóa tin nhắn khỏi kênh và loại bỏ nó là hoàn toàn hợp lý. Trong những trường hợp khác, chúng tôi có thể cần Bộ lọc Kênh lưu trữ các tin nhắn đã bị xóa để kiểm tra hoặc phát lại sau này. Điều này hữu ích nếu các tin nhắn trong một kênh gây ra sự cố hệ thống, vì vậy chúng tôi cần loại bỏ chúng để tiếp tục hoạt động. Tuy nhiên, một khi các vấn đề đã được khắc phục, chúng tôi muốn tái tiêm các tin nhắn để hệ thống không bị mất nội dung của tin nhắn. Điều này cũng có thể bao gồm yêu cầu chỉnh sửa nội dung tin nhắn trước khi tái tiêm tin nhắn. Loại chức năng này kết hợp một số tính năng của Kho Tin Nhắn và Bộ lọc Kênh.
| Ví dụ: Kênh Purger trong JMS Ví dụ này cho thấy một Bộ Xóa Kênh đơn giản được triển khai bằng Java. Ví dụ này chỉ đơn giản là xóa tất cả tin nhắn trên một kênh. Lớp ChannelPurger tham chiếu đến hai lớp bên ngoài mà mã nguồn của chúng không được hiển thị ở đây.
[View full width] import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.Queue; public class ChannelPurger extends JmsEndpoint { public static void main(String[] args) { if (args.length != 1) { System.out.println("Usage: java ChannelPurger |
Chương này sử dụng một ví dụ phức tạp hơn để minh hoạ cách mà các mẫu quản lý hệ thống được giới thiệu trong phần này có thể được sử dụng để giám sát và kiểm soát một giải pháp nhắn tin. Ví dụ này phát triển từ việc triển khai C# và MSMQ của ví dụ môi giới cho vay từ Chương 9, "Giữa chừng: Nhắn tin Thành phần" (xem "Triển khai Bất đồng bộ với MSMQ"). Chúng tôi bổ sung mà không thay đổi giải pháp ví dụ gốc, vì vậy không quan trọng nếu bạn đã xem qua toàn bộ mã nguồn của ví dụ gốc. Cũng giống như trong triển khai gốc, mục đích của ví dụ này không phải là để giải thích việc sử dụng các API cụ thể của MSMQ mà là để minh hoạ việc thực hiện các mẫu trong cuốn sách này bằng cách sử dụng một hệ thống nhắn tin dựa trên hàng đợi. Cấu trúc của giải pháp sẽ trông rất giống nhau khi được triển khai bằng Java sử dụng hàng đợi JMS hoặc IBM WebSphere MQ. Vì chúng tôi tập trung chủ yếu vào các quyết định thiết kế và các sự đánh đổi, chương này sẽ rất giá trị cho bạn ngay cả khi bạn không phải là một nhà phát triển C# hoặc MSMQ.
Việc triển khai môi giới khoản vay bao gồm bốn thành phần chính sau đây (xem hình):

Khách hàng (hoặc khách hàng thử nghiệm) gửi yêu cầu báo giá khoản vay.
Người môi giới vay đóng vai trò là người quản lý quy trình trung tâm và phối hợp việc giao tiếp giữa văn phòng tín dụng và các ngân hàng.
Cơ quan tín dụng cung cấp một dịch vụ cho môi giới cho vay, tính toán điểm tín dụng của khách hàng.
Mỗi ngân hàng nhận một yêu cầu báo giá từ môi giới cho vay và gửi một báo giá lãi suất theo các tham số của khoản vay.
Trong hầu hết các kịch bản tích hợp, chúng tôi không có quyền truy cập vào nội bộ của ứng dụng mà chỉ giới hạn trong việc giám sát và quản lý các thành phần từ bên ngoài. Để làm cho ví dụ này càng thực tế càng tốt, chúng tôi coi mỗi thành phần hiện có như một hộp đen. Với điều kiện này, chúng tôi muốn giải pháp quản lý đáp ứng các yêu cầu sau:
Bảng điều khiển quản lý: Chúng tôi muốn có một giao diện duy nhất hiển thị tình trạng của tất cả các thành phần và cho phép chúng tôi thực hiện các hành động bổ sung nếu có sự cố xảy ra.
Chất lượng dịch vụ của môi giới vay vốn: Trong giải pháp ban đầu, chúng tôi đã phát triển một khách hàng thử nghiệm để theo dõi thời gian phản hồi của môi giới vay giữa yêu cầu báo giá và phản hồi. Trong một kịch bản sản xuất thực tế, khách hàng sẽ không thực hiện chức năng này cho chúng tôi (họ có thể, tuy nhiên, phàn nàn rằng hệ thống quá chậm). Do đó, chúng tôi muốn giải pháp quản lý ghi lại thông tin này và truyền đạt nó đến bảng điều khiển quản lý.
Xác minh hoạt động của Cục tín dụng: Cục tín dụng là một dịch vụ bên ngoài do bên thứ ba cung cấp. Chúng tôi muốn đảm bảo hoạt động đúng đắn của dịch vụ này bằng cách định kỳ gửi tin nhắn thử nghiệm.
Chuyển hướng khi gặp sự cố với Cơ quan Tín dụng: Nếu Cơ quan Tín dụng gặp sự cố, chúng tôi muốn tạm thời chuyển hướng các tin nhắn yêu cầu tín dụng đến một nhà cung cấp dịch vụ khác.
Để đánh giá sức khỏe của giải pháp tổng thể, chúng ta cần có khả năng thu thập các chỉ số từ nhiều thành phần đến một điểm duy nhất, đó là bảng điều khiển quản lý. Bảng điều khiển này cũng phải có khả năng kiểm soát luồng tin nhắn và các tham số của thành phần để chúng ta có thể xử lý các sự cố bằng cách định tuyến lại tin nhắn hoặc thay đổi hành vi của các thành phần.
Bảng điều khiển quản lý giao tiếp với các thành phần riêng lẻ thông qua việc nhắn tin. Nó sử dụng một Bus Điều khiển riêng biệt chỉ chứa các thông điệp liên quan đến quản lý hệ thống và không chứa dữ liệu ứng dụng.
Bởi vì đây là một cuốn sách về tích hợp doanh nghiệp chứ không phải về thiết kế giao diện người dùng, chúng tôi giữ cho bảng điều khiển quản lý rất, rất đơn giản. Nhiều nhà cung cấp cung cấp hiển thị dữ liệu theo thời gian thực, hoặc bạn thậm chí có thể đạt được những điều kỳ diệu về hình ảnh với Visual Basic và các thành phần Microsoft Office như Excel. Ngoài ra, nhiều hệ điều hành và nền tảng lập trình cung cấp các khung công cụ riêng của họ, chẳng hạn như Java/JMX (Java Management Extensions) hoặc WMI (Windows Management Instrumentation) của Microsoft. Chúng tôi tự phát triển giải pháp của mình để làm cho nó ít phụ thuộc vào API của nhà cung cấp cụ thể và để minh họa hoạt động bên trong của một giải pháp giám sát. Chúng tôi sẽ xây dựng bảng điều khiển này khi thực hiện các chức năng quản lý cụ thể.
Yêu cầu đầu tiên cho giải pháp quản lý là đo lường chất lượng dịch vụ mà môi giới cho vay cung cấp cho khách hàng. Đối với loại giám sát này, chúng tôi không quan tâm đến nội dung kinh doanh của từng tin nhắn - tức là, lãi suất được cung cấp cho khách hàng - mà chỉ quan tâm đến thời gian đã trôi qua giữa tin nhắn yêu cầu và tin nhắn trả lời. Phần khó trong việc theo dõi thời gian giữa hai tin nhắn này là khách hàng có thể chỉ định kênh cho tin nhắn trả lời thông qua Địa chỉ Trả về, vì vậy chúng tôi không thể lắng nghe trên một kênh cố định cho tin nhắn trả lời. May mắn thay, mẫu Smart Proxy giải quyết dilema này cho chúng tôi. Một Smart Proxy chặn một tin nhắn yêu cầu, lưu trữ Địa chỉ Trả về do khách hàng cung cấp và thay thế nó bằng một địa chỉ kênh trả lời cố định. Kết quả là, dịch vụ (môi giới cho vay trong trường hợp của chúng tôi) gửi tất cả tin nhắn trả lời đến một kênh. Smart Proxy lắng nghe kênh này và tương ứng các tin nhắn trả lời đến các tin nhắn yêu cầu đã lưu. Sau đó, nó chuyển tiếp tin nhắn trả lời đến Địa chỉ Trả về gốc được khách hàng chỉ định.
"Trang bị cho Người môi giới vay bằng một Proxy thông minh"

Để tận dụng tính năng Smart Proxy, chúng tôi "chèn" Smart Proxy giữa khách hàng và nhà môi giới vay (xem hình trên). Việc chèn này là minh bạch đối với khách hàng vì Smart Proxy lắng nghe trên cùng một kênh mà nhà môi giới vay ban đầu lắng nghe (loanRequestQueue). Chúng tôi bây giờ khởi động nhà môi giới vay với các tham số mới để nó lắng nghe trên kênh brokerRequestQueue thay vì kênh loanRequestQueue. Smart Proxy chỉ dẫn nhà môi giới vay gửi tất cả các tin nhắn phản hồi đến kênh brokerReplyQueue, từ đó nó chuyển tiếp các tin nhắn trở lại địa chỉ trả về đúng như đã được khách hàng chỉ định ban đầu.
Chúng tôi muốn sử dụng Smart Proxy để đo cả thời gian phản hồi cho các yêu cầu vay và số lượng yêu cầu đang được xử lý bởi môi giới vay tại bất kỳ thời điểm nào. Smart Proxy có thể đo thời gian trôi qua giữa các tin nhắn yêu cầu và phản hồi bằng cách ghi lại thời gian mà tin nhắn yêu cầu được nhận. Khi nó nhận được tin nhắn phản hồi liên quan, Smart Proxy trừ thời gian yêu cầu từ thời gian hiện tại để tính toán thời gian trôi qua giữa yêu cầu và phản hồi. Smart Proxy có thể ước lượng số lượng yêu cầu đang hoạt động mà môi giới vay đang quản lý tại một thời điểm bằng cách đếm số lượng tin nhắn yêu cầu chưa được xử lý (tức là, tin nhắn yêu cầu chưa nhận được tin nhắn phản hồi). Smart Proxy không thể phân biệt giữa các tin nhắn đang xếp hàng trong brokerRequestQueue và các tin nhắn mà môi giới vay đã bắt đầu xử lý, vì vậy chỉ số này bằng tổng của cả hai. Chúng tôi có thể cập nhật số lượng tin nhắn yêu cầu chưa được xử lý mỗi khi chúng tôi nhận được một tin nhắn yêu cầu hoặc một tin nhắn phản hồi.
Proxy thông minh truyền thông tin chỉ số đến bảng điều khiển quản lý để giám sát và phân tích qua kênh ControlBusQueue. Chúng tôi có thể gửi thống kê cho từng thông điệp một, nhưng điều đó sẽ làm rối mạng lưới của chúng tôi nếu chúng tôi xử lý lượng thông điệp lớn. Việc chèn một Proxy thông minh vào dòng chảy thông điệp đã làm tăng gấp đôi số lượng thông điệp được gửi (hai thông điệp yêu cầu và phản hồi thay vì mỗi cái một), vì vậy chúng tôi muốn tránh việc gửi thêm một thông điệp điều khiển cho mỗi thông điệp yêu cầu. Thay vào đó, chúng tôi sử dụng một bộ hẹn giờ để Proxy thông minh gửi một thông điệp chỉ số đến Control Bus ở các khoảng thời gian đã định, ví dụ, mỗi 5 giây. Thông điệp chỉ số có thể chứa thông tin chỉ số tóm tắt (ví dụ, thời gian phản hồi tối đa, tối thiểu và trung bình) hoặc thông tin chi tiết cho tất cả các thông điệp đã được gửi qua trong khoảng thời gian đó. Để giữ cho các thông điệp chỉ số nhỏ và bảng điều khiển quản lý đơn giản, chúng tôi quyết định chỉ truyền các chỉ số tóm tắt đến bảng điều khiển.
Để thực hiện việc cho vay của môi giới Smart Proxy, chúng tôi sử dụng lại các lớp cơ sở của SmartProxy được giới thiệu trong mẫu Smart Proxy. Chúng tôi phân lớp các lớp SmartProxyBase, SmartProxyRequestConsumer và SmartProxyReplyConsumer (xem sơ đồ lớp). Vui lòng tham khảo mẫu Smart Proxy để có mã nguồn cho các lớp này.
Biểu đồ lớp proxy thông minh của môi giới cho vay

Giống như Smart-Proxy ban đầu, Loan-Broker-Proxy mới chứa hai bộ tiêu thụ tin nhắn riêng biệt, một cho các tin nhắn yêu cầu đến từ khách hàng (Loan-Broker-ProxyRequestConsumer) và một cho các tin nhắn trả lời đến từ môi giới cho vay (Loan-Broker-ProxyReplyConsumer). Cả hai lớp tiêu thụ đều kế thừa từ các lớp cơ sở tương ứng của chúng (Smart-ProxyRequestConsumer và Smart-ProxyReplyConsumer) và thêm một triển khai mới của phương thức AnalyzeMessage.
Hãy cùng xem xét việc triển khai lớp LoanBrokerProxy. Hàm khởi tạo nhận các tham số giống như lớp cơ sở SmartProxyBase, cộng với một tham chiếu đến hàng đợi Control Bus và khoảng thời gian báo cáo tính bằng giây.
Lớp này duy trì hai ArrayList với các số liệu, performanceStats và queueStats. performanceStats thu thập các điểm dữ liệu về thời gian phản hồi trong khoảng thời gian tính bằng giây, trong khi queueStats thu thập các điểm dữ liệu về số lượng thông điệp yêu cầu đang còn lại (những thông điệp được xếp hàng trong brokerRequestQueue hoặc đang được xử lý bởi môi giới cho vay). Khi bộ đếm thời gian đã lập trình kích hoạt, phương thức OnTimerEvent sẽ chụp ảnh dữ liệu trong cả hai bộ sưu tập. Chúng ta cần thực hiện bất kỳ phân tích nào về dữ liệu với bản sao chụp nhanh này vì các bộ tiêu thụ thông điệp tiếp tục thêm các điểm dữ liệu mới khi thông điệp được nhận.
public class LoanBrokerProxy : SmartProxyBase { protected MessageQueue controlBus; protected ArrayList performanceStats; protected ArrayList queueStats; protected int interval; protected Timer timer; public LoanBrokerProxy(MessageQueue inputQueue, MessageQueue serviceRequestQueue, MessageQueue serviceReplyQueue, MessageQueue controlBus, int interval) : base (inputQueue, serviceRequestQueue, serviceReplyQueue) { messageData = Hashtable.Synchronized(new Hashtable()); queueStats = ArrayList.Synchronized(new ArrayList()); performanceStats = ArrayList.Synchronized(new ArrayList()); this.controlBus = controlBus; this.interval = interval; requestConsumer = new LoanBrokerProxyRequestConsumer(inputQueue, serviceRequestQueue, serviceReplyQueue, messageData, queueStats); replyConsumer = new LoanBrokerProxyReplyConsumer(serviceReplyQueue, messageData, queueStats, performanceStats); } public override void Process() { base.Process(); TimerCallback timerDelegate = new TimerCallback(OnTimerEvent); timer = new Timer(timerDelegate, null, interval*1000, interval*1000); } protected void OnTimerEvent(Object state) { ArrayList currentQueueStats; ArrayList currentPerformanceStats; lock (queueStats) { currentQueueStats = (ArrayList)(queueStats.Clone()); queueStats.Clear(); } lock (performanceStats) { currentPerformanceStats = (ArrayList)(performanceStats.Clone()); performanceStats.Clear(); } SummaryStats summary = new SummaryStats(currentQueueStats, currentPerformanceStats); if (controlBus != null) controlBus.Send(summary); } } Bộ trung gian cho vay sử dụng cấu trúc Thống kê Tóm tắt để cô đặc các điểm dữ liệu cá nhân thành các giá trị tối đa, tối thiểu và trung bình, sau đó gửi dữ liệu tóm tắt đến Bus Điều khiển. Chúng ta có thể làm cho việc đánh giá hiệu quả hơn bằng cách cập nhật các thống kê tóm tắt với mỗi tin nhắn đến, nhằm chỉ cần lưu trữ dữ liệu tóm tắt và không phải từng điểm dữ liệu. Tuy nhiên, việc hoãn lại việc tính toán cho phép chúng ta thay đổi mức độ chi tiết mà chúng ta muốn công bố lên Bus Điều khiển.
Lớp LoanBrokerProxyRequestConsumer xử lý các tin nhắn yêu cầu đến. Lớp cơ sở SmartProxyRequestConsumer đảm nhiệm việc lưu trữ dữ liệu tin nhắn liên quan trong bảng băm messageData. Tương tự, triển khai cơ bản của SmartProxyReplyConsumer sẽ loại bỏ dữ liệu khỏi bảng băm đó mỗi khi nó nhận được tin nhắn phản hồi. Do đó, chúng ta có thể xác định số lượng tin nhắn yêu cầu chưa xử lý hiện tại từ kích thước của bảng băm messageData. LoanBrokerProxyRequestConsumer duy trì một tham chiếu đến tập hợp queueStats được lưu trữ bên trong LoanBrokerProxy để có thể thêm điểm dữ liệu mới vào tập hợp này.
public class LoanBrokerProxyRequestConsumer : SmartProxyRequestConsumer { ArrayList queueStats; public LoanBrokerProxyRequestConsumer(MessageQueue requestQueue, MessageQueue serviceRequestQueue, MessageQueue serviceReplyQueue, Hashtable messageData, ArrayList queueStats) : base(requestQueue, serviceRequestQueue, serviceReplyQueue, messageData) { this.queueStats = queueStats; } protected override void ProcessMessage(Message requestMsg) { base.ProcessMessage(requestMsg); queueStats.Add(messageData.Count); } } Consumer ProxyReply Môi giới vay thu thập hai chỉ số cần thiết khi một thông điệp trả lời đến. Đầu tiên, nó tính toán thời gian giữa việc gửi thông điệp yêu cầu và nhận thông điệp trả lời và thêm chỉ số đó vào bộ sưu tập performanceStats. Thứ hai, nó ghi lại số lượng yêu cầu còn lại (một lần nữa sử dụng kích thước của bảng băm messageData) và thêm số đó vào bộ sưu tập queueStats.
public class LoanBrokerProxyReplyConsumer : SmartProxyReplyConsumer { ArrayList queueStats; ArrayList performanceStats; public LoanBrokerProxyReplyConsumer(MessageQueue replyQueue, Hashtable messageData, ArrayList queueStats, ArrayList performanceStats) : base(replyQueue, messageData) { this.queueStats = queueStats; this.performanceStats = performanceStats; } protected override void AnalyzeMessage(MessageData data, Message replyMessage) { TimeSpan duration = DateTime.Now - data.SentTime; performanceStats.Add(duration.TotalSeconds); queueStats.Add(messageData.Count); } } Cấu trúc SummaryStats tính toán giá trị tối đa, tối thiểu và trung bình dựa trên dữ liệu được thu thập. Nó có thể xác định số lượng thông điệp yêu cầu đã được xử lý bằng cách trừ số điểm dữ liệu hiệu suất (được thu thập chỉ cho thông điệp trả lời) khỏi số điểm dữ liệu kích thước hàng đợi (được thu thập cho thông điệp yêu cầu và trả lời). Việc triển khai cấu trúc này khá đơn giản, vì vậy chúng tôi quyết định không dành cả một trang để viết mã.
Một khi chúng ta chèn proxy môi giới khoản vay mới vào luồng tin nhắn, chúng ta có thể bắt đầu thu thập các chỉ số hiệu suất. Để thu thập một số dữ liệu ví dụ, chúng tôi đã cấu hình hai khách hàng thử nghiệm để thực hiện 50 yêu cầu báo giá khoản vay mỗi khách hàng. Proxy đã thu thập các kết quả sau (chúng tôi đã sử dụng một chuyển đổi XSL đơn giản để hiển thị bảng HTML từ dữ liệu chỉ số được xuất bản theo định dạng XML lên controlBusQueue):
Dấu thời gian | Số lượng yêu cầu | Số lượt phản hồi | Thời gian xử lý tối thiểu | Thời gian xử lý trung bình | Thời gian xử lý tối đa | Kích thước hàng đợi tối thiểu | Kích thước hàng trung bình | Kích thước hàng đợi tối đa |
|---|---|---|---|---|---|---|---|---|
14:11:02.9644424 | 0 | 0 | không 0.00 | Không. | Không.00 | 0 | 0 | 0 |
14 giờ 11 phút 07 giây 9718424. | 89 | 7 | 0.78 in Vietnamese is "không phẩy bảy tám". | 2,54 | 3.93 | 1 | 42 | 82 |
14 giờ 11 phút 12 giây 9792424 mili giây | 11 | 9 | 4.31 | sáu phẩy bốn ba | tám phẩy sáu chín | 83 | 87 | 91 |
14:11:17.9866424 | 0 | 8 | chín phẩy ba mươi chín | mười phẩy tám ba | mười hai phẩy tám hai | 77 | 80 | 84 |
14 giờ 11 phút 22 giây 9940424 mili giây | 0 | 8 | mười ba phẩy tám 0 | mười lăm phẩy bảy năm | mười bảy phẩy bốn mươi tám | 69 | 72 | 76 |
14 giờ 11 phút 28 giây 0014424 | 0 | 7 | mười tám phẩy ba bảy | 20.19 in Vietnamese is "hai mươi phẩy mười chín". | 22.18 in Vietnamese is "hai mươi hai phẩy mười tám". | 62 | 65 | 68 |
14:11:33.0088424 | 0 | 6 | 22.90 in Vietnamese is "hai mươi hai phẩy chín". | Hai mươi bốn phẩy tám ba. | Hai mươi sáu phẩy chín mươi bốn | 56 | 58 | 61 |
14 giờ 11 phút 38 giây 0162424 | 0 | 10 | hai mươi bảy chấm bảy tư | 29,53 | 31.62 trong tiếng Việt là "ba mươi mốt phẩy sáu mươi hai". | 46 | 50 | 55 |
14 giờ 11 phút 43 giây 0236424 mili giây | 0 | 9 | Ba mươi một phẩy tám mươi bảy | 34,47 | 36.30 in Vietnamese is "36,30". | 37 | 41 | 45 |
14 giờ 11 phút 48 giây 0310424 | 0 | 7 | 36.87 | 39,06 | bốn mươi phẩy chín tám | 30 | 33 | 36 |
14:11:53.0384424 | 0 | 9 | 41,75 | bốn mươi ba phẩy tám mươi hai | bốn mươi lăm phẩy mười bốn | 21 | 25 | 29 |
14 giờ 11 phút 58 giây 0458424 | 0 | 8 | Bốn mươi lăm chấm chín mươi hai | bốn mươi bảy phẩy sáu mươi bảy | 49,67 | 13 | 16 | 20 |
14 giờ 12 phút 03 giây 0532424. | 0 | 8 | năm mươi phẩy tám sáu | năm mươi hai phẩy năm tám | Năm mươi bốn phẩy năm chín | 5 | 8 | 12 |
14:12:08.0606424 | 0 | 4 | Năm mươi lăm phẩy bốn mốt | năm mươi lăm phẩy chín sáu | năm mươi sáu phẩy sáu chín | 1 | 2 | 4 |
14:12:13.0680424 | 0 | 0 | Không có. | Không có gì | Không. | 0 | 0 | 0 |
Được tải vào một biểu đồ Excel, dữ liệu kích thước hàng đợi trông như thế này:
Thống kê Proxy Thông minh của Nhà môi giới Vay

Chúng ta có thể thấy rằng hai khách hàng kiểm tra gần như đã làm ngập dịch vụ môi giới cho vay, đạt đỉnh khoảng 90 yêu cầu đang chờ xử lý. Dịch vụ môi giới cho vay sau đó xử lý các yêu cầu với tốc độ ổn định khoảng 2 tin nhắn yêu cầu mỗi giây. Do số lượng yêu cầu đang xếp hàng lớn, thời gian phản hồi khá kém, đạt đỉnh gần 1 phút. Tin tốt là dịch vụ môi giới cho vay xử lý một số lượng lớn yêu cầu đột ngột một cách mềm dẻo, trong khi tin xấu là thời gian phản hồi rất dài. Để cải thiện thời gian phản hồi, chúng ta có thể thực hiện nhiều phiên bản dịch vụ môi giới cho vay hoặc nhiều phiên bản dịch vụ văn phòng tín dụng (dịch vụ văn phòng tín dụng hóa ra là một nút thắt trong triển khai ban đầu được mô tả trong Chương 9, "Giữa: Gửi tin nhắn kết hợp").
Yêu cầu thứ hai cho giải pháp quản lý là theo dõi hoạt động chính xác của dịch vụ báo cáo tín dụng bên ngoài. Người môi giới cho vay truy cập dịch vụ này để lấy điểm tín dụng cho khách hàng yêu cầu báo giá vay vì các ngân hàng yêu cầu thông tin này để cung cấp báo giá chính xác.
Để xác minh hoạt động chính xác của dịch vụ văn phòng tín dụng bên ngoài, chúng tôi quyết định gửi các Thông Điệp Kiểm Tra định kỳ đến dịch vụ. Vì dịch vụ văn phòng tín dụng hỗ trợ Địa Chỉ Trả Lại, nên việc chèn một Thông Điệp Kiểm Tra mà không làm gián đoạn dòng tin nhắn hiện có là rất dễ dàng. Chúng tôi chỉ cần cung cấp một kênh trả lời dành riêng cho các thông điệp kiểm tra, điều này tránh sự cần thiết phải sử dụng một bộ phân tách thông điệp kiểm tra riêng biệt (xem hình).
Giám sát Dịch vụ Văn phòng Tín dụng

Để xác minh hoạt động chính xác của dịch vụ bureau tín dụng, chúng tôi cần một trình tạo dữ liệu thử nghiệm và một trình xác minh dữ liệu thử nghiệm. Trình tạo dữ liệu thử nghiệm tạo ra dữ liệu thử nghiệm để gửi đến dịch vụ đang được thử nghiệm. Một thông điệp thử nghiệm của bureau tín dụng rất đơn giản; trường duy nhất mà bắt buộc là số an sinh xã hội (SSN). Đối với các bài kiểm tra của chúng tôi, chúng tôi sử dụng một số SSN cố định, đặc biệt xác định một người hư cấu. Điều này cho phép chúng tôi xác minh dữ liệu kết quả bằng cách so sánh với các kết quả đã được thiết lập trước. Bằng cách này, chúng tôi không chỉ có thể kiểm tra xem chúng tôi có nhận được thông điệp phản hồi hay không mà còn xác minh rằng nội dung của thông điệp là chính xác. Trong ví dụ đơn giản của chúng tôi được giới thiệu trong Chương 9, "Khoảng giữa: Nhắn tin Tổ hợp," dịch vụ bureau tín dụng được lập trình để trả về các kết quả ngẫu nhiên bất kể số SSN đến. Do đó, trình xác minh dữ liệu thử nghiệm của chúng tôi không kiểm tra các giá trị kết quả cụ thể mà thay vào đó xác minh xem liệu các kết quả có nằm trong phạm vi cho phép hay không (ví dụ: 300 đến 900 cho điểm tín dụng). Nếu các kết quả nằm ngoài phạm vi cho phép (ví dụ, vì một lỗi tính toán đã đặt điểm số bằng không), trình xác minh dữ liệu thử nghiệm sẽ thông báo cho bảng điều khiển quản lý bằng một thông điệp.
Trình xác minh dữ liệu kiểm tra cũng kiểm tra thời gian phản hồi của dịch vụ bên ngoài. Nếu chúng tôi không nhận được tin nhắn trả lời trong khoảng thời gian đã định, chúng tôi cũng sẽ thông báo cho bảng điều khiển quản lý. Để giảm thiểu băng thông mạng, trình xác minh dữ liệu kiểm tra chỉ thông báo cho bảng điều khiển nếu phản hồi bị trễ hoặc bị sai định dạng, không phải khi dịch vụ hoạt động đúng. Ngoại lệ duy nhất cho quy tắc này xảy ra khi trình giám sát nhận được tin nhắn trả lời đúng từ dịch vụ sau khi phát hiện lỗi. Trong trường hợp đó, trình giám sát gửi một tin nhắn "dịch vụ ổn" đến bảng điều khiển quản lý để cho biết rằng cơ quan tín dụng đang hoạt động trở lại bình thường. Cuối cùng, trong quá trình khởi động, trình giám sát gửi một tin nhắn đến bảng điều khiển để thông báo về sự tồn tại của nó. Tin nhắn này cho phép bảng điều khiển "khám phá" tất cả các trình giám sát đang hoạt động để có thể hiển thị trạng thái cho mỗi cái.
Triển khai bộ giám sát sử dụng hai bộ đếm thời gian riêng biệt: một để gửi thông điệp kiểm tra trong các khoảng thời gian được chỉ định và một cái khác để đánh dấu một ngoại lệ nếu không nhận được phản hồi trong khoảng thời gian chờ được chỉ định (xem sơ đồ). Bộ đếm thời gian gửi xác định khoảng thời gian giữa thông điệp nhận được cuối cùng hoặc sự kiện thời gian chờ cuối cùng và việc gửi thông điệp kiểm tra tiếp theo. Bộ đếm thời gian chờ được bắt đầu mỗi khi bộ giám sát gửi một thông điệp yêu cầu. Nếu thông điệp phản hồi đến trong khoảng thời gian chờ được chỉ định, bộ đếm thời gian chờ sẽ được đặt lại và khởi động lại với thông điệp yêu cầu tiếp theo. Nếu bộ giám sát không nhận được thông điệp phản hồi trong khoảng thời gian được chỉ định, bộ đếm thời gian chờ sẽ kích hoạt và bộ giám sát sẽ gửi một thông điệp lỗi đến bus điều khiển. Sau đó, nó bắt đầu một bộ đếm thời gian gửi mới để khởi động một thông điệp yêu cầu mới sau khoảng thời gian gửi. Một kịch bản trong thực tế có khả năng sử dụng một thời gian chờ tương đối ngắn (vài giây) và một khoảng thời gian gửi dài hơn (ví dụ, một phút).
Hình dưới đây minh họa các phụ thuộc giữa hai bộ đếm thời gian. Trong kịch bản này, bộ giám sát gửi một Thông điệp Kiểm tra và bắt đầu Bộ đếm Thời gian Timeout. Một thông điệp phản hồi đến trước khi bộ đếm thời gian hết, vì vậy bộ giám sát hủy bỏ Bộ đếm Thời gian Timeout và bắt đầu Bộ đếm Thời gian Khoảng thời gian. Khi Bộ đếm Thời gian Khoảng thời gian hết, bộ giám sát gửi một Thông điệp Kiểm tra mới và bắt đầu một Bộ đếm Thời gian Timeout mới. Lần này, Bộ đếm Thời gian Timeout hết trước khi thông điệp phản hồi đến, khiến bộ giám sát gửi một thông điệp đến Bus Điều khiển. Đồng thời, bộ giám sát bắt đầu một Bộ đếm Thời gian Khoảng thời gian mới.
Theo dõi Dịch vụ Văn phòng Tín dụng

Việc triển khai bộ giám sát chỉ yêu cầu một lớp duy nhất. Lớp Monitor kế thừa từ MessageConsumer được giới thiệu trong mẫu Smart Proxy. Lớp này cấu hình một kênh vào và khởi động một Người tiêu dùng Dựa trên Sự kiện để nhận tin nhắn. Đối với mỗi tin nhắn đến, nó gọi phương thức ảo ProcessMessage. Một lớp kế thừa có thể đơn giản ghi đè phương thức này để thêm xử lý của riêng mình.
Phương thức Process hướng dẫn một MessageConsumer bắt đầu tiêu thụ các tin nhắn. Lớp Monitor bổ sung cho việc triển khai cơ sở của phương thức này bằng cách bắt đầu Timer Gửi. Khi bộ đếm này kích hoạt, nó gọi phương thức OnSendTimerEvent. Phương thức Process cũng gửi một tin nhắn loại MonitorStatus đến Control Bus để thông báo sự tồn tại của nó.
public override void Process() { base.Process(); sendTimer = new Timer(new TimerCallback (OnSendTimerEvent), null, interval*1000, Timeout.Infinite); MonitorStatus status = new MonitorStatus( MonitorStatus.STATUS_ANNOUNCE, "Monitor On-Line", null, MonitorID); Console.WriteLine(status.Description); controlQueue.Send(status); lastStatus = status.Status; } protected void OnSendTimerEvent(Object state) { CreditBureauRequest request = new CreditBureauRequest(); request.SSN = SSN; Message requestMessage = new Message(request); requestMessage.Priority = MessagePriority.AboveNormal; requestMessage.ResponseQueue = inputQueue; Console.WriteLine(DateTime.Now.ToString() + " Sending request message"); requestQueue.Send(requestMessage); correlationID = requestMessage.Id; timeoutTimer = new Timer(new TimerCallback(OnTimeoutEvent), null, timeout*1000, Timeout.Infinite); } Phương thức OnSendTimerEvent tạo ra một thông điệp yêu cầu mới. Tham số duy nhất trong thông điệp yêu cầu là số An sinh xã hội (SSN) của khách hàng. Phương thức này chỉ định một SSN cố định. Phương thức cũng lưu lại ID thông điệp để xác minh Mã định danh Tương quan của bất kỳ thông điệp phản hồi nào đến. Cuối cùng, nó khởi động bộ đếm thời gian để trình theo dõi được thông báo sau một khoảng thời gian nhất định nếu không nhận được thông điệp phản hồi.
Phương pháp này thiết lập thuộc tính Độ Ưu Tiên của thông điệp kiểm tra thành Trên Bình Thường để đảm bảo rằng các thông điệp ứng dụng đang chờ không làm cho dịch vụ có vẻ như không khả dụng. Việc sử dụng độ ưu tiên cao hơn cho Thông Điệp Kiểm Tra sẽ khiến hàng đợi thông điệp chuyển giao các thông điệp này trước các thông điệp ứng dụng đang chờ. Việc thiết lập độ ưu tiên thông điệp cao hơn là an toàn trong trường hợp này vì bộ tạo dữ liệu kiểm tra chỉ chèn một lượng rất nhỏ thông điệp kiểm tra. Nếu chúng ta chèn một lượng lớn thông điệp có độ ưu tiên cao vào kênh yêu cầu, chúng ta có thể làm gián đoạn dòng chảy của các thông điệp ứng dụng. Điều này chắc chắn sẽ vi phạm ý định của một giải pháp quản lý là phải ít gây trở ngại nhất có thể.
Phương thức ProcessMessage là trái tim của lớp Monitor. Nó thực hiện việc xác minh thông điệp kiểm tra, đánh giá các thông điệp phản hồi đến. Sau khi dừng bộ đếm thời gian timeout, phương thức kiểm tra thông điệp đến để xác nhận Mã định danh Tương quan đúng, loại dữ liệu đúng của nội dung thông điệp và các giá trị hợp lý bên trong nội dung thông điệp. Nếu bất kỳ bài kiểm tra nào trong số này thất bại, phương thức thiết lập một cấu trúc MonitorStatus và gửi nó đến kênh Control Bus. Monitor cũng theo dõi trạng thái trước đó được lưu trữ trong biến lastStatus. Nếu trạng thái thay đổi từ "lỗi" sang "OK," phương thức ProcessMessage cũng gửi một thông báo đến Control Bus.
protected override void ProcessMessage(Message msg) { Console.WriteLine(DateTime.Now.ToString() + " Received reply message"); if (timeoutTimer != null) timeoutTimer.Dispose(); msg.Formatter = new XmlMessageFormatter(new Type[] {typeof(CreditBureauReply)}); CreditBureauReply replyStruct; MonitorStatus status = new MonitorStatus(); status.Status = MonitorStatus.STATUS_OK; status.Description = "No Error"; status.ID = MonitorID; try { if (msg.Body is CreditBureauReply) { replyStruct = (CreditBureauReply)msg.Body; if (msg.CorrelationId != correlationID) { status.Status = MonitorStatus.STATUS_FAILED_CORRELATION; status.Description = "Incoming message correlation ID does not match outgoing message ID"; } else { if (replyStruct.CreditScore < 300 || replyStruct.CreditScore > 900 || replyStruct.HistoryLength < 1 || replyStruct.HistoryLength > 24) { status.Status = MonitorStatus.STATUS_INVALID_DATA; status.Description = "Credit score values out of range"; } } } else { status.Status = MonitorStatus.STATUS_INVALID_FORMAT; status.Description = "Invalid message format"; } } catch (Exception e) { Console.WriteLine("Exception: {0}", e.ToString()); status.Status = MonitorStatus.STATUS_INVALID_FORMAT; status.Description = "Could not deserialize message body"; } StreamReader reader = new StreamReader (msg.BodyStream); status.MessageBody = reader.ReadToEnd(); Console.WriteLine(status.Description); if (status.Status != MonitorStatus.STATUS_OK || (status.Status == MonitorStatus.STATUS_OK && lastStatus != MonitorStatus.STATUS_OK)) { controlQueue.Send(status); } lastStatus = status.Status; sendTimer.Dispose(); sendTimer = new Timer(new TimerCallback(OnSendTimerEvent), null, interval*1000, Timeout.Infinite); } Nếu không có thông điệp nào xuất hiện trong khoảng thời gian đã chỉ định, bộ đếm thời gian timeout sẽ gọi phương thức OnTimeoutEvent. Phương thức này gửi một thông điệp MonitorStatus đến Bus Điều Khiển và bắt đầu một bộ đếm thời gian gửi mới để một thông điệp yêu cầu mới được gửi sau khoảng thời gian đó.
protected void OnTimeoutEvent(Object state) { MonitorStatus status = new MonitorStatus( MonitorStatus.STATUS_TIMEOUT, "Timeout", null, MonitorID); Console.WriteLine(status.Description); controlQueue.Send(status); lastStatus = status.Status; timeoutTimer.Dispose(); sendTimer = new Timer(new TimerCallback(OnSendTimerEvent), null, interval*1000, Timeout.Infinite); } Bây giờ mà chúng ta có thể theo dõi trạng thái của dịch vụ bureau tín dụng bên ngoài, chúng ta muốn sử dụng dữ liệu này để triển khai một cơ chế chuyển đổi (failover) để người môi giới khoản vay có thể tiếp tục hoạt động ngay cả khi dịch vụ bureau tín dụng gặp sự cố. Đáng chú ý rằng các Kênh Điểm-Đến-Điểm đã cung cấp một hình thức chuyển đổi cơ bản. Khi chúng ta sử dụng nhiều Người tiêu dùng Cạnh tranh trên một Kênh Điểm-Đến-Điểm duy nhất, sự cố của một người tiêu dùng sẽ không làm gián đoạn quy trình miễn là các người tiêu dùng khác vẫn hoạt động. Khi nhiều người tiêu dùng đang hoạt động, họ chia sẻ tải, hiệu quả thực hiện một cơ chế cân bằng tải đơn giản. Vậy tại sao chúng ta lại cần phải triển khai một cơ chế chuyển đổi rõ ràng? Khi sử dụng các dịch vụ bên ngoài, chúng ta có thể bị giới hạn vào các kênh đơn giản không hỗ trợ Người tiêu dùng Cạnh tranh, như SOAP qua HTTP. Ngoài ra, chúng ta có thể không muốn nhiều dịch vụ thực hiện cân bằng tải. Ví dụ, chúng ta có thể có một thỏa thuận về khối lượng với nhà cung cấp dịch vụ chính, đảm bảo cho chúng ta giảm giá đáng kể nếu chúng ta đáp ứng một số hạn mức sử dụng nhất định. Chia sẻ lưu lượng giữa hai nhà cung cấp có thể sẽ khiến chúng ta tốn nhiều hơn. Hoặc, chúng ta có thể đang sử dụng một nhà cung cấp giá thấp làm nhà cung cấp dịch vụ chính và muốn chuyển sang một nhà cung cấp cao cấp chỉ khi nhà cung cấp giá thấp gặp sự cố. (Để biết thêm về các quyết định kiến trúc được điều phối bởi các yếu tố cấp phép, hãy xem [Hohmann].)
Để triển khai chuyển đổi dự phòng rõ ràng, chúng tôi chèn một Bộ định tuyến Tin nhắn vào kênh yêu cầu của cơ quan tín dụng (xem hình). Bộ định tuyến này chuyển tiếp yêu cầu đến dịch vụ cơ quan tín dụng chính (mũi tên đen dày) hoặc đến dịch vụ cơ quan tín dụng thứ cấp (mũi tên đen mỏng). Bởi vì dịch vụ thứ cấp có thể sử dụng định dạng tin nhắn khác với dịch vụ đầu tiên, chúng tôi bọc dịch vụ thứ cấp bằng một cặp Bộ chuyển đổi Tin nhắn. Bộ định tuyến Tin nhắn là một Bộ định tuyến Tin nhắn dựa trên ngữ cảnh được điều khiển bởi bảng quản lý qua Bus Điều khiển. Bảng quản lý nhận dữ liệu giám sát từ bộ giám sát cơ quan tín dụng mà chúng tôi thiết kế trong phần trước. Nếu bộ giám sát chỉ ra sự cố, bảng quản lý sẽ hướng dẫn Bộ định tuyến Tin nhắn chuyển hướng lưu lượng tới nhà cung cấp dịch vụ thứ cấp (xem hình).
Chuyển đổi Dự phòng Rõ ràng với Bộ định tuyến Tin nhắn Dựa trên Ngữ cảnh

Khi lưu lượng tin nhắn yêu cầu được chuyển hướng đến nhà cung cấp dịch vụ thứ cấp, bộ giám sát tiếp tục gửi tin nhắn thử nghiệm đến nhà cung cấp chính. Khi bộ giám sát xác nhận hoạt động chính xác của dịch vụ, bảng điều khiển chỉ đạo Bộ Định Tuyến Tin Nhắn quay lại việc định tuyến các tin nhắn yêu cầu đến nhà cung cấp chính. Sơ đồ giải pháp không hiển thị bộ giám sát cho nhà cung cấp dịch vụ thứ cấp mặc dù sẽ rất dễ dàng để sử dụng một phiên bản thứ hai của bộ giám sát bureau tín dụng để giám sát tình trạng của dịch vụ bureau tín dụng dự phòng.
Hãy nhìn vào việc triển khai Bộ định tuyến Tin nhắn dựa trên ngữ cảnh. Lớp ContextBasedRouter kế thừa từ lớp cơ sở MessageConsumer đáng tin cậy của chúng tôi để xử lý các tin nhắn đến. Phương thức ProcessMessage kiểm tra giá trị của biến control và định tuyến các tin nhắn đến theo kênh đầu ra chính hoặc thứ cấp dựa trên giá trị của biến này.
delegate void ControlEvent(int control); class ContextBasedRouter : MessageConsumer { ... protected override void ProcessMessage(Message msg) { if (control == 0) { primaryOutputQueue.Send(msg); } else { secondaryOutputQueue.Send(msg); } } protected void OnControlEvent(int control) { this.control = control; Console.WriteLine("Control = " + control); } } Biến điều khiển được thiết lập bởi phương thức OnControlEvent. Phương thức này được gọi bởi lớp ControlReceiver, cũng kế thừa từ MessageConsumer khi nó lắng nghe các thông điệp từ kênh điều khiển. Lớp ContextBasedRouter cung cấp cho ControlReceiver một delegate loại ControlEvent để gọi khi nó nhận được một sự kiện điều khiển với giá trị số. Nếu bạn chưa gặp delegate, chúng là một cách rất hay và an toàn về kiểu để triển khai callback mà không cần phải thực hiện một giao diện khác hoặc chuyển sang con trỏ hàm ([Box] đi vào tất cả các chi tiết phức tạp).
class ControlReceiver : MessageConsumer { protected ControlEvent controlEvent; public ControlReceiver(MessageQueue inputQueue, ControlEvent controlEvent) : base (inputQueue) { this.controlEvent = controlEvent; } protected override void ProcessMessage(Message msg) { String text = (string)msg.Body; Double resNum; if (Double.TryParse(text, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out resNum)) { int control = int.Parse(text); controlEvent(control); } } } Phiên bản đầu tiên của bảng điều khiển quản lý đơn giản đến nỗi chúng tôi thậm chí không cần hiển thị mã nguồn. Tất cả những gì nó có thể làm là nhận một tin nhắn và ghi nội dung tin nhắn vào một tệp để phân tích sau này (chẳng hạn như tạo đồ thị hiệu suất từ Excel). Bây giờ chúng tôi muốn tích hợp thêm một số trí tuệ vào bảng điều khiển quản lý. Đầu tiên, khi màn hình giám sát tín dụng chính cho thấy sự cố, bảng điều khiển quản lý cần chỉ định Bộ định tuyến Tin nhắn dựa trên ngữ cảnh để chuyển hướng tin nhắn đến nhà cung cấp dịch vụ thứ cấp. Chúng tôi đã quyết định triển khai chức năng này bên trong bảng điều khiển quản lý để có thể tách biệt hiệu quả màn hình giám sát và Bộ định tuyến Tin nhắn dựa trên ngữ cảnh; bảng điều khiển quản lý hoạt động như một Trung gian [GoF]. Hơn nữa, việc triển khai logic chuyển đổi ở một vị trí trung tâm cho phép chúng tôi có một điểm bảo trì duy nhất cho các quy tắc quản lý hệ thống. Các bảng điều khiển quản lý thương mại thường bao gồm các động cơ quy tắc có thể cấu hình để xác định các hành động sửa chữa thích hợp dựa trên các sự kiện trên Bus Điều khiển.
Thứ hai, chúng tôi muốn xây dựng một giao diện người dùng đơn giản cho bảng điều khiển quản lý hiển thị trạng thái hiện tại của hệ thống. Việc có được cái nhìn tổng quát về một hệ thống nhắn tin có thể khá khó khăn, đặc biệt là khi các đường đi của thông điệp thay đổi một cách động. Ngay cả một số lượng nhỏ các thành phần cũng có thể khiến việc hòa giải nơi thông điệp chảy rất khó khăn. Giao diện người dùng của chúng tôi đơn giản nhưng vẫn rất hữu ích. Chúng tôi sử dụng ngôn ngữ biểu tượng được định nghĩa trong cuốn sách này để đại diện cho sự tương tác giữa các thành phần. Hiện tại, giao diện người dùng chỉ hiển thị phần chuyển đổi dự phòng của cơ quan tín dụng trong hệ thống, gồm hai dịch vụ và một Bộ định tuyến Tin nhắn dựa trên ngữ cảnh; xem hình trên trang tiếp theo.
Bảng điều khiển quản lý cho thấy cả hai dịch vụ của cơ quan tín dụng đều đang hoạt động.

Khi Giao thức giám sát phát hiện một sự cố và chỉ thị cho bộ định tuyến reroute lưu lượng, chúng tôi muốn cập nhật giao diện người dùng để phản ánh trạng thái mới (xem hình). Biểu tượng bộ định tuyến hiển thị tuyến đường mới cho các thông điệp yêu cầu, và thành phần cơ quan tín dụng chính thay đổi màu sắc để chỉ ra sự cố.
Bảng điều khiển quản lý cho thấy rằng cơ quan tín dụng chính đã thất bại và lưu lượng đang được chuyển hướng.

Hãy cùng xem qua mã nguồn phía sau bảng điều khiển này. Chúng ta sẽ tập trung vào phần quản lý hệ thống của mã và không đi vào chi tiết của mã thực hiện những hình ảnh giao diện người dùng đẹp mắt. Đầu tiên, bảng điều khiển cần có khả năng truy xuất các thông điệp trạng thái từ thành phần giám sát. Để làm cho bảng điều khiển càng mạnh mẽ càng tốt, chúng ta truy cập nội dung thông điệp theo cách lỏng lẻo, đọc các trường riêng lẻ từ tải trọng XML. Cách tiếp cận này giúp giữ cho bảng điều khiển quản lý hoạt động ngay cả khi các thành phần riêng lẻ quyết định thêm các trường mới vào định dạng thông điệp.
Không có gì ngạc nhiên khi lớp bảng điều khiển cũng kế thừa từ người bạn tốt của chúng ta, MessageConsumer, vì vậy chúng ta chỉ hiển thị việc triển khai của bộ tạo và phương thức ProcessMessage. Phương thức này đơn giản là đọc BodyStream của thông điệp vào một biến chuỗi và truyền nó cho các thành phần khác nhau để phân tích.
public delegate void ControlMessageReceived(String body); public class ManagementConsole : MessageConsumer { protected Logger logger; public MonitorStatusHandler monitorStatusHandler; public ControlMessageReceived updateEvent; public ManagementConsole(MessageQueue inputQueue, string pathName) : base(inputQueue) { logger = new Logger(pathName); monitorStatusHandler = new MonitorStatusHandler(); updateEvent += new ControlMessageReceived(logger.Log); updateEvent += new ControlMessageReceived(monitorStatusHandler.OnControlMessage); } protected override void ProcessMessage(Message m) { Stream stm = m.BodyStream; StreamReader reader = new StreamReader (stm); String body = reader.ReadToEnd(); updateEvent(body); } ... } Lớp ManagementConsole sử dụng một delegate để thông báo cho logger và MonitorStatusHandler. Việc sử dụng delegate cho phép chúng ta dễ dàng thêm các lớp khác cũng lắng nghe các tin nhắn điều khiển đến mà không cần phải thay đổi mã ở phương thức ProcessMessage.
Một trong những thành phần phân tích dữ liệu thông điệp kiểm soát đến là lớp MonitorStatusHandler. Đầu tiên, lớp này kiểm tra xem tài liệu XML chứa trong nội dung của thông điệp đến có phần tử gốc <MonitorStatus> hay không. Nếu có, nó tải nội dung thông điệp vào một tài liệu XML để trích xuất các trường liên quan bên trong các phần tử ID và Status. Sau đó, nó gọi đến delegate updateEvent, có kiểu MonitorStatusUpdate. Bất kỳ lớp nào trong ứng dụng quản lý console quan tâm có thể thêm một phương thức callback vào delegate này và nhận thông báo mỗi khi một thông điệp MonitorStatus đến. Tất cả những gì thành phần này cần làm là cung cấp một triển khai của một phương thức có chữ ký bằng với MonitorStatusUpdate.
public delegate void MonitorStatusUpdate(String ID, int Status); public class MonitorStatusHandler { public MonitorStatusUpdate updateEvent; public void OnControlMessage(String body) { XmlDocument doc = new XmlDocument(); doc.LoadXml(body); XmlElement root = doc.DocumentElement; if (root.Name == "MonitorStatus") { XmlNode statusNode = root.SelectSingleNode("Status"); XmlNode idNode = root.SelectSingleNode("ID"); if (idNode!= null && statusNode != null) { String msgID = idNode.InnerText; String msgStatus = statusNode.InnerText; Double resNum; int status = 99; if (Double.TryParse(msgStatus, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out resNum)) { status = (int)resNum; } updateEvent(msgID, status); } } } } Trong ví dụ của chúng tôi, hai thành phần đầu tiên nghe sự kiện MonitorStatusUpdate được kích hoạt bởi MonitorStatusHandler là hai điều khiển giao diện người dùng đại diện cho dịch vụ văn phòng tín dụng chính và thứ cấp trong mẫu giao diện người dùng. Mỗi điều khiển giao diện người dùng lọc các sự kiện theo định danh mà duy nhất cho thành phần tương ứng đang được giám sát. Khi trạng thái của thành phần được giám sát thay đổi, điều khiển giao diện người dùng thay đổi màu sắc của thành phần. Routine sau đây được thực hiện trong quá trình khởi tạo mẫu hiển thị và kết nối hai điều khiển hiển thị văn phòng tín dụng với monitorStatusHandler của bảng điều khiển quản lý. Mã này khiến phương thức OnMonitorStatusUpdate của các điều khiển được gọi bất cứ khi nào bảng điều khiển nhận được tin nhắn cập nhật trạng thái giám sát.
console = new ManagementConsole(controlBusQueue, logFileName); primaryCreditBureauControl = new ComponentStatusControl("Primary Credit Bureau", "PrimaryCreditService"); primaryCreditBureauControl.Bounds = new Rectangle(300, 30, COMPONENT_WIDTH, COMPONENT_HEIGHT); secondaryCreditBureauControl = new ComponentStatusControl("Secondary Credit Bureau", "SecondaryCreditService"); secondaryCreditBureauControl.Bounds = new Rectangle(300, 130, COMPONENT_WIDTH, COMPONENT_HEIGHT); console.monitorStatusHandler.updateEvent += new MonitorStatusUpdate(primaryCreditBureauControl.OnMonitorStatusUpdate); console.monitorStatusHandler.updateEvent += new MonitorStatusUpdate(secondaryCreditBureauControl.OnMonitorStatusUpdate); Một thành phần khác lắng nghe các sự kiện MonitorStatusUpdate là FailOverHandler. Thành phần này là một thành phần không hiển thị, phân tích các thông điệp trạng thái để xác định xem có nên thiết lập chuyển đổi thất bại hay không. Nếu trạng thái của bộ giám sát đã thay đổi (chúng tôi sử dụng toán tử AND logic được ký hiệu bằng toán tử ^), FailOverHandler gửi một thông điệp lệnh đến kênh lệnh được chỉ định. Trong trường hợp của chúng tôi, kênh lệnh này được kết nối với Bộ định tuyến Thông điệp dựa trên ngữ cảnh được mô tả trước đó, sẽ bắt đầu định tuyến lại các thông điệp yêu cầu điểm tín dụng đến một nhà cung cấp bureau tín dụng khác.
public delegate void FailOverStatusUpdate(String ID, string Command); public class FailOverHandler { ... public void OnMonitorStatusUpdate(String ID, int status) { if (componentID == ID) { if (IsOK(status) ^ IsOK(currentStatus)) { String command = IsOK(status) ? "0" : "1"; commandQueue.Send(command); currentStatus = status; updateEvent(ID, command); } } } protected bool IsOK(int status) { return (status == 0 || status >= 99); } } Bộ xử lý Fail-Over cũng gọi sự kiện updateEvent, điều này là một delegate của kiểu Fail-OverStatusUpdate. Tương tự như MonitorStatusHandler, chúng ta có thể đăng ký bất kỳ thành phần nào thực hiện một phương thức của loại này để nhận thông báo cập nhật bất cứ khi nào Bộ xử lý Fail-Over thay đổi trạng thái. Trong ví dụ của chúng ta, chúng ta đăng ký điều khiển Fail-Over hình ảnh để nhận các sự kiện này để nó có thể vẽ lại bất cứ khi nào trạng thái failover thay đổi. Thủ tục khởi tạo giao diện người dùng console thiết lập kết nối giữa các thành phần này:
failOverControl = new FailOverControl("Credit Bureau Failover", "PrimaryCreditService"); failOverControl.Bounds = new Rectangle(100, 80, ROUTER_WIDTH, COMPONENT_HEIGHT); FailOverHandler failOverHandler = new FailOverHandler(commandQueue, "PrimaryCreditService"); console.monitorStatusHandler.updateEvent += new MonitorStatusUpdate(failOverHandler.OnMonitorStatusUpdate); failOverHandler.updateEvent += new FailOverStatusUpdate(failOverControl.OnMonitorStatusUpdate); Kết nối các thành phần riêng lẻ bên trong bảng điều khiển quản lý thông qua các delegate và sự kiện dẫn đến một kiến trúc lỏng lẻo. Kiến trúc này cho phép chúng ta tái sử dụng các thành phần riêng lẻ và kết hợp chúng thành các cấu hình khác nhau giống như phong cách kiến trúc Pipes and Filters được giới thiệu ở đầu cuốn sách. Về cơ bản, việc truyền thông điệp đến trên Bus Điều Khiển bằng cách sử dụng delegate tương tự như việc tạo ra một Kênh Publish-Subscribe nội bộ ứng dụng. Bởi vì các sự kiện trên bus điều khiển đến qua một Kênh Điểm-điểm, chúng ta phải sử dụng một người tiêu dùng duy nhất, người sau đó phát hành sự kiện đến bất kỳ người đăng ký nào quan tâm bên trong ứng dụng.
Sơ đồ hợp tác dưới đây minh họa sự lan truyền của các sự kiện giữa các thành phần riêng lẻ bên trong bảng điều khiển quản lý.
Sự lan truyền của các sự kiện trong Bảng điều khiển Quản lý

Sử dụng một giao diện điều khiển người dùng để trực quan hóa luồng thông điệp giữa các thành phần riêng lẻ là một công cụ quản lý hệ thống mạnh mẽ. Một số nhà cung cấp bao gồm các bộ phát triển cho phép nhà thiết kế sắp xếp trực quan các thành phần và kết nối các cổng đầu vào và đầu ra của chúng để tạo ra ứng dụng luồng thông điệp phân tán. Ví dụ, sản phẩm Tifosi của Fiorano (http://www.fiorano.com) bao gồm Trình soạn thảo Ứng dụng Phân tán cho phép thiết kế một giải pháp phân tán từ một GUI duy nhất mặc dù mỗi thành phần có thể thực thi trên một máy hoặc nền tảng khác nhau. Công cụ này sử dụng một Bus Điều khiển để kết nối tất cả các thành phần phân tán với một bảng điều khiển quản lý và giám sát trung tâm.
Ví dụ đơn giản của chúng tôi yêu cầu bảng điều khiển quản lý mã cứng kết nối hình ảnh giữa các thành phần riêng lẻ, chẳng hạn như vẽ một đường giữa router chuyển đổi và các biểu tượng đại diện cho các dịch vụ của văn phòng tín dụng. Nhiều công cụ tích hợp cho phép người dùng thiết kế giải pháp từ đầu bằng cách sử dụng giao diện đồ họa. Cách tiếp cận này giúp dễ dàng sử dụng cùng một thiết kế đồ họa để hiển thị trạng thái của giải pháp.
Ngoài ra, chúng ta có thể phân tích luồng tin nhắn trong một giải pháp nhắn tin hiện có để tạo ra một biểu đồ đại diện cho hệ thống. Có hai phương pháp cơ bản để thực hiện loại phân tích này: phân tích tĩnh và phân tích động. Phân tích tĩnh xem xét các kênh mà mỗi thành phần xuất bản và đăng ký. Nếu một thành phần xuất bản vào cùng một kênh mà một thành phần khác đăng ký, công cụ có thể vẽ một đường kết nối giữa hai thành phần. Nhiều bộ công cụ EAI, chẳng hạn như TIBCO ActiveEnterprise, lưu trữ loại thông tin này trong một kho trung tâm, làm cho việc phân tích loại này trở nên dễ dàng hơn rất nhiều. Phương pháp thứ hai sử dụng phân tích động bằng cách kiểm tra các tin nhắn cá nhân chảy qua hệ thống và đảo ngược kỹ thuật kết nối giữa các thành phần dựa trên nguồn gốc của các tin nhắn đến một thành phần cụ thể. Nhiệm vụ này trở nên đơn giản hơn rất nhiều nếu các tin nhắn trong hệ thống chứa Lịch sử Tin nhắn. Nếu không có sự hỗ trợ của Lịch sử Tin nhắn, chúng ta vẫn có thể tái cấu trúc luồng tin nhắn nếu mỗi tin nhắn chứa một trường chỉ định người gửi của tin nhắn (nhiều hệ thống bao gồm một trường như vậy để phục vụ mục đích xác thực).
Để đưa ví dụ này vào phạm vi của một chương duy nhất, chúng tôi đã phải đưa ra một số giả định đơn giản hóa. Ví dụ, cơ chế chuyển tiếp của chúng tôi không xử lý các tin nhắn đã được xếp hàng khi dịch vụ văn phòng tín dụng chính gặp sự cố - những tin nhắn này sẽ vẫn được giữ trong hàng đợi cho đến khi dịch vụ được khôi phục. Nhà môi giới cho vay vẫn có thể tiếp tục hoạt động vì nó liên kết các tin nhắn phản hồi đến các tin nhắn yêu cầu, nhưng các yêu cầu báo giá cho vay liên quan đến những tin nhắn "bị kẹt" sẽ không được xử lý cho đến khi dịch vụ văn phòng tín dụng chính trở lại trực tuyến. Để cải thiện thời gian phản hồi trong kịch bản chuyển tiếp, chúng tôi nên triển khai một chức năng gửi lại cho phép nhà môi giới cho vay phát hành lại các tin nhắn yêu cầu cho những tin nhắn đang tồn đọng vô thời hạn trước một dịch vụ bị lỗi. Alternatively, bộ định tuyến chuyển tiếp có thể lưu trữ tất cả các tin nhắn yêu cầu đã đến kể từ khi chức năng đúng đắn của dịch vụ được xác nhận lần cuối. Nếu phát hiện sự cố dịch vụ, bộ định tuyến có thể gửi lại tất cả các tin nhắn này vì một số trong số đó có thể chưa được xử lý đúng cách. Cách tiếp cận này có thể dẫn đến các tin nhắn yêu cầu trùng lặp (và các tin nhắn phản hồi liên quan), nhưng vì cả dịch vụ văn phòng tín dụng và nhà môi giới cho vay đều là những người nhận Idempotent, điều này không gây ra vấn đề gì - các tin nhắn phản hồi trùng lặp sẽ bị bỏ qua.
Ví dụ này chỉ chứng minh một phần nhỏ trong các chức năng quản lý hệ thống có thể được triển khai với các mẫu trong chương trước. Chẳng hạn, chúng ta có thể theo dõi lưu lượng tin nhắn giữa tất cả các thành phần, thiết lập ngưỡng hiệu suất, yêu cầu từng thành phần gửi tin nhắn trái tim, và nhiều hơn nữa. Thực tế, việc thêm quản lý hệ thống mạnh mẽ vào một giải pháp nhắn tin phân tán có thể đòi hỏi công sức thiết kế và triển khai nhiều như (hoặc hơn) so với giải pháp ban đầu.
bởi Jonathan Simon
Thật dễ dàng để tách rời bản thân khỏi một bộ sưu tập lớn các mẫu hoặc một ngôn ngữ mẫu. Các mẫu là sự trừu tượng hóa một ý tưởng dưới dạng tái sử dụng. Thường thì, chính tính chất rất tổng quát của các mẫu khiến chúng trở nên hữu ích nhưng cũng làm cho chúng trở nên khó nắm bắt. Đôi khi, điều tốt nhất để giúp hiểu các mẫu là một ví dụ thực tế – không phải một kịch bản giả định về những gì có thể xảy ra, mà là những gì thực sự xảy ra và những gì sẽ xảy ra.
Chương này áp dụng các mẫu để giải quyết vấn đề bằng quy trình khám phá. Hệ thống mà chúng tôi thảo luận là một hệ thống giao dịch trái phiếu mà tôi đã làm việc trong hai năm, từ thiết kế ban đầu đến sản xuất. Chúng tôi khám phá các kịch bản và vấn đề đã gặp phải và cách để giải quyết chúng bằng các mẫu. Điều này bao gồm quy trình quyết định chọn một mẫu cũng như cách kết hợp và điều chỉnh các mẫu để phù hợp với nhu cầu của hệ thống. Tất cả đều được thực hiện với sự xem xét các yếu tố gặp phải trong các hệ thống thực, bao gồm yêu cầu kinh doanh, quyết định của khách hàng, yêu cầu kiến trúc và kỹ thuật, và tích hợp hệ thống kế thừa. Mục đích của cách tiếp cận này là cung cấp một hiểu biết rõ ràng hơn về chính các mẫu thông qua ứng dụng thực tiễn.
Một ngân hàng đầu tư lớn ở Phố Wall bắt đầu xây dựng một hệ thống định giá trái phiếu nhằm đơn giản hóa quy trình làm việc của bộ phận giao dịch trái phiếu. Hiện tại, các nhà giao dịch trái phiếu phải gửi giá cho một số lượng lớn trái phiếu đến nhiều nơi giao dịch khác nhau, mỗi nơi có giao diện người dùng riêng. Mục tiêu của hệ thống là giảm thiểu các chi tiết phức tạp trong việc định giá tất cả các trái phiếu kết hợp với các chức năng phân tích nâng cao cụ thể cho thị trường trái phiếu trong một giao diện người dùng độc lập duy nhất. Điều này có nghĩa là tích hợp và giao tiếp với nhiều thành phần qua các giao thức truyền thông khác nhau. Luồng cấp cao của hệ thống trông như thế này:
Luồng tổng thể

Đầu tiên, dữ liệu thị trường được đưa vào hệ thống. Dữ liệu thị trường là dữ liệu liên quan đến giá và các thuộc tính khác của trái phiếu, đại diện cho những gì mọi người sẵn sàng mua và bán trái phiếu trên thị trường tự do. Dữ liệu thị trường ngay lập tức được gửi đến bộ phận phân tích để điều chỉnh dữ liệu. Phân tích đề cập đến các chức năng toán học cho các ứng dụng tài chính nhằm điều chỉnh giá cả và các thuộc tính khác của trái phiếu. Đây là các chức năng chung sử dụng các biến đầu vào để điều chỉnh kết quả của chức năng cho một trái phiếu cụ thể. Ứng dụng khách sẽ chạy trên mỗi máy tính bàn của nhà giao dịch sẽ cấu hình bộ phận phân tích cho từng nhà giao dịch, kiểm soát các chi tiết của phân tích cho mỗi trái phiếu mà nhà giao dịch đang định giá. Khi các phân tích được áp dụng cho dữ liệu thị trường, dữ liệu đã được điều chỉnh sẽ được gửi đến các sàn giao dịch khác nhau, nơi các nhà giao dịch từ các công ty khác có thể mua hoặc bán trái phiếu.
Với cái nhìn tổng quan về dòng dữ liệu trong hệ thống, chúng ta có thể tiếp cận một số vấn đề kiến trúc mà chúng ta gặp phải trong quá trình thiết kế. Hãy xem xét những gì chúng ta biết cho đến nay. Các nhà giao dịch cần một ứng dụng rất phản hồi nhanh trên cả hệ thống Windows NT và trạm làm việc Solaris. Do đó, chúng tôi đã quyết định triển khai ứng dụng khách như một khách hàng dày đặc Java vì tính độc lập với nền tảng của nó và khả năng phản hồi nhanh chóng với đầu vào của người dùng và dữ liệu thị trường. Ở phía máy chủ, chúng tôi đang kế thừa các thành phần C++ cũ mà hệ thống của chúng tôi sẽ sử dụng. Các thành phần dữ liệu thị trường giao tiếp với cơ sở hạ tầng nhắn tin TIBCO Information Bus (TIB).
Chúng tôi đang kế thừa các thành phần sau:
Máy chủ Cung cấp Dữ liệu Thị trường: Xuất bản dữ liệu thị trường đến TIB.
Động cơ Phân tích: Thực hiện phân tích trên dữ liệu thị trường đến và phát sóng dữ liệu thị trường đã được sửa đổi đến TIB.
Máy chủ đóng góp: Thực hiện tất cả các giao tiếp với các sàn giao dịch. Các sàn giao dịch là các thành phần bên thứ ba không được ngân hàng kiểm soát.
Hệ thống con Dữ liệu Thị trường Di sản

Hệ thống Contribution Di sản

Chúng ta cần quyết định cách mà các hệ thống con riêng biệt (khách hàng nặng Java, dữ liệu thị trường và đóng góp) sẽ giao tiếp với nhau. Chúng ta có thể để khách hàng nặng giao tiếp trực tiếp với các máy chủ kế thừa, nhưng điều đó sẽ yêu cầu quá nhiều logic kinh doanh trên khách hàng. Thay vào đó, chúng ta sẽ xây dựng một cặp cổng Java để giao tiếp với các máy chủ kế thừa: cổng giá cho dữ liệu thị trường và cổng đóng góp để gửi giá tới các địa điểm giao dịch. Điều này sẽ đạt được sự đóng gói tốt cho logic kinh doanh liên quan đến các lĩnh vực này. Các thành phần hiện tại trong hệ thống được hiển thị bên dưới. Các kết nối được đánh dấu là "???" cho thấy rằng chúng ta vẫn chưa chắc chắn về cách một số thành phần sẽ giao tiếp.
Hệ thống và các thành phần của nó

Câu hỏi giao tiếp đầu tiên là làm thế nào để tích hợp client dày Java và hai thành phần gateway Java nhằm trao đổi dữ liệu. Hãy xem bốn kiểu tích hợp được đề xuất trong cuốn sách này: Chuyển File, Cơ sở Dữ liệu Chia sẻ, Gọi Thủ tục Từ xa và Nhắn tin. Chúng ta có thể loại trừ Cơ sở Dữ liệu Chia sẻ ngay lập tức vì chúng ta muốn tạo một lớp trừu tượng giữa client và cơ sở dữ liệu, và chúng ta không muốn có mã truy cập cơ sở dữ liệu trong client. Chuyển File cũng có thể bị loại trừ, vì độ trễ tối thiểu là cần thiết để đảm bảo rằng các mức giá hiện tại được gửi đến các địa điểm giao dịch. Điều này để lại cho chúng ta sự lựa chọn giữa Gọi Thủ tục Từ xa và Nhắn tin.
Nền tảng Java cung cấp hỗ trợ tích hợp sẵn cho cả Gọi Thủ Tục Từ Xa và Nhắn Tin. Tích hợp theo kiểu RPC có thể đạt được bằng cách sử dụng Gọi Hàm Từ Xa (RMI), CORBA hoặc Enterprise JavaBeans (EJB). Dịch vụ Nhắn Tin Java (JMS) là API chung cho tích hợp kiểu nhắn tin. Cả hai kiểu tích hợp này đều dễ dàng được triển khai trong Java.
Vậy, cái nào sẽ hoạt động tốt hơn cho dự án này, Gọi Thủ tục Từ xa hay Nhắn tin? Chỉ có một instance của cổng giá cả và một instance của cổng đóng góp trong hệ thống, nhưng thường có nhiều client dày kết nối đồng thời với các dịch vụ này (một cho mỗi giao dịch viên trái phiếu đang đăng nhập tại một thời điểm cụ thể). Hơn nữa, ngân hàng muốn hệ thống định giá này trở thành một hệ thống tổng quát có thể được sử dụng trong các ứng dụng khác. Vì vậy, bên cạnh một số lượng client dày không xác định, còn có thể có một số lượng ứng dụng khác không xác định sử dụng dữ liệu định giá từ các cổng.
Một ứng dụng thick client (hoặc ứng dụng khác sử dụng dữ liệu giá) có thể dễ dàng sử dụng RPC để gọi đến các cổng để lấy dữ liệu giá và thực hiện xử lý. Tuy nhiên, dữ liệu giá sẽ được công bố liên tục, và một số khách hàng chỉ quan tâm đến một số dữ liệu nhất định, vì vậy việc truyền tải dữ liệu liên quan đến các khách hàng phù hợp kịp thời có thể gặp khó khăn. Các khách hàng có thể kiểm tra các cổng, nhưng điều đó sẽ tạo ra nhiều overhead. Sẽ tốt hơn nếu các cổng cung cấp dữ liệu cho các khách hàng ngay khi dữ liệu có sẵn. Tuy nhiên, điều này sẽ yêu cầu mỗi cổng theo dõi xem khách hàng nào hiện đang hoạt động và muốn dữ liệu cụ thể nào; sau đó, khi một mẩu dữ liệu mới trở nên có sẵn (điều này sẽ xảy ra nhiều lần mỗi giây), cổng sẽ cần phải thực hiện một RPC đến từng khách hàng quan tâm để truyền dữ liệu cho khách hàng đó. Lý tưởng nhất, tất cả các khách hàng nên được thông báo đồng thời, vì vậy mỗi RPC cần được thực hiện trong một luồng đồng thời riêng. Điều này có thể hoạt động, nhưng đang trở nên rất phức tạp rất nhanh.
Giao tiếp giúp đơn giản hóa vấn đề này rất nhiều. Với Giao tiếp, chúng ta có thể định nghĩa các kênh riêng biệt cho các loại dữ liệu giá khác nhau. Sau đó, khi một cổng nhận được một mảnh dữ liệu mới, nó sẽ thêm một thông điệp chứa dữ liệu đó vào Kênh Xuất bản-Đăng ký cho loại dữ liệu đó. Trong khi đó, tất cả các khách hàng quan tâm đến một loại dữ liệu nhất định sẽ lắng nghe trên kênh cho loại đó. Bằng cách này, các cổng có thể dễ dàng gửi dữ liệu mới đến bất kỳ ai quan tâm mà không cần biết có bao nhiêu ứng dụng lắng nghe hoặc chúng là gì.
Khách hàng vẫn cần có khả năng kích hoạt hành vi trong các cổng. Vì chỉ có hai cổng, và khách hàng có thể chặn trong khi phương thức được gọi đồng bộ, nên các cuộc gọi từ khách hàng tới cổng có thể được triển khai khá dễ dàng bằng cách sử dụng RPC. Tuy nhiên, vì chúng ta đã sử dụng nhắn tin cho việc giao tiếp từ cổng đến khách hàng, nên nhắn tin có thể cũng là một cách tốt để triển khai giao tiếp từ khách hàng đến cổng.
Do đó, tất cả các giao tiếp giữa các cổng và các khách hàng sẽ được thực hiện thông qua nhắn tin. Vì tất cả các thành phần đều được viết bằng Java, JMS là một sự lựa chọn dễ dàng cho hệ thống nhắn tin. Điều này thực sự tạo ra một Bus Tin nhắn hoặc một kiến trúc sẽ cho phép các hệ thống tương lai tích hợp với hệ thống hiện tại với ít hoặc không có thay đổi nào đối với cơ sở hạ tầng nhắn tin. Bằng cách này, chức năng kinh doanh của ứng dụng có thể dễ dàng được sử dụng bởi các ứng dụng khác mà ngân hàng phát triển.
Các thành phần Java giao tiếp với JMS

JMS chỉ đơn giản là một đặc tả, và chúng ta cần quyết định về một hệ thống nhắn tin tuân thủ JMS. Chúng ta đã quyết định sử dụng IBM MQSeries JMS vì ngân hàng là một "cửa hàng IBM", sử dụng các máy chủ ứng dụng WebSphere và nhiều sản phẩm IBM khác. Do đó, chúng ta sẽ sử dụng MQSeries, vì chúng ta đã có cơ sở hạ tầng hỗ trợ và giấy phép trang của sản phẩm.
Câu hỏi tiếp theo là cách kết nối hệ thống nhắn tin MQSeries với máy chủ đóng góp C++ độc lập và các máy chủ động cơ dữ liệu thị trường và phân tích dựa trên TIBCO. Chúng ta cần một cách để các người tiêu dùng MQSeries có thể truy cập vào các tin nhắn TIB. Nhưng làm thế nào? Có lẽ chúng ta có thể sử dụng mẫu Dịch tin nhắn để chuyển đổi các tin nhắn TIB thành tin nhắn MQSeries. Mặc dù khách hàng C++ cho MQSeries đóng vai trò là Dịch tin nhắn, nhưng việc sử dụng nó sẽ hy sinh độc lập của server JMS. Mặc dù TIBCO có API Java, nhưng kiến trúc sư và quản lý của khách hàng đã từ chối nó. Do đó, phương pháp Dịch tin nhắn phải bị bỏ qua.
Cây cầu từ máy chủ TIB đến máy chủ MQSeries yêu cầu giao tiếp giữa C++ và Java. Chúng ta có thể sử dụng CORBA, nhưng còn việc nhắn tin thì sao? Một cái nhìn sâu hơn về mẫu Biên dịch Tin nhắn cho thấy nó liên quan đến Bộ điều hợp Kênh trong việc sử dụng các giao thức giao tiếp. Tâm điểm của một Bộ điều hợp Kênh là kết nối các hệ thống không nhắn tin với các hệ thống nhắn tin. Một cặp bộ điều hợp kênh kết nối hai hệ thống nhắn tin là một Cầu Nhắn Tin.
Mục đích của một Cầu Nhắn Tin là chuyển giao các thông điệp từ hệ thống nhắn tin này sang hệ thống nhắn tin khác. Đây chính xác là những gì chúng tôi đang làm với sự phức tạp thêm của giao tiếp giữa Java và C++. Chúng tôi có thể triển khai Cầu Nhắn Tin đa ngôn ngữ bằng cách sử dụng sự kết hợp giữa Bộ Chuyển Đổi Kênh và CORBA. Chúng tôi sẽ xây dựng hai máy chủ Bộ Chuyển Đổi Kênh nhẹ, một cái bằng C++ để quản lý giao tiếp với TIB và một cái bằng Java để quản lý giao tiếp với JMS. Hai Bộ Chuyển Đổi Kênh này, mà thực tế là các Điểm Kết Nối Thông Điệp, sẽ giao tiếp với nhau qua CORBA. Giống như sự lựa chọn của chúng tôi cho MQSeries, chúng tôi sẽ sử dụng CORBA thay vì JNI, vì đây là tiêu chuẩn của công ty. Cầu nhắn tin triển khai việc mô phỏng hiệu quả việc dịch thông điệp giữa các hệ thống nhắn tin có vẻ không tương thích và các ngôn ngữ khác nhau.
Cầu Nhắn Tin Sử Dụng Bộ Kết Nối Kênh

Hình tiếp theo trên trang sau minh họa thiết kế hệ thống hiện tại, bao gồm các cổng và các thành phần khác. Đây là một ví dụ tốt về việc áp dụng mẫu. Chúng tôi đã kết hợp hai Bộ chuyển đổi Kênh với một giao thức không nhắn tin để triển khai mẫu Cầu Nhắn tin, sử dụng hiệu quả một mẫu để triển khai một mẫu khác. Thêm vào đó, chúng tôi đã thay đổi bối cảnh của các Bộ chuyển đổi Kênh để kết nối hai hệ thống nhắn tin với một giao thức dịch thuật xuyên ngôn ngữ không nhắn tin thay vì kết nối một hệ thống nhắn tin với một hệ thống không nhắn tin.
Hệ thống Hiện Tại với các Bộ Chuyển Kênh

Một chìa khóa để làm việc với các mẫu là biết không chỉ khi nào sử dụng mẫu nào, mà còn biết cách sử dụng nó một cách hiệu quả nhất. Mỗi việc triển khai mẫu phải tính đến các đặc điểm của nền tảng công nghệ cũng như các tiêu chí thiết kế khác. Phần này áp dụng quy trình khám phá tương tự để tìm cách sử dụng hiệu quả nhất Kênh Xuất-Biểu trong bối cảnh máy chủ dữ liệu thị trường giao tiếp với động cơ phân tích.
Dữ liệu thị trường thời gian thực được xuất phát từ nguồn dữ liệu thị trường, một máy chủ C++ phát sóng dữ liệu thị trường trên TIB. Nguồn dữ liệu thị trường sử dụng một Kênh Đăng-Bao cho mỗi trái phiếu mà nó công bố giá. Điều này có thể có vẻ hơi cực đoan, vì mỗi trái phiếu mới cần một kênh mới riêng. Nhưng điều này không nghiêm trọng, vì bạn thực sự không cần phải tạo kênh trong TIBCO. Thay vào đó, các kênh được tham chiếu bởi một tập hợp tên chủ đề theo cấu trúc phân cấp gọi là các chủ đề. Máy chủ TIBCO sau đó lọc một luồng tin nhắn duy nhất theo chủ đề, gửi mỗi chủ đề độc nhất đến một kênh ảo riêng. Điều này dẫn đến một kênh tin nhắn rất nhẹ.
Chúng tôi có thể tạo ra một hệ thống xuất bản trên một vài kênh, và người đăng ký có thể lắng nghe chỉ các mức giá mà họ quan tâm. Điều này sẽ yêu cầu người đăng ký sử dụng Bộ lọc Tin nhắn hoặc Người tiêu dùng Lựa chọn để lọc toàn bộ dòng dữ liệu cho các mức giá trái phiếu thú vị, quyết định xem mỗi tin nhắn có nên được xử lý khi nhận được hay không. Với việc dữ liệu thị trường được xuất bản trên các kênh chuyên biệt cho trái phiếu, người đăng ký có thể đăng ký nhận cập nhật cho một loạt các trái phiếu. Điều này thực sự cho phép người đăng ký "lọc" bằng cách lựa chọn đăng ký vào các kênh và chỉ nhận cập nhật mà họ quan tâm thay vì quyết định sau khi tin nhắn được nhận. Điều quan trọng cần lưu ý là việc sử dụng nhiều kênh để tránh lọc là một cách sử dụng không tiêu chuẩn của các kênh nhắn tin. Tuy nhiên, trong ngữ cảnh công nghệ TIBCO, chúng tôi thực sự đang quyết định xem có nên triển khai các bộ lọc riêng của mình hay sử dụng tính năng lọc kênh được tích hợp trong TIBCO hơn là việc sử dụng quá nhiều kênh.
Thành phần tiếp theo mà chúng ta cần thiết kế là động cơ phân tích, một máy chủ C++/TIB khác sẽ sửa đổi dữ liệu thị trường và phát lại nó đến TIB. Mặc dù điều này nằm ngoài phạm vi phát triển Java/JMS của chúng tôi, nhưng chúng tôi đang làm việc chặt chẽ với nhóm C++ để thiết kế nó, vì chúng tôi là khách hàng chính của động cơ phân tích. Vấn đề hiện tại là tìm cấu trúc kênh nào phát lại hiệu quả nhất dữ liệu thị trường vừa được sửa đổi.
Vì chúng ta đã có một Kênh Tin nhắn dành riêng cho mỗi trái phiếu được kế thừa từ nguồn cấp dữ liệu giá thị trường, nên sẽ hợp lý nếu thay đổi dữ liệu thị trường và phát lại dữ liệu thị trường đã được sửa đổi trên Kênh Tin nhắn dành riêng cho trái phiếu. Tuy nhiên, điều này sẽ không hoạt động vì các phân tích thay đổi giá trái phiếu là đặc thù cho từng nhà giao dịch. Nếu chúng ta phát lại dữ liệu đã được sửa đổi trên Kênh Tin nhắn trái phiếu, chúng ta sẽ phá vỡ tính toàn vẹn dữ liệu bằng cách thay thế dữ liệu thị trường tổng quát bằng dữ liệu đặc thù cho từng nhà giao dịch. Tuy nhiên, chúng ta có thể có một loại tin nhắn khác cho dữ liệu thị trường đặc thù cho từng nhà giao dịch mà chúng ta công bố trên cùng một kênh, cho phép người đăng ký quyết định tin nhắn nào họ quan tâm nhằm tránh làm hỏng tính toàn vẹn dữ liệu. Nhưng sau đó, các khách hàng sẽ phải triển khai các bộ lọc của riêng họ để tách biệt các tin nhắn cho các nhà giao dịch khác. Thêm vào đó, sẽ có sự gia tăng đáng kể về số lượng tin nhắn mà người đăng ký nhận được, đặt một gánh nặng không cần thiết lên họ.
Có hai tùy chọn:
Mỗi nhà giao dịch có một kênh riêng: Mỗi nhà giao dịch có một kênh được chỉ định cho dữ liệu thị trường đã được chỉnh sửa. Bằng cách này, dữ liệu thị trường gốc vẫn còn nguyên vẹn, và mỗi ứng dụng giao dịch có thể lắng nghe Kênh Tin Nhắn của nhà giao dịch cụ thể để nhận các bản cập nhật giá đã được chỉnh sửa.
Một kênh cho mỗi trader mỗi trái phiếu: Tạo một Kênh Tin Nhắn cho mỗi trader, mỗi trái phiếu, chỉ dành cho dữ liệu thị trường đã được điều chỉnh của trái phiếu đó. Ví dụ, dữ liệu thị trường cho trái phiếu ABC sẽ được công bố trên kênh "Trái phiếu ABC", trong khi dữ liệu thị trường đã được điều chỉnh cho trader A sẽ được công bố trên kênh "Trader A, Trái phiếu ABC", dữ liệu thị trường đã được điều chỉnh cho trader B sẽ được công bố trên kênh "Trader B, Trái phiếu ABC", và cứ như vậy.
Một Kênh cho Mỗi Trader

Mỗi kênh cho mỗi trái phiếu mỗi nhà giao dịch

Có những lợi thế và bất lợi cho mỗi phương pháp. Phương pháp theo từng trái phiếu, chẳng hạn, sử dụng nhiều Kênh Tin Nhắn hơn. Trong trường hợp xấu nhất, số lượng Kênh Tin Nhắn sẽ là tổng số trái phiếu nhân với số lượng nhà giao dịch. Chúng ta có thể đặt giới hạn tối đa về số lượng kênh sẽ được tạo ra, vì chúng ta biết rằng chỉ có khoảng 20 nhà giao dịch và họ không bao giờ định giá nhiều hơn vài trăm trái phiếu. Điều này đưa giới hạn tối đa dưới 10,000, không quá bất hợp lý so với gần 100,000 Kênh Tin Nhắn mà nguồn cấp dữ liệu giá thị trường đang sử dụng. Hơn nữa, vì chúng ta đang sử dụng TIB, và Kênh Tin Nhắn khá rẻ, nên số lượng Kênh Tin Nhắn không phải là vấn đề nghiêm trọng. Tuy nhiên, số lượng Kênh Tin Nhắn có thể gây vấn đề từ góc độ quản lý. Mỗi khi một trái phiếu được thêm vào, một kênh cho từng nhà giao dịch phải được duy trì. Điều này có thể nghiêm trọng trong một hệ thống rất năng động. Hệ thống của chúng ta, tuy nhiên, về cơ bản là tĩnh. Nó cũng có cơ sở hạ tầng để tự động quản lý Kênh Tin Nhắn. Điều này kết hợp với kiến trúc thừa kế của một thành phần cũ sử dụng phương pháp tương tự giúp giảm thiểu các bất lợi. Điều này không có nghĩa là chúng ta nên tạo ra một số lượng Kênh Tin Nhắn không cần thiết. Thay vào đó, chúng ta có thể thực hiện một phương pháp kiến trúc mà sử dụng một số lượng lớn Kênh Tin Nhắn khi có lý do.
Và có một lý do trong trường hợp này, đó là vị trí của logic. Nếu chúng ta triển khai cách tiếp cận theo từng nhà giao dịch, Engine Phân Tích cần có logic để nhóm các kênh đầu vào và đầu ra. Điều này là bởi vì các kênh đầu vào từ Engine Phân Tích là theo từng trái phiếu, và các Kênh Tin Nhắn đầu ra sẽ là theo từng nhà giao dịch, yêu cầu Engine Phân Tích phải định tuyến tất cả đầu vào phân tích từ nhiều trái phiếu cho một nhà giao dịch cụ thể đến Kênh Tin Nhắn đầu ra dành riêng cho nhà giao dịch đó. Điều này về cơ bản biến engine phân tích thành một Bộ Định Tuyến Dựa Trên Nội Dung để thực hiện logic định tuyến tùy chỉnh cho ứng dụng của chúng ta.
Theo cấu trúc Bus Tin nhắn, Engine Phân tích là một máy chủ chung có thể được sử dụng bởi nhiều hệ thống khác trong hệ thống, vì vậy chúng tôi không muốn làm rối nó với các chức năng cụ thể cho hệ thống. Mặt khác, phương pháp theo từng trái phiếu là hợp lý, vì ý tưởng về một trader sở hữu đầu ra phân tích của giá trái phiếu là một thực tiễn được công ty chấp nhận. Phương pháp theo từng trái phiếu giữ cho việc phân tách Kênh Tin nhắn của luồng dữ liệu thị trường nguyên vẹn trong khi thêm một vài Kênh Tin nhắn khác. Trước khi đến tay khách hàng, chúng tôi muốn một Bộ định tuyến Dựa trên Nội dung để kết hợp các kênh này thành một số kênh có thể quản lý được. Chúng tôi không muốn ứng dụng khách chạy trên máy tính để bàn của trader phải lắng nghe hàng ngàn hoặc hàng chục ngàn Kênh Tin nhắn. Bây giờ câu hỏi đặt ra là đặt Bộ định tuyến Dựa trên Nội dung ở đâu. Chúng tôi có thể đơn giản để Bộ chuyển đổi Kênh C++/TIB chuyển tiếp tất cả các tin nhắn đến cổng định giá trên một Kênh Tin nhắn duy nhất. Điều này không tốt vì hai lý do: Chúng tôi sẽ phân chia logic kinh doanh giữa C++ và Java, và chúng tôi sẽ mất đi lợi ích của việc có các Kênh Tin nhắn riêng biệt ở phía TIB mà cho phép chúng tôi tránh việc lọc sau này trong luồng dữ liệu. Nhìn vào các thành phần Java của chúng tôi, chúng tôi có thể đặt nó trong cổng định giá hoặc tạo một thành phần trung gian giữa cổng định giá và khách hàng.
Về lý thuyết, nếu chúng ta giữ nguyên việc tách biệt dựa trên kết nối của các Kênh Tin Nhắn cho đến tận phía client, cổng thông tin định giá sẽ phát lại thông tin định giá với cùng cấu trúc kênh như cổng thông tin định giá và Máy Phân Tích. Điều này có nghĩa là sẽ xảy ra việc sao chép tất cả các kênh TIB dành riêng cho trái phiếu trong JMS. Ngay cả khi chúng ta tạo một thành phần trung gian giữa cổng thông tin định giá và client, cổng thông tin định giá vẫn phải sao chép tất cả các kênh trong JMS. Tuy nhiên, việc triển khai logic trực tiếp trong cổng thông tin định giá cho phép chúng ta tránh việc sao chép số lượng lớn các kênh trong JMS, cho phép chúng ta tạo ra một số kênh nhỏ hơn, khoảng một kênh cho mỗi nhà giao dịch. Cổng thông tin định giá đăng ký mình qua Bộ Chuyển Đổi Kênh C++/TIB như một người tiêu thụ cho mỗi trái phiếu của từng nhà giao dịch trong hệ thống. Sau đó, cổng thông tin định giá chuyển tiếp cho mỗi client cụ thể chỉ các tin nhắn liên quan đến nhà giao dịch đó. Bằng cách này, chúng ta chỉ sử dụng một số lượng nhỏ các Kênh Tin Nhắn ở phía JMS trong khi tối đa hóa lợi ích của việc tách biệt ở phía TIB.
Dòng dữ liệu thị trường hoàn chỉnh đến khách hàng

Thảo luận về bố cục Kênh Tin Nhắn là một ví dụ tốt về việc tích hợp các mẫu là quan trọng như thế nào. Mục tiêu là tìm ra cách sử dụng hiệu quả các Kênh Tin Nhắn. Chỉ nói rằng bạn sử dụng một mẫu là không đủ. Bạn cần tìm ra cách tốt nhất để triển khai và tích hợp nó vào hệ thống của bạn để giải quyết các vấn đề hiện tại. Ngoài ra, ví dụ này còn cho thấy các lực lượng kinh doanh đang hoạt động. Nếu chúng tôi có thể triển khai logic kinh doanh trong bất kỳ thành phần nào của mình, chúng tôi có thể đã chọn phương pháp theo từng nhà giao dịch và thực hiện một cách tiếp cận tổng thể đơn giản hơn với ít kênh hơn rất nhiều.
Bây giờ chúng ta đã biết cách thức giao tiếp giữa các thành phần Java/JMS và các thành phần C++/TIBCO, và đã thấy một số cấu trúc Kênh Tin Nhắn, chúng ta cần quyết định loại Kênh Tin Nhắn JMS nào mà các thành phần Java nên sử dụng để giao tiếp. Trước khi chúng ta có thể chọn giữa các Kênh Tin Nhắn khác nhau có sẵn trong JMS, hãy xem qua luồng thông điệp cấp cao của hệ thống. Chúng ta có hai cổng (giá cả và đóng góp) giao tiếp với khách hàng. Dữ liệu thị trường chảy đến khách hàng từ cổng giá cả, cổng này gửi dữ liệu đến cổng đóng góp. Ứng dụng khách hàng gửi tin nhắn đến cổng giá cả để thay đổi các phân tích đang được áp dụng cho mỗi trái phiếu. Cổng đóng góp cũng gửi tin nhắn đến ứng dụng khách hàng để thông báo trạng thái cập nhật giá đến các sàn giao dịch khác nhau.
Luồng Tin Nhắn Hệ Thống

Thông số JMS mô tả hai loại Kênh Tin nhắn: Hàng đợi (Kênh Điểm-Đến-Điểm) và Chủ đề (Kênh Phát-Hành-Đăng-Ký). Hãy nhớ rằng lý do sử dụng phát-hành-đăng-ký là để cho phép tất cả các người tiêu thụ quan tâm nhận được một tin nhắn, trong khi lý do sử dụng điểm-đến-điểm là để đảm bảo rằng chỉ một người tiêu thụ đủ điều kiện nhận được một tin nhắn cụ thể.
Nhiều hệ thống sẽ đơn giản phát sóng thông điệp đến tất cả các ứng dụng khách, để mỗi ứng dụng khách cá nhân tự quyết định xem có xử lý một thông điệp cụ thể hay không. Điều này sẽ không hoạt động cho ứng dụng của chúng tôi, vì một số lượng lớn thông điệp dữ liệu thị trường đang được gửi đến mỗi ứng dụng khách. Nếu chúng tôi phát sóng các cập nhật dữ liệu thị trường đến những nhà giao dịch không quan tâm, chúng tôi sẽ lãng phí không cần thiết các chu kỳ xử lý của khách hàng để quyết định xem có xử lý một cập nhật dữ liệu thị trường hay không.
Các Kênh Điểm-Đến-Điểm ban đầu nghe có vẻ là một lựa chọn tốt, vì các khách hàng đang gửi tin nhắn đến các máy chủ độc nhất và ngược lại. Nhưng đó là một yêu cầu kinh doanh rằng các nhà giao dịch có thể đăng nhập vào nhiều máy tính cùng một lúc. Nếu một nhà giao dịch đăng nhập tại hai trạm làm việc cùng lúc và một bản cập nhật giá theo kiểu điểm-đến-điểm được gửi đi, chỉ một trong hai ứng dụng khách sẽ nhận được tin nhắn. Điều này là do chỉ có một người tiêu dùng trên Kênh Điểm-Đến-Điểm có thể nhận được một tin nhắn cụ thể (xem hình ở trang tiếp theo). Hãy lưu ý rằng chỉ có ứng dụng khách đầu tiên trong mỗi nhóm ứng dụng của nhà giao dịch nhận được tin nhắn.
Tin nhắn Điểm-đến-Điểm cho Cập nhật Giá

Chúng tôi có thể giải quyết vấn đề này bằng cách sử dụng Danh sách Người Nhận, điều này phát hành tin nhắn đến một danh sách những người nhận dự kiến, đảm bảo chỉ có các khách hàng trong danh sách người nhận mới nhận được tin nhắn. Bằng cách sử dụng mẫu này, hệ thống có thể tạo ra các danh sách người nhận với tất cả các phiên bản ứng dụng của khách hàng liên quan đến mỗi nhà giao dịch. Gửi một tin nhắn liên quan đến một nhà giao dịch cụ thể sẽ gửi tin nhắn đến mỗi ứng dụng trong danh sách người nhận. Điều này đảm bảo tất cả các phiên bản ứng dụng của khách hàng liên quan đến một nhà giao dịch cụ thể sẽ nhận được tin nhắn. Nhược điểm của cách tiếp cận này là nó đòi hỏi một lượng lớn logic thực hiện để quản lý người nhận và phân phối tin nhắn.
Danh sách người nhận cho cập nhật giá

Dù rằng có thể làm cho phương pháp point-to-point hoạt động, hãy xem liệu có cách nào tốt hơn. Bằng cách sử dụng các Kênh Publish-Subscribe, hệ thống có thể phát sóng các tin nhắn trên các kênh cụ thể cho nhà giao dịch thay vì các kênh cụ thể cho ứng dụng khách. Bằng cách này, tất cả các ứng dụng khách xử lý tin nhắn cho một nhà giao dịch duy nhất sẽ nhận và xử lý tin nhắn (xem hình dưới đây).
Nhắn tin Đăng-Tin cho Cập nhật Giá

Nhược điểm của việc sử dụng Kênh Xuất Bản-Đăng Ký là việc xử lý tin nhắn duy nhất không được đảm bảo với các thành phần máy chủ. Có thể có nhiều thể hiện của một thành phần máy chủ được khởi tạo và mỗi thể hiện có thể xử lý cùng một tin nhắn, có thể gửi ra các giá không hợp lệ.
Ghi nhớ luồng thông điệp của hệ thống, chỉ có một hướng giao tiếp duy nhất là thỏa mãn với mỗi Kênh Thông điệp. Giao tiếp từ máy chủ đến khách hàng với mô hình xuất bản-theo dõi là thỏa mãn, trong khi giao tiếp từ khách hàng đến máy chủ thì không, và giao tiếp từ khách hàng đến máy chủ với mô hình điểm-điểm thì thỏa mãn, trong khi giao tiếp từ máy chủ đến khách hàng thì không. Vì không cần thiết phải sử dụng cùng một Kênh Thông điệp ở cả hai hướng, chúng ta có thể sử dụng mỗi Kênh Thông điệp chỉ theo một hướng. Giao tiếp từ khách hàng đến máy chủ sẽ được triển khai với mô hình điểm-điểm, trong khi giao tiếp từ máy chủ đến khách hàng sẽ được triển khai với mô hình xuất bản-theo dõi. Bằng cách sử dụng sự kết hợp này của các Kênh Thông điệp, hệ thống sẽ được hưởng lợi từ giao tiếp trực tiếp với các thành phần máy chủ bằng cách sử dụng thông điệp điểm-điểm và tính chất đa dạng của mô hình xuất bản-theo dõi mà không có bất kỳ nhược điểm nào.
Luồng Thông Điệp với Các Loại Kênh

Các mẫu là công cụ, và các bộ sưu tập mẫu là hộp công cụ. Chúng giúp giải quyết các vấn đề. Một số người nghĩ rằng các mẫu chỉ hữu ích trong thiết kế. Theo phép ẩn dụ về hộp công cụ, điều này giống như nói rằng các công cụ chỉ hữu ích khi bạn xây dựng một ngôi nhà, chứ không phải khi bạn sửa chữa nó. Thực tế là các mẫu là một công cụ hữu ích trong suốt dự án khi được áp dụng đúng cách. Trong các phần tiếp theo, chúng tôi sẽ sử dụng cùng một quy trình khám phá mẫu mà chúng tôi đã sử dụng trong phần trước để giải quyết các vấn đề trong hệ thống hiện đang hoạt động của chúng tôi.
Các nhà giao dịch muốn các ô trong bảng nhấp nháy khi nhận được dữ liệu thị trường mới cho một trái phiếu, rõ ràng chỉ ra các thay đổi. Khách hàng Java nhận được các tin nhắn với dữ liệu mới, điều này kích hoạt cập nhật bộ nhớ đệm dữ liệu của khách hàng và cuối cùng là sự nhấp nháy trong bảng. Vấn đề là các bản cập nhật đến khá thường xuyên. Ngăn xếp luồng GUI đang trở nên quá tải và cuối cùng làm đông cứng khách hàng, vì nó không thể phản hồi lại sự tương tác của người dùng. Chúng ta sẽ giả định rằng việc nhấp nháy đã được tối ưu hóa và tập trung vào dòng dữ liệu của các tin nhắn thông qua quy trình cập nhật. Một cuộc khám phá dữ liệu hiệu suất cho thấy ứng dụng khách đang nhận được vài bản cập nhật mỗi giây; hai bản cập nhật có thể xảy ra cách nhau chưa đầy một mili giây. Hai mẫu có vẻ như có thể giúp làm chậm dòng tin nhắn là Bộ tổng hợp và Bộ lọc tin nhắn.
Một suy nghĩ đầu tiên là triển khai một Bộ Lọc Tin Nhắn để kiểm soát tốc độ dòng tin nhắn bằng cách loại bỏ các bản cập nhật được nhận trong một khoảng thời gian ngắn sau tin nhắn tham chiếu. Ví dụ, giả sử rằng chúng ta sẽ bỏ qua các tin nhắn trong vòng 5 mili giây với nhau. Bộ Lọc Tin Nhắn có thể lưu trữ thời gian của tin nhắn chấp nhận cuối cùng và loại bỏ bất kỳ tin nhắn nào được nhận trong vòng 5 mili giây tiếp theo. Trong khi các ứng dụng khác có thể không chịu đựng được việc mất dữ liệu đến mức độ như vậy, điều này hoàn toàn có thể chấp nhận được trong hệ thống của chúng ta do tần suất cập nhật giá.
Bộ lọc thông điệp dựa trên thời gian

Vấn đề với phương pháp này là không phải tất cả các trường dữ liệu đều được cập nhật cùng một lúc. Mỗi trái phiếu có khoảng 50 trường dữ liệu được hiển thị cho người dùng, bao gồm cả giá. Chúng tôi nhận ra rằng không phải mọi trường đều được cập nhật trong mỗi tin nhắn. Nếu hệ thống bỏ qua các tin nhắn liên tiếp, nó có thể sẽ vứt bỏ những dữ liệu quan trọng.
Mẫu khác mà chúng ta quan tâm là Aggregator. Aggregator được sử dụng để quản lý sự hòa hợp của nhiều tin nhắn liên quan thành một tin nhắn duy nhất, có khả năng giảm lưu lượng tin nhắn. Aggregator có thể giữ một bản sao dữ liệu trái phiếu từ tin nhắn đã được tổng hợp đầu tiên, sau đó chỉ cập nhật các trường mới hoặc đã thay đổi từ các tin nhắn kế tiếp. Cuối cùng, dữ liệu trái phiếu đã được tổng hợp sẽ được gửi trong một tin nhắn tới khách hàng. Hiện tại, hãy giả sử rằng Aggregator sẽ gửi một tin nhắn mỗi 5 mili giây giống như Bộ Lọc Tin Nhắn. Sau này, chúng ta sẽ khám phá một phương án thay thế khác.
Người tập hợp dữ liệu với các cập nhật thành công một phần

Bộ tổng hợp, như bất kỳ mẫu nào khác, không phải là một giải pháp hoàn hảo; nó có những ưu điểm và nhược điểm cần được khám phá. Một nhược điểm tiềm tàng là việc triển khai một bộ tổng hợp sẽ giảm lượng lưu lượng tin nhắn rất nhiều trong trường hợp của chúng tôi chỉ nếu nhiều tin nhắn đến trong một khoảng thời gian tương đối ngắn liên quan đến cùng một trái phiếu. Tuy nhiên, chúng tôi sẽ không đạt được gì nếu khách hàng Java nhận được cập nhật cho chỉ một trường trên tất cả các trái phiếu của các nhà giao dịch. Ví dụ, nếu chúng tôi nhận được 1.000 tin nhắn trong một khoảng thời gian xác định với bốn trái phiếu quan tâm, chúng tôi sẽ giảm lưu lượng tin nhắn từ 1.000 xuống còn bốn tin nhắn trong khoảng thời gian đó. Ngược lại, nếu chúng tôi nhận được 1.000 tin nhắn trong cùng một khoảng thời gian với 750 trái phiếu quan tâm, chúng tôi sẽ giảm lưu lượng tin nhắn từ 1.000 xuống 750 tin nhắn: tương đối ít lợi ích cho lượng nỗ lực bỏ ra. Một phân tích nhanh về các bản cập nhật tin nhắn cho thấy rằng khách hàng Java nhận được nhiều tin nhắn cập nhật các trường của cùng một trái phiếu và do đó là các tin nhắn liên quan. Vì vậy, Bộ tổng hợp thực sự là một quyết định đúng đắn.
Điều còn lại là xác định cách mà Aggregator sẽ nhận biết khi nào gửi một tin nhắn mà nó đã tổng hợp. Mẫu này mô tả một vài thuật toán để Aggregator biết khi nào gửi tin nhắn. Các thuật toán này bao gồm việc khiến Aggregator gửi nội dung của nó sau một khoảng thời gian nhất định đã trôi qua, sau khi tất cả các trường cần thiết trong bộ dữ liệu đã được hoàn thành, và những cái khác. Vấn đề với tất cả các phương pháp này là Aggregator, chứ không phải là khách hàng, đang kiểm soát dòng tin nhắn và khách hàng, chứ không phải dòng tin nhắn, là nút thắt chính trong trường hợp này.
Điều này là do Bộ Tập Hợp (Aggregator) giả định rằng các người tiêu dùng của các thông điệp đã được xóa (ứng dụng khách trong trường hợp này) là Người Tiêu Dùng Dựa Trên Sự Kiện (Event-Driven Consumers), hay những người tiêu dùng dựa vào các sự kiện từ một nguồn bên ngoài. Chúng tôi cần biến ứng dụng khách thành một Người Tiêu Dùng Kiểm Tra (Polling Consumer), hay một người tiêu dùng liên tục kiểm tra xem có thông điệp nào không, để ứng dụng khách có thể kiểm soát luồng thông điệp. Chúng tôi có thể làm điều này bằng cách tạo một luồng nền (background thread) liên tục duyệt qua tập hợp các trái phiếu (bonds) và cập nhật cũng như thông báo bất kỳ thay đổi nào đã xảy ra kể từ lần lặp trước đó. Bằng cách này, ứng dụng khách kiểm soát thời gian nhận thông điệp, và do đó, đảm bảo rằng nó sẽ không bao giờ bị quá tải với các thông điệp trong các thời kỳ cập nhật cao. Chúng tôi có thể dễ dàng triển khai điều này bằng cách gửi một Thông Điệp Lệnh (Command Message) tới Bộ Tập Hợp, khởi xướng một cập nhật. Bộ Tập Hợp sẽ phản hồi bằng một Thông Điệp Tài Liệu (Document Message) chứa tập hợp các trường đã được cập nhật mà ứng dụng khách sẽ xử lý.
Sự lựa chọn giữa Aggregator và Bộ lọc Thông điệp rõ ràng là một quyết định dựa hoàn toàn vào yêu cầu kinh doanh của hệ thống chúng ta. Mỗi phương pháp đều có thể giúp chúng ta giải quyết vấn đề hiệu suất, nhưng việc sử dụng Bộ lọc Thông điệp sẽ giải quyết vấn đề với cái giá phải trả là tính toàn vẹn dữ liệu của hệ thống.
Với việc hiệu suất của đèn nhấp nháy đã được khắc phục, chúng tôi hiện đang trong quá trình sản xuất. Một ngày, toàn bộ hệ thống bị sập. MQSeries gặp sự cố, kéo theo nhiều thành phần khác cũng bị sập. Chúng tôi gặp khó khăn với vấn đề này trong một thời gian và cuối cùng đã truy tìm được nguyên nhân trở lại hàng đợi thư chết của MQSeries (một cách triển khai của Kênh Thư Chết). Hàng đợi lớn lên đến mức làm sập toàn bộ máy chủ. Sau khi khám phá các thông điệp trong hàng đợi thư chết, chúng tôi phát hiện tất cả đều là thông điệp dữ liệu thị trường đã hết hạn. Điều này do "người tiêu thụ chậm", hoặc những người tiêu thụ không xử lý thông điệp đủ nhanh. Trong khi các thông điệp đang chờ được xử lý, chúng sẽ hết thời gian chờ (xem mẫu Hết Hạn Thông Điệp) và được gửi đến Kênh Thư Chết. Số lượng thông điệp dữ liệu thị trường hết hạn quá mức trong hàng đợi thư chết là một dấu hiệu rõ ràng cho thấy dòng thông điệp quá lớn - các thông điệp hết hạn trước khi ứng dụng mục tiêu có thể tiêu thụ chúng. Chúng tôi cần phải khắc phục dòng thông điệp, và chúng tôi quay sang các mẫu để giúp làm chậm dòng thông điệp.
Nút thắt cổ chai

Một bước đi hợp lý ban đầu là khám phá việc giải quyết vấn đề này với Aggregator, vì chúng tôi gần đây đã sử dụng mẫu này để giải quyết vấn đề tỷ lệ kiểm soát dữ liệu thị trường nhấp nháy tương tự. Thiết kế hệ thống phụ thuộc vào ứng dụng khách để ngay lập tức chuyển tiếp các tin nhắn cập nhật dữ liệu thị trường đến các sàn giao dịch. Điều này có nghĩa là hệ thống không thể chờ để thu thập các tin nhắn và tổng hợp chúng, vì vậy Aggregator phải bị bỏ qua.
Có hai mô hình khác giải quyết vấn đề tiêu thụ tin nhắn đồng thời: Người tiêu dùng cạnh tranh và Người phân phối tin nhắn. Bắt đầu với Người tiêu dùng cạnh tranh, lợi ích của mô hình này là xử lý song song các tin nhắn đến. Điều này được thực hiện bằng cách sử dụng nhiều người tiêu dùng trên cùng một kênh. Chỉ có một người tiêu dùng xử lý mỗi tin nhắn đến, để lại cho những người khác để xử lý các tin nhắn tiếp theo. Tuy nhiên, Người tiêu dùng cạnh tranh sẽ không hoạt động cho chúng tôi, vì chúng tôi đang sử dụng các Kênh Công bố-Đăng ký trong giao tiếp từ máy chủ đến khách hàng. Người tiêu dùng cạnh tranh trên một Kênh Công bố-Đăng ký có nghĩa là tất cả người tiêu dùng xử lý cùng một tin nhắn đến. Điều này dẫn đến nhiều công việc hơn mà không có lợi ích và hoàn toàn bỏ lỡ mục tiêu của mô hình. Cách tiếp cận này cũng phải được từ bỏ.
Trình phân phối thông điệp mô tả một cách tiếp cận mà bạn thêm một số người biểu diễn vào một nhóm. Mỗi người biểu diễn có thể chạy một luồng thực thi riêng. Một người tiêu dùng chính lắng nghe Kênh Thông điệp và phân công thông điệp cho một người biểu diễn không được chiếm dụng trong nhóm, sau đó ngay lập tức quay lại lắng nghe trên kênh. Điều này đạt được lợi ích xử lý song song của Người tiêu dùng Cạnh tranh nhưng hoạt động trên các Kênh Xuất bản-Đăng ký.
Bộ điều phối tin nhắn trong bối cảnh

Việc triển khai điều này trong hệ thống của chúng tôi là đơn giản. Chúng tôi tạo ra một MessageListener duy nhất gọi là Dispatcher, chứa một tập hợp các MessageListeners khác gọi là Performers. Khi phương thức onMessage của Dispatcher được gọi, nó sẽ chọn một Performer trong tập hợp để thực sự xử lý thông điệp. Kết quả là một listener thông điệp (Dispatcher) luôn trả về ngay lập tức. Điều này đảm bảo một luồng xử lý thông điệp ổn định bất kể tốc độ luồng thông điệp. Điều này hoạt động tương đương trên một Kênh Publish-Subscribe như trên một Kênh Point-to-Point. Với cơ sở hạ tầng này, các thông điệp có thể được nhận bởi ứng dụng khách với hầu như bất kỳ tốc độ nào. Nếu ứng dụng khách vẫn chậm trong việc xử lý thông điệp sau khi nhận chúng, ứng dụng khách có thể xử lý việc xử lý chậm và dữ liệu thị trường có thể đã lỗi thời thay vì các thông điệp hết hạn trong Kênh Thông điệp JMS.
Sự cố được thảo luận trong phần này và cách khắc phục bằng cách sử dụng Trình dịch Thông điệp là một ví dụ tuyệt vời về giới hạn của việc áp dụng các mẫu thiết kế. Chúng tôi đã gặp phải vấn đề hiệu suất dựa trên một sai sót trong thiết kế đã ngăn cản khách hàng xử lý thông điệp song song. Việc áp dụng các mẫu đã giảm thiểu vấn đề đáng kể nhưng không hoàn toàn khắc phục được nó, vì vấn đề thực sự là khách hàng trở thành một điểm nghẽn. Điều này không thể được khắc phục bằng hàng nghìn mẫu thiết kế. Sau đó, chúng tôi đã giải quyết vấn đề này bằng cách tái cấu trúc kiến trúc dòng thông điệp để định tuyến thông điệp trực tiếp từ cổng định giá đến cổng đóng góp. Vì vậy, các mẫu thiết kế có thể giúp thiết kế và duy trì hệ thống, nhưng chúng không nhất thiết bù đắp cho thiết kế kém ngay từ đầu.
Trong chương này, chúng tôi đã áp dụng các mẫu cho một số khía cạnh khác nhau của một hệ thống giao dịch trái phiếu, bao gồm việc giải quyết các vấn đề thiết kế ban đầu và khắc phục một sự cố sản xuất gần như đe dọa đến công việc với các mẫu. Chúng tôi cũng đã thấy những mẫu này khi chúng đã tồn tại trong các sản phẩm của bên thứ ba, các thành phần kế thừa và hệ thống nhắn tin JMS và TIBCO của chúng tôi. Quan trọng nhất, đây là những vấn đề thực sự với các loại vấn đề kiến trúc, kỹ thuật và kinh doanh mà chúng tôi gặp phải khi thiết kế và duy trì các hệ thống của riêng mình. Hy vọng rằng việc đọc về việc áp dụng các mẫu vào hệ thống này đã giúp bạn hiểu rõ hơn về các mẫu và cách áp dụng chúng vào các hệ thống của bạn.
bởi Sean Neville
Khi dữ liệu chảy qua các hệ thống và ranh giới miền thông qua các kênh nhắn tin, và khi các nhà phát triển và kiến trúc sư trở nên thành thạo hơn trong các mẫu quy định các hệ thống nhắn tin, những tiêu chuẩn và sản phẩm mới sẽ xuất hiện nhằm mở rộng khả năng tiếp cận chiến thuật của những mẫu này. Theo thời gian, các mẫu thường trở nên mạnh mẽ hơn nhưng ít thay đổi, nếu có; nhưng các chiến lược triển khai của chúng thường phát triển nhanh chóng để cho phép các nhà phát triển áp dụng chúng vào quy mô tinh vi hơn nhiều. Ví dụ, mẫu thông điệp cơ bản tìm thấy phạm vi và khả năng áp dụng của nó được mở rộng khi các đối tượng triển khai phát triển từ Chuyển đổi Dữ liệu Điện tử (EDI) sang Phần mềm trung gian Nhắn tin Độc quyền (MOM), sang các dịch vụ web dựa trên XML và SOAP, đến Ngôn ngữ Thực thi Quy trình Kinh doanh toàn cầu (BPEL) và hơn thế nữa.
Chương này xem xét tương lai của tích hợp doanh nghiệp dựa trên tin nhắn về các tiêu chuẩn mới nổi mà các nhà phát triển ứng dụng sẽ gặp phải vào giữa những năm 2000. Nhiều tiêu chuẩn trong số này hiện chưa được sử dụng phổ biến nhưng đang hình thành với sự ủng hộ rộng rãi từ ngành công nghiệp và có khả năng sẽ trở thành nền tảng cho việc triển khai các mẫu tích hợp, đặc biệt trong kiến trúc hướng dịch vụ. Hầu hết trong số chúng mở rộng các công nghệ dịch vụ web mới nổi để hỗ trợ các loại mẫu được trình bày trong cuốn sách này. Chúng tôi xem xét lý do tại sao những tiêu chuẩn này lại quan trọng liên quan đến các mẫu thiết kế, tổ chức nào đang tạo ra chúng và cách họ tiến hành, đồng thời cung cấp một tóm tắt ngắn gọn về các giải pháp kỹ thuật cho tích hợp quy trình kinh doanh mà một vài tiêu chuẩn dịch vụ web và Java đầy hứa hẹn nhằm cung cấp.
Hai artefacts tinh thần cung cấp mức độ trừu tượng cao nhất trong kiến trúc phần mềm hiện nay: hướng lập trình, bao gồm lập trình hướng đối tượng, lập trình hướng dịch vụ, lập trình tái tạo, và các hình thức tương tự; và ngôn ngữ mẫu, như được tài liệu hóa trong cuốn sách này. Nếu một hướng hoặc mẫu thiết kế cụ thể cho thấy hữu ích, và nếu bối cảnh của nó thường xuyên lặp lại, các chiến thuật và chiến lược được sử dụng để triển khai mẫu đó thường trở nên rất giống nhau. Các giải pháp mẫu trên nhiều nền tảng, sản phẩm và ứng dụng thường có rất ít sự khác biệt nhưng những khác biệt ít ỏi đó thường là yếu tố làm cản trở sự phát triển, thường có bản chất ngữ nghĩa, và gây ra sự tương tác kém làm cản trở sự phức tạp của quy mô. Để mở rộng phạm vi của các ứng dụng và các mẫu mà chúng dựa vào, những khác biệt như vậy có xu hướng bị loại bỏ khỏi các sản phẩm và nền tảng thông qua các tiêu chuẩn được thống nhất chính thức.
Khi chiến thuật hoặc chiến lược triển khai của một mẫu được tiêu chuẩn hóa, mẫu đó không mất đi tính hữu dụng, không bị thay thế bởi tiêu chuẩn đó; thay vào đó, điều hoàn toàn ngược lại xảy ra. Giống như các vòng trong thân cây, một mẫu mạnh mẽ phát triển trên chính nó đến những cấp độ áp dụng ngày càng rộng hơn, tạo ra và sau đó áp dụng chính nó trong những trường hợp ngữ cảnh rộng hơn. Sự phát triển về quy mô này xảy ra vì các trường hợp riêng biệt của việc triển khai một mẫu trở nên tương tác với nhau. Lấy một ứng dụng J2EE kiểu mẫu có hướng tin nhắn làm ví dụ, một mẫu như Pipes and Filters tồn tại ở nhiều cấp độ trong ứng dụng được thiết kế bởi nhà phát triển và cũng trong sản phẩm máy chủ được sử dụng để lưu trữ ứng dụng, trong các container và dịch vụ trong máy chủ đó, trong các bộ lọc và thành phần cấu thành các hệ thống con nhắn tin, và như vậy theo cách đệ quy.
Tiêu chuẩn nhắn tin và dịch vụ Web mới nổi sẽ góp phần củng cố các mẫu trong cuốn sách này bằng cách mở rộng phạm vi cho các nhà phát triển sử dụng chúng. Các tiêu chuẩn như BPEL và Độ tin cậy Dịch vụ Web (WS-Reliability) sẽ lan truyền phạm vi của những mẫu này vượt ra ngoài các bit, các ngôn ngữ, các sản phẩm và ra khỏi đó vào những sự kết hợp ngày càng hữu ích trong các vòng tròn sử dụng ca trường và yêu cầu tập trung vào con người và hệ thống. Các nhà phát triển ứng dụng có thể ngừng sử dụng các mẫu như Nhận diện Tương quan để khớp các phản hồi tin nhắn thô với các người gửi của chúng và có thể bắt đầu sử dụng mẫu tương tự đó để tương quan các thành phần quy trình bao gồm nhiều người gửi và nhận tin nhắn bất đồng bộ. Nếu không có lợi ích của các tiêu chuẩn nhắn tin, một nhà phát triển Java có thể triển khai Bộ định tuyến Tin nhắn ở mức mã để kiểm tra nội dung của các tin nhắn XML riêng lẻ nhằm chuyển tiếp chương trình tin nhắn đến một dịch vụ hoặc bộ lọc cụ thể. Các tiêu chuẩn quy trình làm việc và vũ điệu mới nổi sẽ cho phép nhà phát triển đó áp dụng kiến thức của mình về mẫu Bộ định tuyến Tin nhắn ở mức trừu tượng cao hơn để định tuyến quy trình làm việc giữa các thành phần quy trình, nơi mà các hiện vật chiến thuật là các thành phần quy trình kinh doanh thay vì các đoạn thô của các tài liệu XML. Nói cách khác, các nhà phát triển ứng dụng có thể ngừng lãng phí thời gian quý báu để kết nối các giao thức và bắt đầu việc kết nối các quy trình kinh doanh và dịch vụ qua các ranh giới miền.
Tính hữu ích của các mẫu thiết kế và lập trình hướng đối tượng trong việc phát triển các hệ thống tinh vi tỉ lệ thuận với khả năng của nhà phát triển ứng dụng trong việc phụ thuộc vào các chiến lược và chiến thuật triển khai chung, có thể tương tác với nhau. Ngày nay, các chiến lược làm việc với mẫu nhắn tin trong J2EE có thể bao gồm việc sử dụng JMS, JCA hoặc JAX-RPC; ngày mai, các chiến lược mà các nhà phát triển ứng dụng sử dụng có thể liên quan đến việc sử dụng công nghệ dựa trên mô hình, các kịch bản dựa trên lược đồ, khía cạnh, hoặc ý định, và bất kỳ sự chuyển biến nào trong các chiến thuật triển khai chỉ làm tăng tầm quan trọng của các mẫu, nếu định nghĩa ngữ cảnh của mẫu và các tiêu chuẩn liên quan được áp dụng một cách thích hợp. Các tiêu chuẩn cung cấp cách tốt nhất mà chúng tôi hiện biết để thực thi những điểm chung này nhằm mở rộng sự thành thạo của kiến trúc sư phần mềm về các mẫu thiết kế.
Trái ngược với những hoài nghi phổ biến, các tiêu chuẩn không được phát triển trong một môi trường nhà cung cấp tách biệt khỏi quá trình phát triển ứng dụng thực tiễn. Chúng được thiết kế để thống nhất và cải thiện các phương pháp triển khai mà các nhà phát triển ứng dụng đã khám phá và phát triển. Bằng cách áp dụng các mẫu thiết kế trong cuốn sách này, bạn có thể đang góp phần vào việc phát triển một tiêu chuẩn ngay cả khi bạn không trực tiếp tham gia vào một nhóm làm việc về thông số kỹ thuật cụ thể. Các tổ chức và liên minh giám sát các nhóm làm việc về thông số kỹ thuật không phải lúc nào cũng làm tốt việc công nhận và tiếp nhận các phương pháp triển khai, nhưng đó chính là ý định.
Các tiêu chuẩn chính thức ra đời khi một nhà phát minh hoặc nhóm nhà phát minh đưa ra một đề xuất chính thức cho một tổ chức tiêu chuẩn. Thông thường, điều này yêu cầu phải có tư cách thành viên trong tổ chức tiêu chuẩn. Mỗi tổ chức tiêu chuẩn có quy trình riêng để định hình các đề xuất thành một tiêu chuẩn, và tất cả thành viên đều bị ràng buộc bởi các quy tắc đó. Các quy trình thường liên quan đến việc thành lập một nhóm làm việc hoặc ủy ban để phát triển thêm các thông số kỹ thuật dưới sự giám sát và phê duyệt cuối cùng của ban quản lý tổ chức. Quyền sở hữu trí tuệ và chính sách cấp phép thường là những vấn đề nóng trong các tổ chức này và có thể khác nhau giữa các tổ chức tiêu chuẩn và thậm chí giữa các nhóm làm việc trong các tổ chức tiêu chuẩn.
Dưới đây là cái nhìn về các tổ chức tiêu chuẩn chính liên quan đến việc tạo ra các tiêu chuẩn nhắn tin và dịch vụ Web đang nổi:
W3C: Tổ chức World Wide Web Consortium (http://www.w3c.org) phát triển nhiều công nghệ web cơ bản, được sử dụng làm nền tảng bởi các tổ chức tiêu chuẩn khác. Tổ chức này được quản lý bởi một đội ngũ quốc tế gồm các nhà nghiên cứu và kỹ sư, bao gồm một nhóm lớn các nhà cung cấp, nhà cung cấp nội dung, chính phủ, phòng thí nghiệm nghiên cứu và các thực thể khác. W3C sử dụng một quy trình xem xét mở và hợp tác trong các nhóm làm việc và sau đó là công khai, dẫn đến những phiên bản dài nhưng nói chung là chất lượng cao. Các công nghệ được phát triển thông qua W3C thường không bị ràng buộc bởi các yêu cầu sở hữu trí tuệ từ các thành viên. Các công nghệ của W3C bao gồm SOAP và WSDL cũng như tất cả các thông số cụ thể của XML cốt lõi. Nhóm làm việc về Biên đạo W3C nhiều khả năng sẽ giải quyết các thông số quy trình kinh doanh mâu thuẫn và cung cấp cơ sở xác định cho việc tích hợp sử dụng dịch vụ web.
OASIS: Một trong số vài tổ chức xây dựng trên các công nghệ của W3C là Tổ chức Phát triển các Tiêu chuẩn Thông tin Cấu trúc, hay OASIS (http://www.oasis-open.org). Được thành lập để phát triển các hướng dẫn cho việc phát triển SGML, tổ chức phi lợi nhuận này hiện tập trung vào việc thúc đẩy việc áp dụng các tiêu chuẩn kinh doanh điện tử toàn cầu. Các ủy ban kỹ thuật của OASIS đang sản xuất nhiều tiêu chuẩn dịch vụ Web mới nổi, như ebXML và WS-Reliability. OASIS cũng điều hành cổng thông tin xml.org.
WS-I: Tổ chức Đảm bảo Tương tác Dịch vụ Web (WS-I) (http://www.ws-i.org) nhằm mục đích đảm bảo rằng các công nghệ và tiêu chuẩn dịch vụ web phù hợp để tạo điều kiện cho các sự hợp tác kinh doanh theo cách tổng quát và tương tác. Tổ chức này thúc đẩy các giao thức và thực tiễn dịch vụ web có thể áp dụng trên nhiều hệ thống, nền tảng và ngôn ngữ khác nhau. Một chiến thuật chính trong việc đạt được những mục tiêu này là Hồ sơ Cơ bản WS-I, hồ sơ này xác định tập hợp các tiêu chuẩn dịch vụ web cùng với số phiên bản của chúng; trong hồ sơ đầu tiên, những tiêu chuẩn này bao gồm XML Schema 1.0, SOAP 1.1, WSDL 1.1 và UDDI 1.0 cũng như các quy tắc quy định cách thức chúng nên được sử dụng cùng nhau. Do vậy, WS-I có ý định đóng vai trò thống nhất trong việc đảm bảo rằng các nhà cung cấp khác nhau tham gia vào phát triển dịch vụ web có thể hợp tác với nhau theo cách mang lại lợi ích cho các nhà phát triển ứng dụng. Tổ chức này được thành lập và quản lý bởi các công ty cung cấp dịch vụ web hàng đầu, bao gồm Microsoft, IBM, BEA Systems, Oracle và những công ty khác.
JCP: Quy trình Cộng đồng Java (JCP) (http://www.jcp.org) sản xuất các liên kết ngôn ngữ Java và API J2EE cho các công nghệ như các tiêu chuẩn dịch vụ web và nhắn tin được phát triển bởi các tổ chức khác. Do Sun Microsystems dẫn dắt, JCP từ trước đến nay không phải là một quy trình mở; mặc dù nó sử dụng các nhóm chuyên gia và quy trình đề xuất tương tự như các tổ chức tiêu chuẩn khác, quyền sở hữu trí tuệ thường được giữ lại bởi Sun và cấp phép cho các nhà cung cấp nền tảng Java và J2EE với một khoản phí. Hầu hết các nhóm chuyên gia JSR cũng do các kỹ sư của Sun lãnh đạo. Mặc dù thiếu sự cởi mở của các tổ chức khác, JCP đã hưởng lợi từ sự tập trung mà Sun cung cấp, ít bị cản trở bởi các chương trình nghị sự bên ngoài.
Liên minh Nhà Cung Cấp Tạm Thời: Trong cuộc đua thiết lập quyền kiểm soát đối với các phần của công nghệ dịch vụ web mới nổi, đặc biệt là cho mục đích tích hợp doanh nghiệp, những đối thủ truyền thống như IBM và Microsoft đã trong một số trường hợp hợp tác để công bố các chuẩn mà không nộp những tác phẩm đó cho bất kỳ cơ quan tiêu chuẩn nào. Nhiều đặc tả WS-* thuộc nhóm này. Thường thì, các tiêu chuẩn được phát triển thông qua các liên minh nhà cung cấp cuối cùng trở thành các đơn nộp cho các tổ chức tiêu chuẩn; BPEL đầy hứa hẹn, chẳng hạn, đã trải qua giai đoạn đầu đời như một sáng tạo của Microsoft và IBM trước khi được nộp cho OASIS. Sự quan tâm giữ lại quyền sở hữu trí tuệ dường như là động lực cho việc làm việc theo cách tạm thời. Những đặc tả này đạt được khả năng tương tác mà không có sự mở cho việc cấp phép, điều này thường là đủ cho các nhà phát triển ứng dụng tích hợp các nền tảng phổ biến như những nền tảng do Microsoft và IBM sản xuất, mặc dù việc liệu những tác phẩm này có thực sự là "chuẩn mở" hay không là điều đáng tranh luận.
Không chỉ hài lòng với việc ảnh hưởng đến lập trình hướng đối tượng, phân decompoision cấu trúc và mô hình miền, Aristotle còn một cách tinh nghịch đặt ra một trong những câu hỏi hùng biện có ảnh hưởng nhất từng làm phiền lòng kiến trúc phần mềm: Liệu thế giới chủ yếu là một loạt các quá trình, hay là một loạt các đối tượng?
Tiêu chuẩn nhắn tin đáp lại với một câu trả lời xứng đáng của một đồ đệ Zen: có. Thế giới là một loạt các đối tượng mà những đặc điểm quan trọng nhất của chúng thường là các quá trình mà qua đó chúng tương tác và liên hệ với các đối tượng khác. Thường thì những hành vi của một đối tượng liên quan đến các đối tượng khác, chứ không phải thành phần bên trong của nó, mới là điều quan trọng nhất. Trong lĩnh vực dịch vụ Web và tích hợp doanh nghiệp, góc nhìn lai giữa đối tượng/quá trình này được gọi là thành phần quy trình kinh doanh. Thành phần quy trình kinh doanh thống nhất một loạt các dịch vụ thành một đơn vị logic tương tác với các đơn vị tương tự khác thông qua việc nhắn tin để đạt được các luồng logic và dữ liệu có khả năng mở rộng cao và linh hoạt. Sự hợp nhất của các quy trình, đối tượng và mô hình tương tác thành một thành phần quy trình kinh doanh là tương lai của nhắn tin theo như nhiều nhà cung cấp dịch vụ Web và cơ quan tiêu chuẩn nhìn nhận.
Thành phần quy trình là một cái nhìn tổng quát về một tập hợp các dịch vụ có liên quan đặc biệt đến tích hợp doanh nghiệp. Lấy một ví dụ không kỹ thuật, một con người có thể lái xe, và cả con người lẫn chiếc xe đều là những hệ thống phức tạp riêng biệt; tuy nhiên, góc nhìn quy trình của con người và chiếc xe xem chúng như một thành phần đơn lẻ được định nghĩa bởi những tương tác giữa chúng và không tập trung vào thành phần của cả con người lẫn chiếc xe tách rời khỏi sự tương tác giữa chúng. Hơn nữa, góc nhìn thành phần quy trình mô tả các tương tác của thành phần đơn lẻ đó với những thành phần khác trên đường, một lần nữa không quan tâm đến thành phần nội tại của các phương tiện khác hoặc người lái. Điều này không giống như chỉ đơn thuần trình bày một giao diện bên ngoài, vì nó cũng bao gồm các quy tắc điều chỉnh hành vi giữa các lần sử dụng các giao diện.
Thành phần quy trình kinh doanh, như xuất hiện trong các tiêu chuẩn, là một thành phần duy nhất mà bên trong bao gồm một tập hợp các dịch vụ Web và một định nghĩa về cách thức các thông điệp chảy vào và ra khỏi chúng. Các dịch vụ Web và các điểm đích thông điệp khác là các khối xây dựng được sử dụng để tạo thành các thành phần lớn hơn, trong đó các tương tác tuân theo các mẫu thông điệp cả trong việc tạo thành thành phần quy trình và kết nối nhiều thành phần quy trình thành một ứng dụng đều theo các mẫu thông điệp. Các tiêu chuẩn quy trình kinh doanh giải quyết mối tương quan của các thông điệp giữa các dịch vụ Web nhằm tạo ra các luồng thực thi và bao gồm các hành vi liên quan đến lỗi, giao dịch và trao đổi dữ liệu.
Một ví dụ kinh doanh kỹ thuật hơn được minh họa trong hình bên dưới, trong đó quy trình xử lý một đơn đặt hàng được thực hiện bởi một thành phần bao gồm nhiều hoạt động dịch vụ.
Thành phần Quy trình Kinh doanh Phơi bày một Điểm đích Đơn lẻ Thay mặt cho Nhiều Dịch vụ Web được Choreographed Nội bộ.

Ví dụ bao gồm các đặc điểm và hoạt động sau:
Mỗi hoạt động trong thành phần Quy trình Đặt hàng Mua là một hoạt động có sẵn trên loại cổng của một dịch vụ Web, và các dịch vụ Web khác nhau mà cung cấp các hoạt động này có thể nằm trên các máy chủ từ xa trong các cơ sở sản xuất của đối tác.
Khi một đơn đặt hàng được nhận, bốn hoạt động được khởi động đồng thời, nhưng một số hoạt động có các phụ thuộc cần được giải quyết đồng bộ (các mũi tên chấm trong hình minh hoạ chỉ ra các phụ thuộc).
Hai phụ thuộc cụ thể cho thấy rằng hợp đồng vận chuyển và chi phí bảo hiểm là cần thiết để tính toán chi phí cuối cùng và rằng một hợp đồng bảo hiểm ràng buộc phải được nhận trước khi nhà sản xuất cam kết nguồn lực cho lịch trình sản xuất.
Khi tất cả các hoạt động dịch vụ đã hoàn thành bất đồng bộ, đơn đặt hàng đã được xử lý. Thay vì yêu cầu khách hàng nhắn tin phải tương tác với tất cả các dịch vụ này một cách riêng lẻ và quản lý các phụ thuộc giữa chúng - tức là, thay vì yêu cầu khách hàng tạo ra một triển khai Quản lý Quy trình - thành phần quy trình sẽ cung cấp một điểm cuối mạng duy nhất thay mặt cho tất cả các dịch vụ và quản lý tất cả các thông điệp và phụ thuộc giữa các dịch vụ theo cách nội bộ, đơn giản hóa các nhiệm vụ của khách hàng.
Thành phần quy trình Đặt Hàng lại được liên kết với một thành phần quy trình kinh doanh khác, Thành phần Xử lý Hóa đơn.
Bốn sáng kiến tiêu chuẩn đáng được xem xét trong lĩnh vực thành phần quy trình kinh doanh và tích hợp: sáng kiến ebXML, hai đề xuất cạnh tranh gọi là Ngôn ngữ Thực thi Quy trình Kinh doanh và Giao diện Biên đạo Dịch vụ Web, và một tập hợp các đặc tả cá nhân được kết nối thông qua tiền tố WS mà giải quyết các phần của cùng một chức năng theo cách hơi hẹp hơn, cụ thể hơn.
Ngay cả trước khi sự phổ biến bùng nổ của SOAP và WSDL, nhiều nhà tư tưởng sáng tạo trong các dự án hợp tác kinh doanh và tích hợp B2B đã nhìn thấy cần thiết phải phát triển một hạ tầng mở, an toàn và có khả năng tương tác cho việc trao đổi thông tin kinh doanh sử dụng tin nhắn XML. Nhiều tiêu chuẩn và sáng kiến cụ thể được phát triển dưới nhãn hiệu Kinh doanh Điện tử sử dụng Ngôn ngữ Đánh dấu Mở rộng (ebXML) đã giải quyết nhu cầu đó, và khi các công nghệ như SOAP trở nên phổ biến, ebXML đã phát triển để bao gồm và xây dựng dựa trên chúng. Các sáng kiến ebXML được quản lý chung qua OASIS và tổ chức Liên Hợp Quốc UN/CEFACT. UN/CEFACT là nhóm toàn cầu đã đưa tiêu chuẩn EDI vào thế giới, và ebXML theo nhiều cách đại diện cho giai đoạn hợp logic tiếp theo trong sự tiến hóa của EDI.
Nhiều đặc tả cụ thể cấu thành ebXML, bao gồm các chủ đề như cách mà các doanh nghiệp quảng bá quy trình kinh doanh của họ và tìm kiếm những quy trình của các đối tác tiềm năng, cách mà các đối tác thống nhất và khởi động giao tiếp, việc sử dụng các sổ đăng ký để hỗ trợ việc khám phá và khởi tạo các cuộc trò chuyện kinh doanh, và hành vi của cơ sở hạ tầng nhắn tin cần thiết để hỗ trợ những cuộc trò chuyện này. Điều này, đặc biệt là yếu tố cuối cùng, đã thu hút được một lượng lớn sự chú ý, và trong khi nó tận dụng các đặc tả ebXML khác, nó cũng có thể được xem xét một cách riêng biệt, điều này rất hữu ích cho việc tập trung vào các mẫu nhắn tin.
ebMS không hoàn toàn "mới nổi" như một số tiêu chuẩn khác được đề cập ở đây, vì nó đã đạt được thành công đáng kể như một phương tiện tích hợp quy trình kinh doanh, mở rộng các hệ thống EDI và mở rộng SOAP để cung cấp độ tin cậy và bảo mật cho các dịch vụ Web. Được phát triển bởi OASIS trong vòng ba năm bắt đầu từ năm 1999, ebMS cũng đang chứng tỏ ảnh hưởng của nó trong việc phát triển các tiêu chuẩn quy trình kinh doanh khác.
Mục tiêu của ebMS là tạo điều kiện thuận lợi cho việc trao đổi thông điệp kinh doanh trong một khung XML, nhưng khung này bao gồm việc sử dụng các tải trọng thông điệp không nhất thiết phải là XML - tải trọng có thể ở bất kỳ định dạng nào, bao gồm cả các định dạng EDI truyền thống cũng như các định dạng nhị phân. Do đó, ebMS có thể đóng gói các hệ thống nhắn tin hiện có và phục vụ như một công nghệ cầu nối linh hoạt, bao gồm một tập hợp các triển khai Bộ dịch Thông điệp, điều này đặc biệt hữu ích trong việc mở rộng việc tích hợp đến các extranet và giao tiếp B2B giữa các đối tác kinh doanh. Một nguồn quan trọng các trường hợp sử dụng cho ebMS là sự kết nối của các hệ thống MOM độc quyền giữa các doanh nghiệp khác nhau, và đã có rất nhiều thử nghiệm giữa các nhà cung cấp và các nhà phát triển để xác minh tính tương tác này. Điều quan trọng đối với ebMS là nó hỗ trợ các hệ thống EDI kế thừa, cho phép các doanh nghiệp tận dụng các khoản đầu tư lâu dài vào EDI trong khi bù đắp những thiếu sót của EDI bằng cách tích hợp các tính năng của Web và XML.
Trong khi ebMS là một phiên bản tương thích của EDI, thì nó cũng là một cải tiến tinh vi của các dịch vụ dựa trên SOAP tiêu chuẩn. Các truyền tải XML được sử dụng trong hệ thống ebMS bao gồm các bao SOAP có chứa các tiêu đề SOAP cụ thể cho ebMS để ghi lại các định danh tin nhắn duy nhất, dấu thời gian, chữ ký số và một bản kê khai cung cấp siêu dữ liệu về tải trọng của tin nhắn. Do đó, ebMS sử dụng cơ chế Tiêu đề SOAP để thực hiện các mẫu định tuyến tin nhắn và nhiều mẫu điểm cuối nhắn tin, chẳng hạn như Bộ nhận Idempotent và những mẫu khác liên quan đến việc đảm bảo giao hàng theo thứ tự.
ebMS truyền tải các tải trọng của nó bằng cách sử dụng tiêu chuẩn SOAP với đính kèm để đính kèm tải trọng vào phong bì SOAP theo cách tương tự như các tệp đính kèm được thêm vào các thông điệp email. Các tải trọng này, một lần nữa, không có giới hạn định dạng nào được đặt lên chúng: Tải trọng của một thông điệp có thể là dữ liệu XML, dữ liệu nhị phân, hoặc các tham chiếu dựa trên liên kết đến dữ liệu ngoại vi, và v.v. Hơn nữa, mỗi tải trọng có thể có chữ ký số riêng của nó, và các biện pháp xác thực và phân quyền bổ sung có thể được cung cấp bởi các nhà thực hiện ebMS.
Một tin nhắn ebMS được cấu thành từ các tin nhắn SOAP có kèm theo tệp đính kèm.

Hệ thống chuyển phát tin nhắn bất đồng bộ là mặc định, nhưng chuyển phát đồng bộ cũng có thể thực hiện thông qua ebMS. Cơ chế xử lý lỗi cũng khá tinh vi, và tùy thuộc vào việc triển khai, nó có thể cung cấp thông tin SOAP Fault cùng với các thông báo lỗi cụ thể về payload.
Để cung cấp độ tin cậy, yếu tố quan trọng của một triển khai ebMS được gọi là Trình xử lý Tin nhắn ebXML duy trì các tin nhắn ở phía gửi của một cuộc trò chuyện. Các nhà phát triển có thể cung cấp các khai báo ngữ nghĩa như "chỉ một lần và duy nhất" và "lưu và chuyển tiếp" cho các tin nhắn cá nhân hoặc cho các nhóm tin nhắn. ebMS chỉ định các dịch vụ để quản lý việc giao hàng theo thứ tự và quản lý; dịch vụ cuối cùng này được triển khai thông qua Dịch vụ Trạng thái Tin nhắn, đại diện cho một Bus Kiểm soát. Nó cung cấp khả năng yêu cầu trạng thái của một tin nhắn đã được gửi trước đó vào hệ thống ebMS, mà bên dưới hoạt động thông qua một triển khai Lịch sử Tin nhắn và các mẫu liên quan.
Thông tin thêm về ebXML có thể được tìm thấy tại http://www.ebxml.org/. Tài liệu cụ thể về ebMS có thể được tìm thấy tại http://www.ebxml.org/specs/ebMS2.pdf.
Một tiêu chuẩn nổi bật đang xuất hiện để định nghĩa các thành phần quy trình kinh doanh và sự tương tác của chúng là Ngôn ngữ Thực thi Quy trình Kinh doanh cho Dịch vụ Web (BPEL4WS). Tên gọi thường được phát âm là bee-pelor, thậm chí tệ hơn, bee-pel cho những ai yếu đuối. Tiêu chuẩn này đại diện cho sự hợp nhất của hai đề xuất đối địch từ IBM và Microsoft. Ngôn ngữ Luồng Dịch vụ Web của IBM (WSFL) đã chỉ định một phương pháp tạo ra và kết nối các điểm cuối dịch vụ để biên đạo các quy trình làm việc dịch vụ web, trong khi XLANG của Microsoft cung cấp một cú pháp và mô hình phát triển để tạo ra các thành phần quy trình làm việc như đã thực hiện trong sản phẩm máy chủ BizTalk của Microsoft. BPEL4WS cung cấp một chút từ cả hai: Nó bao gồm một cú pháp để xây dựng các quy trình từ các dịch vụ hiện có và để mô tả các giao diện quy trình nhằm mục đích liên kết chúng lại với nhau trong các quy trình làm việc lớn hơn. Nó được tạo ra bởi một sự hợp tác tạm thời giữa BEA Systems, IBM và Microsoft, và đã được trình lên OASIS.
Thiết kế của BPEL yêu cầu liên kết các dịch vụ Web, được gọi là đối tác, để đưa các thông điệp XML vào và ra khỏi các kho lưu trữ thông điệp, được gọi là các container, theo các quy tắc được gọi là hoạt động. Một tập hợp logic của các liên kết dịch vụ, các container thông điệp và các hoạt động tạo thành một thành phần quy trình kinh doanh duy nhất. Đặc tả BPEL về cơ bản định nghĩa một Trình quản lý Quy trình, tạo ra Giấy phép Định tuyến, Người đăng ký Bền, Kênh Kiểu dữ liệu và các thành phần khác dựa trên cú pháp XML khai báo. Các nhà phát triển khai báo hành vi bằng XML (có thể với sự hỗ trợ của các công cụ trực quan) để chế tạo các thành phần quy trình kinh doanh (chẳng hạn như cái được hiển thị trong hình ở trang 630) và không cần phải lập trình tạo ra việc nhắn tin giữa các dịch vụ.
Tài liệu WSDL rất quan trọng đối với BPEL, vì thành phần BPEL sẽ bao gồm và quản lý nhiều dịch vụ Web dựa trên tài liệu WSDL của các dịch vụ đó. Quy trình kinh doanh khởi tạo và chuyển tiếp tin nhắn đến các điểm cuối dịch vụ được khai báo trong tài liệu WSDL của các dịch vụ này bằng cách sử dụng các tin nhắn được định dạng theo các khai báo tin nhắn WSDL. Cú pháp BPEL liên kết portType và các thao tác của một tập hợp dịch vụ Web bằng cách nhập các tệp WSDL của chúng và khai báo các chuỗi để sử dụng để nhận tin nhắn dịch vụ, nơi để gửi chúng, khi nào và bằng cách nào để phản hồi, khi nào để gọi các dịch vụ Web khác, và nhiều hơn nữa.
Để thiết lập mối liên kết giữa các dịch vụ, nhà phát triển ứng dụng nhập WSDL của các dịch vụ Web cấu thành thành phần và định nghĩa các mối quan hệ đối tác giữa chúng bằng cách sử dụng phần tử BPEL serviceLinkType. Phần tử này tham chiếu đến các portTypes của các dịch vụ Web liên quan trong một chu trình và các vai trò đối tác mà chúng đảm nhận liên quan đến quy trình; sau đó, nhà phát triển có thể tham chiếu đến những liên kết và vai trò đối tác này khi khai báo cách các tin nhắn nên chảy vào và ra khỏi chúng.
Sau khi tuyên bố các mối quan hệ giữa các dịch vụ, nhà phát triển sử dụng BPEL để tạo ra các container để lưu trữ các thông điệp mà các dịch vụ sử dụng làm đầu vào và đầu ra. Các container rất giống như một Kênh Kiểu Dữ liệu cho các loại thông điệp được định nghĩa trong WSDL. Tùy thuộc vào việc triển khai container cơ bản, một container cũng có thể được coi từ góc độ của kiểu tích hợp Cơ sở Dữ liệu Chia sẻ, nhưng với khả năng đóng gói tốt hơn và ngữ nghĩa cộng tác tích hợp sẵn; một container là một kho dữ liệu chia sẻ được sử dụng bởi các dịch vụ riêng biệt. Ngoài việc kết nối các container với các dịch vụ thông qua các phần tử BPEL, nội dung của một container có thể được truy cập trực tiếp qua các tiện ích mở rộng XPath.
Một thành phần BPEL tự nó đưa ra các điểm đầu vào và đầu ra của riêng mình như một giao diện duy nhất, và nó thực hiện điều này dưới dạng mà các dịch vụ Web nội bộ của nó sử dụng: thông qua WSDL. Tuy nhiên, điều này nên rõ ràng rằng WSDL của một thành phần quy trình kinh doanh hơi khác so với tài liệu WSDL của một dịch vụ Web, vì các portType của WSDL quy trình kinh doanh định nghĩa các điểm vào và ra của quy trình duy nhất đó, thay vì các phần logic riêng biệt được triển khai như các phương thức trong giao diện dịch vụ.
Hành vi của một thành phần BPEL được khai báo dưới dạng một tập hợp các hành động. Trong bất kỳ hành động cụ thể nào, một quy trình kinh doanh có thể gửi tin nhắn đến một dịch vụ (trong trường hợp này, dịch vụ web được gọi là đối tác được gọi), nhận tin nhắn từ một dịch vụ (trong trường hợp này, dịch vụ được gọi là đối tác khách hàng), trả lời một tin nhắn được gửi bởi một đối tác khách hàng, xác định xem nó có nên gửi hoặc nhận tin nhắn dựa trên một quy tắc logic nào đó, chờ đợi trong một khoảng thời gian theo lịch, báo cáo lỗi, sao chép một tin nhắn từ nơi này sang nơi khác, hoặc không làm gì cả.
Ngữ pháp BPEL XML phản ánh từng hành động cơ bản này. Một nhà phát triển sử dụng phần tử invoke để gửi tin nhắn đến một đối tác được gọi và sử dụng receive và reply để nhận và trả lời một đối tác khách hàng. Các phần tử như flow và pick chia logic thành các kênh thực hiện song song và dựa trên sự kiện. Phần tử throw hỗ trợ việc báo cáo lỗi, trong khi các phần tử wait, empty, và terminate tạm dừng hoặc dừng thực hiện. Các phần tử để cấu trúc hoạt động bao gồm while, sequence, và pick, và các điều kiện trong BPEL được khai báo bằng các câu lệnh XPath.
Khi một nhà phát triển đã tạo ra tệp XML nguồn định nghĩa các dịch vụ sẽ cấu thành một quy trình kinh doanh, khai báo các container tin nhắn mà các dịch vụ sẽ sử dụng và khai báo trình tự các thao tác liên quan trong việc trao đổi tin nhắn, anh ấy hoặc cô ấy đã sẵn sàng để triển khai thành phần quy trình kinh doanh. Đây là lúc các khía cạnh runtime của các triển khai BPEL phát huy tác dụng.
Ngoài việc hoạt động như các tuyên bố về mối quan hệ dịch vụ và luồng tin nhắn, mô tả BPEL cũng là các tệp có thể thực thi được và có thể được nạp vào một bộ điều khiển BPEL4WS. Khi điều này xảy ra, bộ điều khiển sẽ diễn giải tệp và thiết lập một loạt các cấu trúc tin nhắn cho nhà phát triển ứng dụng, kết nối các dịch vụ Web là một phần của quy trình kinh doanh. Như một triển khai Quản lý Quy trình, thời gian chạy BPEL4WS là thực thể quản lý chính điều hành và tương quan luồng tin nhắn giữa các dịch vụ. Bộ điều khiển BPEL4WS chấp nhận tất cả các tài liệu cần thiết và động thái tạo ra và quản lý cơ sở hạ tầng tin nhắn.
Đặc tả BPEL có thể được tìm thấy tại http://www-106.ibm.com/developerworks/webservices/library/ws-bpel/.
Giao diện Biên soạn Dịch vụ Web (WSCI; thường được phát âm là whiskey) giải quyết cùng một lĩnh vực vấn đề mà BPEL đang xử lý. Hai tài liệu này ban đầu là các đặc tả cạnh tranh được hỗ trợ bởi các liên minh nhà cung cấp cạnh tranh (ngoại trừ BEA, có vẻ như đang đa dạng hóa rủi ro bằng cách đóng góp cho cả hai đặc tả). WSCI được hỗ trợ bởi Sun, Intalio, SAP và BEA, và đã được gửi đến W3C. Tuy nhiên, một số nhà hỗ trợ ban đầu của WSCI hiện đang ủng hộ BPEL.
WSCI bị ảnh hưởng bởi Ngôn ngữ Mô hình Hóa Quy trình Kinh doanh (BPML), mà mặc dù không liên quan trực tiếp đến các mẫu tích hợp, nhưng vẫn đáng được đề cập vì bối cảnh lịch sử của WSCI. BPML đại diện cho các quy trình kinh doanh trong một siêu ngôn ngữ dựa trên XML được sử dụng trong mô hình hóa quy trình. Các khía cạnh quy trình làm việc của BPML phần lớn là một phần của WSCI, nhưng BPML cũng bao gồm một ký hiệu đồ họa đồng hành và ngôn ngữ truy vấn.
Giống như BPEL, WSCI nhận ra rằng tích hợp doanh nghiệp liên quan đến các cuộc hội thoại kéo dài giữa các dịch vụ tổng hợp thay vì các cuộc gọi hoạt động đơn lẻ như được giả định bởi các giao thức web dịch vụ cơ bản. WSCI cung cấp một cách để liên kết các tin nhắn dịch vụ từ nhiều hoạt động vào các quy trình tổng hợp này, đảm bảo rằng các tin nhắn được gửi hoặc nhận theo các chuỗi thích hợp, được gửi và nhận theo các quy tắc kinh doanh theo tuyên bố, được gửi theo cách giao dịch khi cần thiết, và có thể được mô tả và quản lý như một quy trình toàn cầu duy nhất. Tận dụng những lợi thế của dịch vụ web so với các giải pháp MOM độc quyền truyền thống, WSCI cũng điều chỉnh việc khám phá dịch vụ động, các giao thức khác nhau và sự phối hợp phi tập trung của quy trình làm việc.
Giống như BPEL, WSCI phụ thuộc nhiều vào việc quảng cáo các điểm cuối dịch vụ, portType, hoạt động và loại tin nhắn của WSDL. Các hành động WSCI trực tiếp ánh xạ tới các hoạt động được công khai trong WSDL của các dịch vụ trong một điệu nhảy hợp tác. Hơn nữa, cú pháp WSCI được nhúng trực tiếp trong tệp WSDL; các khai báo nằm trong một tài liệu WSDL, tài liệu này nhập khẩu các tài liệu WSDL của các dịch vụ hợp tác, hoặc trong tệp WSDL của một dịch vụ đơn lẻ mà các hoạt động của nó đang được hợp tác. Các phần tử WSCI được chứa trong phần tử định nghĩa WSDL.
Cấu trúc cơ bản của WSCI là hành động mà trong đó việc nhắn tin dịch vụ Web xảy ra. Các hành động được nhóm lại trong các phần tử quy trình để chúng được tuyên bố xảy ra tuần tự, song song, lặp lại hoặc có điều kiện. Một tập hợp các quy trình được nhóm với một khai báo giao diện; phần tử giao diện này là giao diện của thành phần quy trình, và nó được nhúng trực tiếp trong các định nghĩa WSDL của một dịch vụ Web. Nhiều phần tử hoạt động tương tự như của BPEL, và giống như các đồng nghiệp BPEL của chúng, chúng bao gồm hỗ trợ cho các biểu thức XPath.
Thông số WSCI có thể được tìm thấy tại http://wwws.sun.com/software/xml/developers/wsci/wsci-spec-10.pdf.
JCP tạo ra các API và ràng buộc ngôn ngữ Java chịu ảnh hưởng từ các tiêu chuẩn không phải Java. Đặc biệt, các tiêu chuẩn được phát triển bởi Nhóm Quản lý Đối tượng (OMG) và W3C đã được JCP chú ý. Gần đây, JCP đã chuyển hướng tiếp cận này sang các tiêu chuẩn dịch vụ Web được phát triển bởi các nhóm như WS-I, và hai JSR mới, được quảng bá rất nhiều, hiện đang được thực hiện để giải quyết các ràng buộc Java cho các thành phần quy trình kinh doanh: Định nghĩa Quy trình cho Java (JSR-207), được nộp bởi BEA Systems, và Tích hợp Doanh nghiệp Java (JSR-208), được nộp bởi Sun Microsystems. Mặc dù thoạt nhìn hai đề xuất này có thể có sự trùng lặp, nhưng thực tế chúng khá bổ sung cho nhau. JSR-207 xác định cách để các nhà phát triển nhanh chóng và dễ dàng tạo ra các thành phần nhắn tin hoặc quy trình bằng cách sử dụng siêu dữ liệu gắn liền với mã Java; JSR-208 xác định cách mà các thành phần đó sẽ tương tác với nhau, với các container, và với phần còn lại của thế giới J2EE và dịch vụ Web. Vì vậy, JSR-207 phần nào là một cái nhìn vi mô, và JSR-208 là cái nhìn vĩ mô về cách thức nhắn tin giữa các thành phần quy trình sẽ được tiêu chuẩn hóa trong Java.
Định nghĩa Quy trình cho Java (JSR-207), được nộp bởi BEA Systems, nhằm xác định siêu dữ liệu, giao diện và mô hình thời gian chạy để tạo ra các quy trình kinh doanh trong môi trường Java/J2EE. JSR rất quan trọng này nhằm mục đích xác định các phương tiện tiêu chuẩn để chế tác các thành phần quy trình kinh doanh bằng cách sử dụng ngôn ngữ Java và các chú thích siêu dữ liệu giống như Javadoc. Được đề xuất như một bổ sung cho J2EE, cơ chế này cũng có thể được sử dụng để xây dựng các triển khai Java của các sáng kiến quy trình kinh doanh như BPEL4WS, WSCI và những cái được sản xuất bởi Nhóm I làm việc về Biên đạo của W3C.
Công nghệ này xây dựng dựa trên công nghệ Siêu dữ liệu Ngôn ngữ Java (JSR-175) nhằm cung cấp cú pháp đơn giản để mô tả các quy trình kinh doanh. Siêu dữ liệu có thể được áp dụng trực tiếp vào mã nguồn Java để động thái tạo ra và kết nối các hành vi quy trình, bao gồm hỗ trợ cho việc nhắn tin không đồng bộ, thực thi song song, tương quan tin nhắn, định tuyến tin nhắn, xử lý lỗi và các hoạt động luồng phổ biến khác. Do đó, ý nghĩa của siêu dữ liệu cần phải phong phú đủ để hỗ trợ các tham số cần thiết cho bộ chứa của một thành phần để thiết lập động các cơ sở hạ tầng nhắn tin và xử lý các vấn đề được mô tả trong phần giới thiệu của Chương 5, "Xây dựng Tin nhắn," khi thành phần được triển khai.
Đáng lưu ý rằng JSR này không cần thiết để cho phép các nhà phát triển xây dựng các thành phần quy trình kinh doanh trong J2EE. Hiện tại, có thể xây dựng những quy trình như vậy, nhưng công việc này rất vất vả và yêu cầu các nhà phát triển áp dụng các mẫu thông điệp ở mức độ rất thấp, dẫn đến các quy trình công việc tốn kém trong việc duy trì. Tài liệu này nhằm mục đích đơn giản hóa việc tạo ra các thành phần quy trình để các nhà phát triển có thể áp dụng kỹ năng của họ ở mức cao hơn, tạo ra các ứng dụng mạnh mẽ hơn một cách nhanh chóng với chi phí ít tốn kém hơn trong việc phát triển và quản lý theo thời gian.
Thông tin chi tiết về định nghĩa quy trình cho Java có thể được tìm thấy tại http://www.jcp.org/en/jsr/detail?id=207.
Sun đã đề xuất Java Business Integration (JBI) trong JSR-208 với mục đích định nghĩa các giao diện nhà cung cấp dịch vụ (SPIs) để tạo ra một môi trường tích hợp kinh doanh cho các đặc tả như WSCI, BPEL4WS và công việc được sản xuất bởi Nhóm làm việc về Biên đạo W3C. JBI không đề xuất API Java mới hay chú thích mới, nhưng bao gồm một cơ chế triển khai và đóng gói mới. Thay vì thêm API cho các nhà phát triển, JBI tập trung vào hạ tầng tích hợp, và các SPIs của nó sẽ được nhìn thấy chủ yếu bởi các nhà cung cấp sản phẩm tạo ra các mô hình thành phần tin nhắn và quy trình để thực hiện công việc tích hợp trong một môi trường Java. Nhóm chuyên gia JBI nhằm mục đích theo sát sự dẫn dắt của Nhóm làm việc về Biên đạo W3C và đảm bảo rằng công việc của nhóm đó sẽ hòa nhập liền mạch vào nền tảng J2EE.
JBI có một mục tiêu khá cao cả: Lập bản đồ các hệ thống và tiêu chuẩn giao thức, tức là nhiều ngữ pháp được sử dụng để mô tả mối quan hệ giữa các quy trình, bao gồm các ngữ pháp có tính chất độc quyền và cụ thể cho từng nhà cung cấp cũng như những ngữ pháp trở thành tiêu chuẩn cho nhau và cho J2EE. Nó cung cấp một ràng buộc Java cho biên đạo tin nhắn bất kể những đặc điểm về tin nhắn và quy trình cơ sở. Nó cũng bao gồm một cơ chế đóng gói mới mở rộng đóng gói J2EE (như WAR, JAR, RAR và EAR) để hỗ trợ việc triển khai một thành phần JBI vào môi trường J2EE.
JBI thấy ba vai trò chính cần thiết để hỗ trợ các thành phần quy trình: các liên kết, máy móc, và môi trường. Liên kết liên quan đến các định dạng giao tiếp và bao gồm các định dạng tin nhắn và mạng cùng với các ánh xạ của chúng, đồng thời tạo thành một ô bao quanh các định dạng công việc như BPEL; máy móc là các container dịch vụ và quy trình chịu trách nhiệm lưu trữ và quản lý các quy trình kinh doanh; môi trường là hệ thống quản lý quy trình tổng thể kết nối các máy móc và liên kết khác nhau với nhau. JBI tập trung vào môi trường như là cốt lõi của hệ thống tích hợp và chỉ định cách mà các máy móc và liên kết tương tác với nó. Cơ chế đóng gói và triển khai JBI được thiết kế để cung cấp một phương tiện kết nối các quy trình với môi trường một cách chuẩn mực, nhưng việc tạo ra các thành phần đó thực sự nằm ngoài phạm vi của thông số kỹ thuật.
JBI coi Định nghĩa Quy trình cho Java (JSR-207) được mô tả ở trên là một cách để kết hợp các thành phần quy trình, và môi trường thực thi sẽ chứa các thành phần đó thuộc vào danh mục máy JBI. Máy đó nên triển khai Bộ Biên dịch Tin nhắn, Kích hoạt Dịch vụ, Bọc Định dạng và các mẫu khác cần thiết để làm rõ các định dạng và hành vi giao thức của chúng thông qua JBI nhằm đảm bảo rằng nó có thể tích hợp đúng cách với môi trường tích hợp.
Thông tin chi tiết về JBI có thể được tìm thấy tại http://www.jcp.org/en/jsr/detail?id=208.
Ít tham vọng hơn so với các đặc tả quy trình tích hợp đã được mô tả, một số đặc tả dịch vụ Web hiện đang nổi lên để mở rộng các dịch vụ Web dựa trên SOAP và WSDL nhằm bao gồm độ tin cậy, bảo mật, trạng thái và chất lượng dịch vụ. Thường được nhận diện bằng tiền tố WS-, các đặc tả này dựa trên các công nghệ của W3C, và mỗi đặc tả đều giải quyết một vấn đề khá cụ thể.
Thật không may, cảnh quan các tiêu chuẩn dịch vụ web đã trở nên hỗn loạn với những phiên bản cạnh tranh được các liên minh nhà cung cấp cạnh tranh hỗ trợ, và có lẽ là kết quả của sự cạnh tranh này, nhiều tiêu chuẩn trong số này hiếm khi được triển khai ngoài thực tế ngày nay. Một cuộc sàng lọc số tiêu chuẩn dường như đang đến gần. Tuy nhiên, những đặc tả này rất đáng lưu ý, vì ngôn ngữ và chiến thuật của chúng có thể chứng minh hữu ích cho các nhà phát triển ứng dụng đang áp dụng các công nghệ dịch vụ web như SOAP và WSDL vào tích hợp doanh nghiệp dựa trên nhắn tin. Những tiêu chuẩn này chắc chắn sẽ có chỗ đứng trong các sản phẩm của những nhà cung cấp đề xuất chúng, bao gồm cả IBM, BEA, Microsoft và Oracle.
Một vài thông số nổi bật hơn trong danh mục này bao gồm các yếu tố liên quan đến khả năng giao dịch, độ tin cậy, định tuyến, trạng thái hội thoại và bảo mật. Chúng được mô tả trong các trang sau.
Vì không có trạng thái và không đáng tin cậy, các giao thức và phương thức truyền tải dịch vụ Web phổ biến nhất không cung cấp chất lượng dịch vụ cần thiết cho các quy trình giao dịch. Thiếu sót này phát triển thành một vấn đề quan trọng một cách nghiêm trọng. Trên thực tế, điều đó có nghĩa là nếu một nhà phát triển muốn sử dụng cơ chế tích hợp dựa trên dịch vụ Web, họ phải phát triển hệ thống giao dịch của riêng mình trong các cơ chế tích hợp đó. Một tập hợp các cuộc gọi dịch vụ diễn ra thông qua nhắn tin bất đồng bộ phải có khả năng được nhóm lại một cách nguyên tử để các tin nhắn hoạt động như một đơn vị có thể thất bại hoặc quay lại tất cả cùng một lúc, hoặc như một đơn vị mà sự thất bại của nó có thể kích hoạt một hình thức bồi hoàn nào đó. Điều này rất phổ biến trong các hệ thống MOM sở hữu. Các đặc tả về Phối hợp Dịch vụ Web và Giao dịch Dịch vụ Web giải quyết vấn đề này cho các dịch vụ Web.
WS-Coordination, được soạn thảo bởi BEA, Microsoft và IBM, chỉ ra cách tạo ra và phân phối thông tin ngữ cảnh bởi tất cả các dịch vụ tham gia trong một luồng, ngay cả khi không đồng bộ và qua các khoảng thời gian không đều. Tài liệu mô tả một khung mở rộng để tạo ra các giao thức phối hợp các hành động của các ứng dụng và dịch vụ. Các giao thức phối hợp này hoạt động bằng cách tạo ra và đăng ký các ngữ cảnh dựa trên XML mà được phân phối với các thông điệp SOAP và được sử dụng bởi những người điều phối nằm ở tất cả các điểm cuối trong một sự tương tác.
Các ngữ cảnh như vậy có thể được sử dụng để hỗ trợ một số hành vi ứng dụng, chẳng hạn như những hành vi cần đạt được sự đồng thuận nhất quán về kết quả của các giao dịch phân tán. Do đó, đặc tả WS-Transaction sử dụng WS-Coordination để thực hiện tính khả thi phân tán qua các lần gọi dịch vụ.
WS-Transaction định nghĩa một cách để giám sát và đo lường sự thành công hoặc thất bại của mỗi hành động trong một quy trình. Thực tế, điều này có nghĩa là khi một tin nhắn SOAP đến một điểm cuối, tiêu đề SOAP chứa bối cảnh phối hợp phải được lọc và lấy ra từ tin nhắn (các triển khai có thể sử dụng mẫu Bộ lọc Nội dung và Chia để thực hiện nhiệm vụ này) và sau đó được gửi đến bộ điều phối giao dịch để giải thích.
Đoạn trích bao bì SOAP dưới đây cung cấp một ví dụ đơn giản về bối cảnh điều phối được sử dụng để thực hiện các thao tác SOAP trở nên có thể giao dịch thông qua WS-Transaction. Thông tin bối cảnh này trong tiêu đề SOAP được các điều phối viên sử dụng để đăng ký các ứng dụng nhận các sự kiện giao dịch như ghi danh, giai đoạn chuẩn bị của quá trình cam kết hai pha, thu hồi và cam kết.
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope"> <SOAP-ENV:Header> <wscoor:CoordinationContext xmlns:wscoor="http://schemas.xmlsoap.org/ws/2002/08/wscoor" xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility" xmlns:myTransactableApp="http://foo.com/baz"> <wsu:Identifier>http://foo.com/baz/bar</wsu:Identifier> <wsu:Expires>2004-12-31T18:00:00-08:00</wsu:Expires> <wscoor:CoordinationType> http://schemas.xmlsoap.org/ws/2002/08/wstx </wscoor:CoordinationType> <wscoor:RegistrationService> <wsu:Address> http://foo.com/coordinationservice/registration </wsu:Address> </wscoor:RegistrationService> <myTransactableApp:IsolationLevel> RepeatableRead </myTransactableApp:IsolationLevel> </wscoor:CoordinationContext> </SOAP-ENV:Header> <!-- SOAP BODY (snipped) --> </SOAP-ENV:Envelope>
Thông số WS-Transaction định nghĩa hai loại điều phối cho các nhà phát triển sử dụng trong ứng dụng của họ: giao dịch nguyên tử (AT) và hoạt động kinh doanh (BA).
Các giao dịch nguyên tử phù hợp khá tốt với công nghệ giao dịch phân tán truyền thống, chẳng hạn như XA. Chúng hữu ích cho các hoạt động có thời gian sống ngắn, trong đó việc khóa các tài nguyên như luồng và phần dữ liệu là chấp nhận được và trong đó việc hoàn tác tuyệt đối là hợp lý. WS-Transaction cung cấp một phương tiện để liên kết các triển khai XA độc quyền, bao gồm việc hỗ trợ cam kết hai pha, với dịch vụ web.
Một hoạt động kinh doanh thường là một quá trình kéo dài có thể bao gồm một số giao dịch nguyên tử. Việc hoàn tác toàn cầu thường không được mong muốn trong trường hợp có một điều kiện thất bại đơn lẻ trong một hoạt động kinh doanh; thay vào đó, một thất bại của một giao dịch nguyên tử trong một hoạt động kinh doanh nên thường kích hoạt một tập hợp các cuộc gọi dịch vụ và trao đổi tin nhắn khác. Những trao đổi này có thể bao gồm các kỹ thuật bồi thường để khôi phục từ lỗi một cách preserving phần lịch sử của hoạt động kinh doanh. Một ví dụ là một hoạt động kinh doanh bao gồm việc đặt vé chuyến bay, thuê xe, đặt phòng khách sạn và đặt vé xem kịch mà người dùng thực hiện trong vòng hai hoặc ba ngày. Mỗi hoạt động trong quy trình này có thể là một giao dịch nguyên tử, và nếu một trong các sự kiện gặp thất bại, hoạt động kinh doanh tổng thể của việc sắp xếp chuyến đi nên điều chỉnh thông qua bồi thường thay vì thông qua việc hoàn tác phối hợp tất cả các giao dịch nguyên tử.
Các đặc tả WS-Coordination và WS-Transaction là những nỗ lực hứa hẹn nhằm cung cấp các hành vi đáng tin cậy và phong phú trong trường hợp xảy ra lỗi trong quá trình nhắn tin dịch vụ. Khi chúng bắt đầu được áp dụng vào sản phẩm, chúng sẽ giảm bớt gánh nặng cho các nhà phát triển trong việc tạo ra khả năng giao dịch và dịch vụ ngữ cảnh xung quanh các ứng dụng dịch vụ dựa trên tin nhắn.
Thông tin về WS-Transaction có thể được tìm thấy tại http://dev2dev.bea.com/technologies/webservices/ws-transaction.jsp.
Thông thường, các tương tác dựa trên tin nhắn giữa các dịch vụ Web yêu cầu có tin nhắn đáng tin cậy và có thể đảm bảo ngay cả khi gặp sự cố về mạng, ứng dụng hoặc thành phần, và cần bao gồm các cơ chế lưu trữ và ngữ nghĩa gửi lại. Tuy nhiên, các công nghệ dịch vụ Web phổ biến nhất không cung cấp độ tin cậy như vậy; ví dụ, SOAP mà không có các cải tiến không phải là giải pháp hữu ích toàn diện trong nhiều kịch bản nhắn tin doanh nghiệp vì các ràng buộc phổ biến nhất của nó không đảm bảo đáng tin cậy việc giao hàng tin nhắn.
Để khắc phục điều này, các nhà phát triển ứng dụng thường bị buộc phải tự triển khai độ tin cậy bằng cách sử dụng khả năng mở rộng của các cơ chế dịch vụ Web như SOAP Headers. Để loại bỏ sự cần thiết cho các nhà phát triển ứng dụng thực hiện nhiệm vụ này, các tiêu chuẩn mới đang xuất hiện để giải quyết độ tin cậy của dịch vụ Web. Hai thông số cụ thể như vậy là Độ tin cậy của Dịch vụ Web (WS-Reliability) và Nhắn tin Đáng tin cậy của Dịch vụ Web (WS-ReliableMessaging). Như thường thấy trong lĩnh vực tiêu chuẩn dịch vụ Web còn non trẻ, hai tiêu chuẩn này đang cạnh tranh, được hỗ trợ bởi các nhóm nhà cung cấp khác nhau nhằm giải quyết cùng một lĩnh vực vấn đề.
WS-Reliability cung cấp các dịch vụ Web dựa trên SOAP khả năng trao đổi tin nhắn một cách bất đồng bộ với đảm bảo giao hàng, không có bản sao và với thứ tự tin nhắn. Đây là một tiêu chuẩn SOAP để quản lý sự tổng hợp và phân loại tin nhắn, và cung cấp một chiến thuật tiêu chuẩn cho việc triển khai các mẫu Đảm Bảo Giao Hàng và Tái Phân loại, среди các mẫu khác. WS-Reliability tận dụng cơ chế Header của SOAP để thêm các phần tử header như MessageHeader, ReliableMessage, MessageOrder và RMResponse vào các tin nhắn SOAP. Những phần tử này chỉ định các định danh tin nhắn như ID nhóm và số thứ tự, dấu thời gian, giá trị thời gian sống, giá trị loại tin nhắn, thông tin người gửi và người nhận, và thông tin gọi lại xác nhận. WS-Reliability được sản xuất bởi một số nhà cung cấp, bao gồm Sun, Oracle và Sonic, và đã được nộp cho OASIS. Nó đã bị ảnh hưởng nặng bởi chức năng của ebMS.
Để tuân thủ WS-Reliability, người nhận của một thông điệp SOAP phải phản hồi bằng cách gửi hoặc một lỗi hoặc một thông báo xác nhận sử dụng phần tử <RMResponse> trong tiêu đề SOAP. Nếu không nhận được thông báo xác nhận như vậy, thì người gửi sẽ gửi lại cùng một thông điệp sử dụng cùng một định danh thông điệp. Người gửi được yêu cầu phải lưu trữ thông điệp cho đến khi giá trị thời gian sống của nó hết hạn hoặc cho đến khi xác nhận hoặc thất bại xảy ra; người nhận cũng được yêu cầu phải lưu trữ thông điệp cho đến khi nó có thể được truyền tải đáng tin cậy đến lớp ứng dụng.
Để đảm bảo rằng các hành vi thông điệp chỉ xảy ra một lần duy nhất được thực thi, WS-Reliability cung cấp một cơ chế số thứ tự có thể được kích hoạt dựa trên yêu cầu của ứng dụng. Các thông điệp riêng biệt được nhóm lại với nhau có thể chia sẻ cùng một định danh nhóm nhưng sẽ quảng bá số thứ tự riêng của chúng trong tiêu đề SOAP, cho phép người nhận tái sắp xếp các thông điệp trước khi chuyển chúng cho ứng dụng.
Tài liệu về đặc tả WS-Reliability có thể được tìm thấy tại http://www.oasis-open.org/committees/documents.php?wg_abbrev=wsrm.
Thông số WS-ReliableMessaging mô tả một giao thức tương tự cho phép các tin nhắn được gửi một cách đáng tin cậy giữa các ứng dụng phân tán trong tình huống có sự cố. Giao thức được mô tả một cách độc lập, cho phép nó được triển khai bằng cách sử dụng nhiều công nghệ và ràng buộc truyền tải mạng khác nhau. Thông số này bao gồm một ràng buộc cụ thể cho SOAP. WS-ReliableMessaging được hỗ trợ bởi BEA, IBM và Microsoft, và vẫn chưa được phát hành cho một cơ quan tiêu chuẩn.
WS-ReliableMessaging hoạt động trên cùng một nguyên tắc như WS-Reliability. Nó sử dụng tương tự các thông điệp xác nhận, callback và định danh; ngụ ý việc sử dụng tương tự các bộ nhớ cache thông điệp bền vững; và cung cấp các thông điệp lỗi chi tiết. Nó đảm bảo rằng các thông điệp được gửi đi theo bất kỳ một trong bốn đảm bảo giao hàng cơ bản: Tối đa một lần, tối thiểu một lần, chính xác một lần, và theo thứ tự. Một ví dụ về chuỗi thông điệp được gửi qua WS-ReliableMessaging được minh họa bên dưới.
WS-ReliableMessaging cung cấp Giao Hàng Đảm Bảo Theo Thứ Tự thông qua một loạt các Callback Xác Nhận dựa trên các ID Độc Nhất được chèn vào phần Header của SOAP.

Một điểm khác biệt chính giữa hai tiêu chuẩn độ tin cậy cạnh tranh là WS-ReliableMessaging bao gồm việc sử dụng các tiêu chuẩn dịch vụ Web quan trọng khác, chẳng hạn như WS-Security và WS-Addressing. Trong thực tế, điều này có nghĩa là WS-ReliableMessaging sử dụng các cách diễn đạt cụ thể từ các tiêu chuẩn khác để cung cấp thông tin này, trong khi đó WS-Reliability hỗ trợ các tính năng nhưng chưa yêu cầu các hình thức cách diễn đạt đã được quy định trong các tiêu chuẩn mới khác.
Thông tin thêm về WS-ReliableMessaging có thể được tìm thấy tại http://dev2dev.bea.com/technologies/webservices/ws-reliablemessaging.jsp.
"Các cuộc trò chuyện dịch vụ web (WS-Conversation) xác định một giao thức để quản lý việc trao đổi tin nhắn bất đồng bộ có trạng thái giữa một người gửi và người nhận, thường là qua hai điểm cuối SOAP. Khác với việc dựa vào một thành phần quy trình kinh doanh bao bọc để quản lý việc trao đổi tin nhắn có trạng thái giữa nhiều đối tác, đề xuất này cung cấp một phương tiện đơn giản để hoàn thành cùng một điều giữa một khách hàng đơn và một dịch vụ đơn (nơi mà khách hàng cũng có thể là một dịch vụ)."
Giao thức này tận dụng cơ chế SOAP Header để gửi các định danh hoặc ID token cùng với các tin nhắn SOAP. Khi một cuộc hội thoại có trạng thái được bắt đầu, phần tử StartHeader được sử dụng để cung cấp một định danh cuộc hội thoại và URI callback. Các tin nhắn tiếp theo thuộc về cùng một cuộc hội thoại sử dụng ContinueHeader và CallbackHeader cho các yêu cầu và phản hồi tiếp theo, và các phần tử này sẽ bao gồm cùng một định danh được thiết lập khi cuộc hội thoại được bắt đầu.
Cơ chế SOAP Header có thể được sử dụng để triển khai những mẫu này mà không cần sử dụng các cơ chế tiêu chuẩn, mặc dù có lợi trong việc thiết lập một cơ chế chung cho các khách hàng và dịch vụ trên nhiều nền tảng. Đây là một sự chính thức hóa của các mẫu Aggregator và Composed Message Processor bằng cách sử dụng Correlation Identifier với mục đích liên kết nhiều thông điệp vào một phiên duy nhất.
Cách tiếp cận việc ngoại hóa quản lý trạng thái thông qua một thành phần quy trình hoặc biên đạo có vẻ hứa hẹn hơn cho các dự án tích hợp quy mô lớn, nơi mà vì lý do đơn giản, việc xem các dịch vụ và thành phần như những hộp đen là hữu ích. Tuy nhiên, WS-Conversation là một ví dụ cho những gì có thể thực hiện được khi có sự kiểm soát lớn hơn đối với các dịch vụ và khách hàng.
Trong khi các tiêu chuẩn như WS-ReliableMessaging, WS-Coordination và WS-Addressing cung cấp nhiều cơ chế khác nhau để xác định người gửi của một thông điệp, không có bất kỳ đặc tả nào đảm bảo rằng người gửi thực sự sở hữu danh tính mà họ tuyên bố. Các yếu tố của WS-I Basic Profile, XML Schema, SOAP, WSDL và UDDI không đề cập đến cách danh tính được xác minh và đảm bảo hoặc cách duy trì tính toàn vẹn của thông điệp. Những người đầu tiên áp dụng dịch vụ web hoặc giữ dịch vụ của họ mở và sẵn có cho tất cả mọi người hoặc phát triển các giao thức bảo mật sở hữu để lấp đầy khoảng trống này. Các phương pháp sở hữu và riêng tư đã tạo ra một sự liên kết không mong muốn giữa người gửi và người nhận thông điệp, điều này đặc biệt gây khó chịu trong các liên minh nút thông điệp không đồng bộ và kết nối lỏng lẻo.
WS-Security, còn được gọi là Ngôn ngữ Bảo mật Dịch vụ Web, là tiêu chuẩn được đề xuất để giải quyết những vấn đề này. Trong tất cả các đặc tả WS-*, nó có thể được hưởng mức độ đồng thuận rộng rãi nhất giữa các nhà cung cấp nền tảng dịch vụ web lớn. Được tạo ra bởi một liên minh gồm Microsoft, IBM và Verisign, nó hiện nay là một phần của OASIS; nó đã nhận được sự tín nhiệm từ các công ty như Sun, BEA, Intel, SAP, IONA, RSA Security và nhiều công ty khác.
WS-Security không đề xuất các công nghệ bảo mật mới, mà thay vào đó, nó kết nối SOAP và các công nghệ bảo mật hiện có. Nó cung cấp một phương tiện tổng quát, có thể mở rộng để kết hợp các token bảo mật với các tin nhắn SOAP và truyền tải các token đó đến các điểm cuối SOAP. Nó cũng xác định phương pháp tiêu chuẩn để mã hóa các token bảo mật nhị phân, chẳng hạn như chứng chỉ số và vé Kerberos, trong các tin nhắn SOAP. Nó không mô tả các giao thức cố định cụ thể mà thay vào đó thiết lập một tập hợp cơ chế tổng quát để triển khai bất kỳ số lượng giao thức bảo mật nào và kết hợp bất kỳ số lượng miền tin cậy, định dạng chữ ký và công nghệ mã hóa nào. Trong chừng mực nó có thể bao gồm việc sử dụng chứng chỉ số, hàm băm và việc thực hiện các công nghệ như PKI, Kerberos, SSL và những thứ tương tự, WS-Security đại diện cho một cách để áp dụng các tiêu chuẩn bảo mật Internet quen thuộc vào các điểm cuối SOAP.
Ngoài việc xác minh danh tính người gửi, WS-Security có thể bảo vệ tính toàn vẹn của tin nhắn, tức là bảo vệ nó khỏi những ánh mắt tò mò của trung gian trong quá trình truyền tải qua mạng bằng cách tận dụng các tiêu chuẩn W3C XML Signature và XML Encryption. Tuy nhiên, trong những trường hợp không có sự tham gia của các tác nhân trung gian và dịch vụ bên thứ ba, việc sử dụng HTTPS là một phương pháp thay thế phổ biến để bảo vệ tin nhắn SOAP trong quá trình truyền tải.
Mô hình bảo mật quy định rằng người gửi tin nhắn SOAP đưa ra một loạt các tuyên bố như danh tính của người gửi, nhóm, đặc quyền và những thứ tương tự. Các tuyên bố này được tập hợp dưới dạng một token bảo mật đã được ký. Người nhận tin nhắn có trách nhiệm xác nhận các tuyên bố. Các token và chữ ký được mang theo trong một khối Header SOAP, cụ thể là dưới phần tử tiêu đề bảo mật trong không gian tên WS-Security. Nếu có lỗi xảy ra khi người nhận xác nhận các tuyên bố, lỗi đó sẽ thuộc một trong hai loại: lỗi không được hỗ trợ, cho thấy rằng điểm cuối không hỗ trợ một token hoặc thuật toán mã hóa cụ thể nào đó, và lỗi thất bại, cho thấy hầu hết các lỗi khác, bao gồm tất cả các lỗi liên quan đến token và chữ ký không hợp lệ. Tài liệu quy định không yêu cầu rằng các lỗi thất bại luôn phải được báo cáo, vì chúng có thể là kết quả của một cuộc tấn công. Khi các lỗi được báo cáo, chúng có dạng SOAP Faults với mã lỗi được định nghĩa trong tài liệu.
Thông số kỹ thuật WS-Security có thể được tìm thấy trên các trang web của mỗi nhà cung cấp đồng biên soạn, bao gồm cả địa điểm sau tại IBM: http://www-106.ibm.com/developerworks/library/ws-secure/.
Có một số đặc tả WS-* khác được đề xuất với mức độ hỗ trợ và chấp nhận khác nhau. Một số điều này có phạm vi khá hạn chế, chẳng hạn như WS-Địa chỉ, định nghĩa các phần tử XML để xác định các điểm cuối dịch vụ Web trong các thông điệp. Đặc tả này nhằm hỗ trợ nhắn tin qua các trung gian như quản lý điểm cuối, proxy, tường lửa và cổng một cách trung lập với giao thức truyền tải. Về cơ bản, WS-Địa chỉ là một cách chuẩn để chỉ ra ai là người gửi một thông điệp ("Từ:") và ai là người nhận ("Đến:"). Nó cung cấp một phương tiện để kết nối các dịch vụ Web dựa trên SOAP vào các giải pháp Danh sách Người nhận. Vì nó cung cấp một phương tiện để chỉ định nơi để chuyển hướng một phản hồi, nó có vẻ như sẽ trở thành cách tiếp cận chuẩn cho các dịch vụ web để giải quyết các vấn đề được nêu ra trong Địa chỉ Trả về.
Một phương thức cung cấp siêu dữ liệu về các dịch vụ, Khung Chính sách Dịch vụ Web (WS-Policy) cung cấp một cú pháp để mô tả các chính sách của một dịch vụ Web. Các chính sách này bao gồm yêu cầu dịch vụ, sở thích, khả năng, và siêu dữ liệu chất lượng dịch vụ. Ngôn ngữ Khẳng định Chính sách Dịch vụ Web (WS-PolicyAssertions) đi kèm quy định một phương thức khẳng định rằng một thông điệp hoặc điểm cuối dịch vụ hỗ trợ một chính sách cụ thể. Nó liên quan đến việc điều tra các tuyên bố WS-Policy để tìm kiếm một chính sách yêu cầu cụ thể. Cuối cùng, Đính kèm Chính sách Dịch vụ Web (WS-PolicyAttachment) mô tả cách mà các tiêu chuẩn chính sách này phù hợp với các công nghệ dịch vụ Web hiện có. Nó quy định cách liên kết các biểu thức chính sách với các định nghĩa kiểu WSDL và các thực thể UDDI, và xác định cách liên kết các chính sách cụ thể về triển khai với toàn bộ hoặc một phần của portType WSDL.
Các tiêu chuẩn WS-* mới đang xuất hiện nhanh chóng khi các nhà cung cấp ráo riết formal hóa các phương pháp triển khai mà các nhà phát triển ứng dụng đang theo đuổi, đánh dấu quyền sở hữu trí tuệ giá trị của dịch vụ Web trong quá trình này. Các nhà phát triển ứng dụng thông thái sẽ theo dõi những tiêu chuẩn thú vị và chọn lọc các cách diễn đạt từ chúng khi cần thiết, nhưng cũng sẽ nhớ rằng mẫu hình và không phải cách diễn đạt thực hiện là điều quan trọng nhất để xây dựng một ứng dụng dựa trên thông điệp. Các tiêu chuẩn WS-* đang nổi lên chưa được yêu cầu cho việc triển khai các hệ thống nhắn tin doanh nghiệp tương tác, và khi chúng trở thành trở ngại hoặc phân tâm, chúng nên được dũng cảm bỏ qua cho đến khi chúng trưởng thành.
Ở mức tốt nhất, các tiêu chuẩn mở rộng khả năng của các mẫu thiết kế bằng cách đảm bảo rằng các triển khai khác nhau của cùng một mẫu có thể tương tác với nhau. Nhiều nỗ lực đang được thực hiện để mở rộng các mẫu nhắn tin thông qua các tiêu chuẩn dịch vụ web; nhiều tiêu chuẩn trong số này tập trung vào sự cấu thành và hành vi của các thành phần quy trình làm việc được gọi là các thành phần quy trình kinh doanh. Các tiêu chuẩn như BPEL, WSCI và các thông số WS-* giải quyết nhiều vấn đề được mô tả trong cuốn sách này và triển khai một số mẫu trong ngôn ngữ mẫu này.
Tuy nhiên, các câu chuyện về tiêu chuẩn mới nổi vẫn đôi khi mâu thuẫn và có thể gây nhầm lẫn. Chúng chắc chắn không phải tất cả đều đã sẵn sàng cho việc sử dụng rộng rãi. Khi áp dụng một mẫu, nhà phát triển ứng dụng nên tránh bị mắc kẹt bởi các tiêu chuẩn và thay vào đó, tập trung vào các trường hợp sử dụng cụ thể. Hãy xem xét cách mà một số tiêu chuẩn đang tiếp cận một vấn đề, và áp dụng những triển khai theo phong cách chiến thuật, phù hợp của một mẫu nếu điều đó hợp lý hoặc hữu ích trong quá trình thực hiện, bất kể cách tiếp cận đó có được tiêu chuẩn hóa trong các sản phẩm của nhà cung cấp hay không. Các nhà phát triển cũng có thể cung cấp phản hồi cho các tổ chức tiêu chuẩn để thách thức, chỉ trích và đảm bảo rằng các tiêu chuẩn trở nên hữu ích thực tiễn chứ không phải là những bài tập hàn lâm hay của nhà cung cấp. Khi các tiêu chuẩn trưởng thành, các kiến trúc sư nên khôn ngoan xem xét cách mà việc sử dụng của chúng có thể mở rộng các giải pháp tích hợp doanh nghiệp đến những cấp độ rộng hơn, ít rủi ro hơn, ít tốn kém hơn, và có sức mạnh hơn về độ tinh vi.
"[Alexander]Một Ngôn Ngữ Mẫu: Thị Trấn, Công Trình, Xây Dựng, Christopher Alexander, Sara Ishikawa và Murray Silverstein; Nhà Xuất Bản Đại Học Oxford 1977, ISBN 0195019199 Có lẽ là cuốn sách được trích dẫn nhiều nhất trong bất kỳ công trình nào liên quan đến mẫu. Tôi thực sự đã sử dụng một số mẫu của Alexander để thiết kế một ngôi nhà ven biển cho một lớp học kiến trúc nội thất. Thật thú vị khi lưu ý rằng mong muốn của Alexander trong việc phân tích kiến trúc và thiết kế thành một tập hợp các cấu trúc có thể ghép lại với nhau có thể bắt nguồn từ nghiên cứu toán học của ông. Luận văn của ông, được xuất bản dưới tên "Ghi chú về việc tổng hợp hình thức," đề cập đến một tập hợp các chương trình mà ông đã phát triển bằng mã lắp ráp IBM 7090. Do đó, sự thành công to lớn của các mẫu của Alexander trong cộng đồng phần mềm không phải là ngẫu nhiên."
"[Alpert] Bạn đồng hành về Mẫu Thiết kế Smalltalk, Sherman Alpert, Kyle Brown và Bobby Woolf; Addison-Wesley 1998, ISBN 0201184621 Một cái nhìn thứ hai về tài liệu Mẫu Thiết kế [GoF], lần này dành cho các nhà phát triển sử dụng một môi trường lập trình có thư viện lớp chung và chạy trên một máy ảo có thu gom rác. Vào thời điểm đó, đó là Smalltalk, nhưng nhiều hiểu biết cũng áp dụng cho Java và .NET/C#."
`[Hộp] .NET Cơ Bản, Tập 1: Thời gian thực thi ngôn ngữ chung, Don Box; Addison-Wesley 2002, ISBN 0201734117 Nhiều hơn tất cả những gì bạn từng muốn biết về cách hoạt động bên trong của CLR.`
[BPEL4WS] Ngôn ngữ Thực thi Quy trình Kinh doanh cho Dịch vụ Web, Phiên bản 1.0, BEA, IBM, Microsoft; Ngày 31 tháng 7 năm 2002, http://www.ibm.com/developerworks/webservices/library/ws-bpel1/Đặc tả BPEL4WS 1.0.
"[CoreJ2EE] Các mẫu Core J2EE: Thực tiễn tốt nhất và Chiến lược thiết kế (ấn bản thứ 2), Deepak Alur, John Crupi, & Dan Malks; Nhà xuất bản Prentice Hall PTR 2003, ISBN 0131422464. Một cuốn sách rất hay về các mẫu kiến trúc ứng dụng doanh nghiệp cho Java."
"[CSP] 'Giao tiếp các quá trình theo trình tự,' C. A. R. Hoare; Tạp chí Giao tiếp của ACM, 1978. Cần có quyền truy cập vào thư viện trực tuyến của ACM để xem toàn văn bài viết này."
"[Dickman] Thiết kế Ứng dụng với MSMQ, Alan Dickman; Addison-Wesley 1998, ISBN 0201325810. Cuốn sách chứa một chương tuyệt vời về "Giải pháp cho các vấn đề Giao tiếp" đề cập đến sự tương quan, người tiêu thụ theo sự kiện và tuần tự hóa đối tượng, và giải tuần tự hóa. Thật không may, tuổi tác của cuốn sách có nghĩa là tất cả các ví dụ sử dụng Visual Basic với COM hoặc C++."
"[Douglass] Mô Hình Thiết Kế Thời Gian Thực, Bruce Powel Douglass; Addison-Wesley 2003, ISBN 0201699567. Cuốn sách này chứng minh tính khả chuyển của các mẫu qua các lĩnh vực khác nhau. Một số mẫu độ tin cậy của Douglass chứng tỏ rất hữu ích trong bối cảnh nhắn tin doanh nghiệp."
"[EAA] Các mẫu kiến trúc ứng dụng doanh nghiệp, Martin Fowler; Addison-Wesley 2003, ISBN 0321127420. Cuốn sách toàn diện nhất về các mẫu kiến trúc ứng dụng cho đến nay. Mặc dù nó đề cập đến 51 mẫu, nhưng sách dễ đọc và thú vị mà không hy sinh độ chính xác kỹ thuật."
[Tài liệu cụ thể về EJB 2.0] Đặc tả Enterprise JavaBeans, phiên bản 2.0, Sun Microsystems; Ngày 14 tháng 8 năm 2001, http://java.sun.com/products/ejb/docs.html Đặc tả EJB 2.0.
[Garlan] Kiến trúc Phần mềm: Những Góc nhìn về một Ngành học Mới nổi, Mary Shaw & David Garlan; Nhà xuất bản Prentice Hall 1996, ISBN 0131829572. Cuốn sách chứa một chương tuyệt vời về các kiểu kiến trúc, bao gồm > Ống và Bộ lọc.
"[GoF] Các mẫu thiết kế: Các yếu tố của phần mềm đối tượng có thể tái sử dụng, Erich Gamma, Richard Helm, Ralph Johnson & John Vlissides; Addison-Wesley 1995, ISBN 0201633612 chắc chắn là cuốn sách được trích dẫn nhiều thứ hai trong bất kỳ công trình nào về mẫu."
"[Graham] Xây dựng Dịch vụ Web bằng Java: Hiểu về XML, SOAP và UDDI, Steve Graham, Simon Simeonov, Toufic Boubez, Glen Daniels, Doug Davis, Yuichi Nakamura, & Ryo Nyeama; SAMS Publishing 2002, ISBN 0672321815. Một cuốn sách rất hay về cách Java và các dịch vụ Web kết hợp với nhau."
"[Hapner] Hướng dẫn và Tài liệu tham khảo về API Dịch vụ Tin nhắn Java, Mark Hapner, Rich Burridge, Rahul Sharma, Joseph Fialli, & Kim Haase; Addison-Wesley 2002, ISBN 0201784726 Cách hoạt động của JMS, từ các tác giả đã viết đặc tả."
"[Hohmann] Vượt qua Kiến trúc Phần mềm: Tạo ra và Duy trì các Giải pháp Chiến thắng, Luke Hohmann; Addison-Wesley 2003, ISBN 0201775948. Luke nhắc nhở chúng ta rằng nhiều quyết định kiến trúc không chỉ được điều khiển bởi công nghệ mà còn bởi các quyết định kinh doanh, các chương trình cấp phép và nhiều yếu tố bên ngoài khác."
[JMS] Dịch vụ tin nhắn Java (JMS), Sun Microsystems; 2001-2003, http://java.sun.com/products/jms/ Giao diện lập trình ứng dụng Dịch vụ Tin nhắn Java, một phần của nền tảng Java 2, Phiên bản Doanh nghiệp (J2EE).
[JMS 1.1] Dịch vụ Tin nhắn Java (Đặc tả Dịch vụ Tin nhắn Java 1.1 của Sun), Sun Microsystems; Ngày 12 tháng 4 năm 2002, http://java.sun.com/products/jms/docs.html Đặc tả JMS 1.1.
[JTA] API Giao Dịch Java (JTA), Sun Microsystems; 20012003, http://java.sun.com/products/jta/ API Giao Dịch Java, một phần của nền tảng Java 2, Phiên bản Doanh Nghiệp (J2EE).
"Khoa học ngữ nghĩa của một ngôn ngữ đơn giản cho lập trình song song," G. Kahn, Xử lý Thông tin 74: Kỷ yếu Đại hội IFIP 74, Nhà xuất bản North-Holland, 1974
[Kaye] Các thành phần còn thiếu của dịch vụ web: Tác giả Doug Kaye; RDS Press 2003, ISBN 1881378241. Một cái nhìn mới mẻ về dịch vụ web. Thay vì phải lội qua các API, chúng ta được đọc về các nguyên tắc cốt lõi hoạt động trong kiến trúc hướng dịch vụ theo cách trung lập về công nghệ và không sử dụng thuật ngữ chuyên môn. Cuốn sách này có thể quá cao cho các nhà phát triển đang nóng lòng thực hiện gọi SOAP, nhưng nó lý tưởng cho các nhà quản lý kỹ thuật và kiến trúc sư phải giải thích những khái niệm này cho những người không chuyên.
Sách cổ điển (phiên bản gốc xuất bản năm 1978) của William Kent có tên là "Dữ liệu và Thực tế", do 1stBooks phát hành năm 2000, ISBN 1585009709, nói về lý do tại sao việc mô phỏng thực tế trong một hệ thống máy tính lại khó khăn như vậy.
"[Lewis] Ứng dụng Nhắn Tin Nâng Cao với MSMQ và MQSeries, Rhys Lewis; Que 2000, ISBN 078972023X"
**[Leyman] Quy trình sản xuất: Khái niệm và Kỹ thuật, Frank Leyman & Dieter Roller; Prentice-Hall PTR 1999, ISBN 0130217530**
Đặc điểm Nhận Diện Đa Điểm, Microsoft; Tháng 2 năm 2003, http://msdn.microsoft.com/library/en-us/msmq/msmq_about_messages_8aqv.asp Bàn về tính năng mới trong MSMQ 3.0 cho phép gửi tin nhắn đến nhiều điểm đến khác nhau.
"[Micro-Workflow] 'Micro-Workflow: Kiến trúc Quy trình Hỗ trợ Phát triển Phần mềm Hướng đối tượng Tổ hợp,' Dragos Manolescu; Đại học Illinois 2000, http://micro-workflow.com/PhDThesis/phdthesis.pdf"
"[Monroe] "Kiến trúc kiểu dáng, mẫu thiết kế và đối tượng," Robert T. Monroe, Drew Kompanek, Ralph Melton và David Garlan; 1996, http://www-2.cs.cmu.edu/afs/cs/project/compose/ftp/pdf/ObjPatternsArch-ieee97.pdf"
Sách Java Message Service, Richard Monson-Haefel & David A. Chappell; O'Reilly 2001, ISBN 0596000685. Có lẽ là cuốn sách về JMS nổi tiếng nhất.
WebSphere MQ (trước đây là MQSeries), IBM; http://www.software.ibm.com/ts/mqseries Một trong những sản phẩm nhắn tin và tích hợp lâu đời và nổi tiếng nhất.
[MSMQ] Hệ thống Đặt hàng Tin nhắn của Microsoft (MSMQ), Microsoft; http://www.microsoft.com/windows2000/technologies/communications/msmq/Sản phẩm nhắn tin được tích hợp trong Windows 2000, Windows XP và Windows Server 2003.
[Hình thức mẫu] Hình thức mẫu, Wiki-Wiki-Web, Cunningham & Cunningham; chỉnh sửa lần cuối vào ngày 26 tháng 8 năm 2002, http://c2.com/cgi/wiki?HìnhThứcMẫu Danh sách các hình thức mẫu thường được sử dụng và sự khác biệt của chúng.
[PLoPD1]Ngôn ngữ Mẫu trong Thiết kế Chương trình, James Coplien & Douglas Schmidt (Biên tập); Addison-Wesley 1995, ISBN 0201607344. Tài liệu từ hội nghị PLoP lần đầu tiên. Những tài liệu này chứa nhiều bài viết đã tạo thành cơ sở cho các cuốn sách sau này, chẳng hạn như [POSA]. Tập này bao gồm "Hệ thống Các mẫu" của Frank Buschmann và Regine Meunier, "Kiến trúc Ống và Bộ lọc" của Regine Meunier, và "Các Kiến trúc Tích hợp Dựa trên Mẫu" của Diane Mularz.
[PLoPD3] Ngôn ngữ mẫu thiết kế phần mềm 3, Robert Martin, Dirk Riehle, & Frank Buschmann (Biên tập); Addison-Wesley 1998, ISBN 0201310112. Cuốn sách thứ ba từ các hội nghị PLoP (PLoP, EuroPLoP, v.v.; xem http://hillside.net/conferencesnavigation.htm) chứa các mẫu đã trở thành nền tảng cho [POSA2]: Acceptor và Connector, Asynchronous Completion Token, và Double-Checked Locking. Nó cũng chứa hai mẫu từ các tác giả của cuốn sách này: Null Object và Type Object.
"[POSA] Kiến trúc phần mềm theo mẫu, Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, & Michael Stal; Wiley 1996, ISBN 0471958697. Một cuốn sách hay về kiến trúc và các mẫu thiết kế."
"[POSA2] Kiến trúc phần mềm hướng theo mẫu, Tập 2, Douglas Schmidt, Michael Stal, Hans Rohnert, & Frank Buschmann; Wiley 2000, ISBN 0471606952 Nhiều mẫu hơn tập trung vào các hệ thống phân phối và các vấn đề đồng xử lý."
[Mô hình quy trình] Mô hình hóa quy trình: Công cụ cho cải tiến quy trình và phát triển ứng dụng, Alec Sharp & Patrick McDermott; Artech House 2001, ISBN 1580530214. Cuốn sách này tập trung vào khía cạnh mô hình hóa của quy trình, là một tài liệu thú vị cho các nhà phân tích và kiến trúc sư doanh nghiệp.
"[SOAP 1.1] Tài liệu đặc tả Giao thức Truy cập Đối tượng Đơn giản (SOAP) 1.1, Tổ chức W3C; Ghi chú W3C, ngày 8 tháng 5 năm 2000, http://www.w3.org/TR/SOAP/ Tài liệu đặc tả SOAP 1.1."
"[SOAP 1.2 Phần 2] Phiên bản SOAP 1.2, Phần 2: Các phần bổ sung, Tổ chức W3C; Khuyến nghị của W3C, ngày 24 tháng 6 năm 2003, http://www.w3.org/TR/soap12-part2/ Các 'phần bổ sung' của đặc tả SOAP 1.2."
[Stevens] TCP/IP Minh họa, Tập 1: Các Giao thức, W. Richard Stevens; Addison-Wesley 1994, ISBN 0201633469
"[SysMsg]""Không gian tên System.Messaging," .NET Framework, phiên bản 1.1, Microsoft; http://msdn.microsoft.com/library/en-us/cpref/html/cpref_start.asp
"[Tennison]XSLT và XPath tại Rìa, Jeni Tennison; John Wiley & Sons 2001, ISBN 0764547763"
"[UML] UML Distilled: Hướng Dẫn Ngắn Gọn về Ngôn Ngữ Mô Hình Đối Tượng Tiêu Chuẩn (ấn bản thứ 3), Martin Fowler; Addison-Wesley 2003, ISBN 0321193687. Một nguồn tài liệu tuyệt vời để học về các sơ đồ UML, chúng nên trông như thế nào và ý nghĩa của chúng."
"[UMLEAI] "Hồ sơ UML cho Tích hợp Ứng dụng Doanh nghiệp," Nhóm Quản lý Đối tượng; 2002, http://www.omg.org/technology/documents/modeling_spec_catalog.htm"
[TCP/IP Minh họa, Tập 2: Sự Triển Khai, Gary R. Wright & W. Richard Stevens; Addison-Wesley 1995, ISBN 020163354X]
“Kiến trúc Dịch vụ Web - Các Kịch bản Sử dụng,” Tổ chức World Wide Web; Dự thảo Làm việc W3C, ngày 14 tháng 5 năm 2003, http://www.w3.org/TR/ws-arch-scenarios/ Suy nghĩ mới nhất của W3C về cách thức mà dịch vụ web sẽ được sử dụng và các yêu cầu mà các thông số kỹ thuật cần phải đáp ứng.
[WSDL 1.1] Ngôn ngữ mô tả dịch vụ web (WSDL) 1.1, Tổ chức Internet toàn cầu; Ghi chú W3C ngày 15 tháng 3 năm 2001, http://www.w3.org/TR/wsdl Đặc tả WSDL 1.1.
[WSFL]Ngôn ngữ Luồng Dịch vụ Web (WSFL) 1.0, IBM; Tháng 5 năm 2001, http://www-3.ibm.com/software/solutions/webservices/pdf/WSFL.pdf Tài liệu đặc tả WSFL 1.0.
"[WSMQ] WebSphere MQ Sử Dụng Java (ấn bản lần thứ 2), IBM; Tháng 10 năm 2002, http://publibfp.boulder.ibm.com/epubs/pdf/csqz-aw11.pdf Hướng dẫn cho các lập trình viên Java sử dụng sản phẩm nhắn tin WebSphere MQ của IBM [MQSeries]."
[XML 1.0] Ngôn ngữ Đánh dấu Mở rộng (XML) 1.0 (ấn bản thứ 2), Tổ chức W3C; Khuyến nghị W3C, ngày 6 tháng 10 năm 2000, http://www.w3.org/TR/REC-xml Tài liệu kỹ thuật XML 1.0.
[XSLT 1.0] XSL Biến đổi (XSLT) Phiên bản 1.0, Tổ chức W3C; Khuyến nghị W3C, ngày 16 tháng 11 năm 1999, http://www.w3.org/TR/xslt Đặc tả XSLT 1.0.
"[Waldo] 'Một Ghi Chú về Điện Toán Phân Tán' (Báo cáo Kỹ thuật SMLI TR-94-29), Jim Waldo, Geoff Wyant, Ann Wollrath, & Sam Kendall; Phòng Thí Nghiệm Sun Microsystems, tháng 11 năm 1994, http://citeseer.nj.nec.com/waldo94note.html"
`[Zahavi] Tích hợp ứng dụng doanh nghiệp với CORBA, Ron Zahavi; John Wiley & Sons 1999, ISBN 0471327204`
![]() | Người tổng hợp Làm thế nào chúng ta kết hợp kết quả của những tin nhắn riêng lẻ nhưng liên quan để chúng có thể được xử lý như một tổng thể? |
Mô hình dữ liệu chuẩn. Làm thế nào bạn có thể giảm thiểu sự phụ thuộc khi tích hợp các ứng dụng sử dụng các định dạng dữ liệu khác nhau?
![]() | Bộ chuyển đổi kênh Làm thế nào bạn có thể kết nối một ứng dụng với hệ thống nhắn tin để nó có thể gửi và nhận tin nhắn? |
![]() | Bộ làm sạch kênh Làm thế nào bạn có thể giữ lại các tin nhắn còn sót lại trên một kênh không làm ảnh hưởng đến việc kiểm tra hoặc hệ thống đang chạy? |
![]() | Kiểm tra yêu cầu Làm cách nào để giảm khối lượng dữ liệu của thông điệp được gửi qua hệ thống mà không hy sinh nội dung thông tin? |
![]() | Tin nhắn lệnh: Làm thế nào để tin nhắn được sử dụng để gọi một quy trình trong một ứng dụng khác? |
![]() | Người tiêu dùng cạnh tranh: Làm thế nào một ứng dụng nhắn tin có thể xử lý nhiều tin nhắn đồng thời? |
![]() | "Bộ xử lý tin nhắn hợp thành Làm thế nào bạn có thể duy trì dòng chảy tin nhắn tổng thể khi xử lý một tin nhắn gồm nhiều phần tử, mỗi phần tử có thể yêu cầu các quy trình khác nhau?" |
![]() | Người làm phong phú nội dung Làm thế nào chúng ta có thể giao tiếp với một hệ thống khác nếu người khởi tạo tin nhắn không có đủ các mục dữ liệu cần thiết? |
![]() | Bộ lọc nội dung Làm thế nào để bạn đơn giản hóa việc xử lý một tin nhắn lớn khi bạn chỉ quan tâm đến một vài dữ liệu? |
![]() | Bộ Định Tuyến Dựa Trên Nội Dung Làm thế nào chúng ta xử lý một tình huống trong đó việc triển khai một chức năng logic duy nhất được phân bổ trên nhiều hệ thống vật lý? |
![]() | Bus Điều Khiển Làm thế nào chúng ta có thể quản lý hiệu quả một hệ thống nhắn tin phân tán trên nhiều nền tảng và trong một khu vực địa lý rộng lớn? |
![]() | Nhận diện mối tương quan Làm thế nào một người yêu cầu đã nhận được phản hồi biết rằng phản hồi này là cho yêu cầu nào? |
![]() | Kênh kiểu dữ liệu Làm thế nào ứng dụng có thể gửi một mục dữ liệu để người nhận biết cách xử lý nó? |
![]() | Kênh Thư Chết Hệ thống nhắn tin sẽ làm gì với một tin nhắn mà nó không thể gửi đi? |
![]() | Lối đi vòng Detour Làm thế nào bạn có thể chuyển hướng một tin nhắn qua các bước trung gian để thực hiện xác thực, kiểm tra hoặc gỡ lỗi chức năng? |
![]() | Tài liệu Tin nhắn Làm thế nào để nhắn tin có thể được sử dụng để chuyển dữ liệu giữa các ứng dụng? |
![]() | Người đăng ký bền vững Làm thế nào một người đăng ký có thể tránh bỏ lỡ các tin nhắn khi họ không lắng nghe chúng? |
![]() | Bộ định tuyến động Làm thế nào bạn có thể tránh sự phụ thuộc của bộ định tuyến vào tất cả các điểm đến có thể có trong khi vẫn duy trì hiệu quả của nó? |
![]() | Bì thư Bao bọc Làm thế nào các hệ thống hiện có có thể tham gia vào một cuộc trao đổi tin nhắn đặt ra các yêu cầu cụ thể, chẳng hạn như các trường tiêu đề tin nhắn hoặc mã hóa, trên định dạng tin nhắn? |
![]() | Thức Thông điệp Sự kiện Làm thế nào để việc nhắn tin có thể được sử dụng để truyền tải sự kiện từ ứng dụng này sang ứng dụng khác? |
![]() | Người tiêu dùng theo sự kiện Làm thế nào một ứng dụng có thể tự động tiêu thụ các tin nhắn khi chúng trở nên khả dụng? |
![]() | Chuyển giao tệp Làm thế nào tôi có thể tích hợp nhiều ứng dụng để chúng hoạt động cùng nhau và có thể trao đổi thông tin? |
Chỉ báo định dạng Làm thế nào để thiết kế định dạng dữ liệu của một thông điệp nhằm cho phép các thay đổi có thể xảy ra trong tương lai?
![]() | Đảm bảo giao hàng Làm thế nào người gửi có thể chắc chắn rằng một tin nhắn sẽ được giao ngay cả khi hệ thống nhắn tin gặp sự cố? |
Người nhận idempotent Làm thế nào một người nhận tin nhắn có thể xử lý các tin nhắn trùng lặp?
![]() | Kênh Tin nhắn Không Hợp lệ Làm thế nào để một trình nhận tin nhắn xử lý một cách nhẹ nhàng việc nhận một tin nhắn mà không có ý nghĩa? |
![]() | Nhà môi giới tin nhắn Làm thế nào bạn có thể tách biệt đích đến của một tin nhắn khỏi người gửi và duy trì kiểm soát trung tâm đối với dòng chảy của các tin nhắn? |
![]() | Hệ thống Tin nhắn. Kiến trúc nào cho phép các ứng dụng riêng biệt hoạt động cùng nhau nhưng theo cách tách rời, giúp các ứng dụng có thể dễ dàng được thêm vào hoặc gỡ bỏ mà không ảnh hưởng đến các ứng dụng khác? |
![]() | Kênh Tin Nhắn Làm thế nào một ứng dụng giao tiếp với một ứng dụng khác thông qua việc nhắn tin? |
![]() | Bộ xử lý tin nhắn Làm thế nào mà nhiều người tiêu dùng trên một kênh đơn lẻ có thể phối hợp xử lý tin nhắn của họ? |
![]() | Đầu mối Tin nhắn Làm thế nào một ứng dụng kết nối với một kênh nhắn tin để gửi và nhận Tin nhắn? |
![]() | Hết hạn tin nhắn Làm thế nào một người gửi có thể chỉ định khi nào một tin nhắn nên được coi là lỗi thời và do đó không nên được xử lý? |
![]() | Bộ lọc tin nhắn Làm thế nào một thành phần có thể tránh nhận được những tin nhắn không thú vị? |
Lịch sử Tin nhắn Làm thế nào chúng ta có thể phân tích và gỡ lỗi hiệu quả luồng tin nhắn trong một hệ thống lỏng lẻo kết nối?
![]() | Bộ định tuyến tin nhắn Làm thế nào bạn có thể tách rời các bước xử lý riêng lẻ để các tin nhắn có thể được chuyển đến các bộ lọc khác nhau tùy thuộc vào một tập hợp các điều kiện? |
![]() | Thông điệp Chuỗi Làm thế nào mà việc nhắn tin có thể truyền tải một lượng dữ liệu lớn tùy ý? |
![]() | Cửa hàng Tin nhắn Làm thế nào chúng ta có thể báo cáo thông tin tin nhắn mà không làm ảnh hưởng đến tính chất lỏng lẻo và tạm thời của một hệ thống nhắn tin? |
![]() | Nguyên tắc chuyển đổi tin nhắn: Làm thế nào các hệ thống sử dụng định dạng dữ liệu khác nhau có thể giao tiếp với nhau thông qua tin nhắn? |
![]() | Tin nhắn Làm thế nào hai ứng dụng được kết nối qua một kênh tin nhắn có thể trao đổi một thông tin? |
![]() | Cầu Nối Tin Nhắn Làm thế nào để nhiều hệ thống tin nhắn có thể được kết nối để các tin nhắn có sẵn trên một hệ thống cũng có sẵn trên các hệ thống khác? |
![]() | Cổng nhắn tin Làm thế nào để bạn đóng gói quyền truy cập vào hệ thống nhắn tin từ phần còn lại của ứng dụng? |
Bản đồ Tin nhắn Làm thế nào bạn di chuyển dữ liệu giữa các đối tượng miền và hạ tầng nhắn tin trong khi giữ cho chúng độc lập với nhau?
![]() | Nhắn tin Làm thế nào tôi có thể tích hợp nhiều ứng dụng để chúng hoạt động cùng nhau và có thể trao đổi thông tin? |
![]() | Bộ chuẩn hóa: Bạn xử lý các thông điệp có nghĩa tương đương nhưng đến theo định dạng khác như thế nào? |
![]() | "Ống và Bộ lọc Làm thế nào chúng ta có thể thực hiện việc xử lý phức tạp trên một thông điệp trong khi vẫn duy trì sự độc lập và linh hoạt?" |
![]() | Kênh điểm-điểm Làm sao người gọi có thể chắc chắn rằng chỉ có một người nhận sẽ nhận tài liệu hoặc thực hiện cuộc gọi? |
![]() | Người tiêu dùng lấy mẫu Làm thế nào một ứng dụng có thể tiêu thụ một tin nhắn khi ứng dụng đã sẵn sàng? |
![]() | Quản lý quy trình Làm thế nào chúng ta có thể định tuyến một tin nhắn qua nhiều bước xử lý khi các bước cần thiết có thể không được biết tới vào thời điểm thiết kế và có thể không theo thứ tự? |
![]() | Kênh Đăng-Ký Phát Hành Làm thế nào người gửi có thể phát sóng một sự kiện đến tất cả các người nhận quan tâm? |
![]() | Danh sách người nhận Làm thế nào để chúng ta gửi một tin nhắn đến một danh sách người nhận động? |
![]() | Gọi thủ tục từ xa Làm thế nào tôi có thể tích hợp nhiều ứng dụng để chúng hoạt động cùng nhau và có thể trao đổi thông tin? |
![]() | Yêu cầu - Phản hồi Khi một ứng dụng gửi một tin nhắn, làm thế nào nó có thể nhận được phản hồi từ người nhận? |
![]() | Làm thế nào chúng ta có thể đưa một luồng tin nhắn liên quan nhưng không theo thứ tự trở lại đúng trật tự? |
![]() | Địa chỉ trả lại Làm thế nào một người trả lời biết gửi phản hồi đến đâu? |
![]() | Biên bản Lộ trình Làm thế nào để chúng ta chuyển tiếp một thông điệp liên tiếp qua một loạt các bước xử lý khi thứ tự các bước không được biết tại thời điểm thiết kế và có thể thay đổi cho mỗi thông điệp? |
Phân tán-Tập hợp Làm thế nào bạn duy trì luồng thông điệp tổng thể khi một thông điệp phải được gửi đến nhiều người nhận, mỗi người có thể gửi phản hồi?
![]() | Người tiêu dùng chọn lọc Làm thế nào một người tiêu dùng tin nhắn có thể chọn những tin nhắn nào mà họ muốn nhận? |
![]() | Người khởi động dịch vụ Làm thế nào một ứng dụng có thể thiết kế một dịch vụ để được gọi thông qua các công nghệ nhắn tin khác nhau và thông qua các kỹ thuật không nhắn tin? |
![]() | Cơ sở dữ liệu chia sẻ Làm thế nào tôi có thể tích hợp nhiều ứng dụng để chúng hoạt động cùng nhau và có thể trao đổi thông tin? |
![]() | Proxy thông minh Làm thế nào bạn có thể theo dõi các tin nhắn trên một dịch vụ phát hành tin nhắn trả lời đến Địa chỉ Trả hàng được chỉ định bởi người yêu cầu? |
![]() | `Bộ chia: Làm thế nào chúng ta có thể xử lý một thông điệp nếu nó chứa nhiều phần tử, mỗi phần tử có thể cần được xử lý theo cách khác nhau?` |
![]() | Tin nhắn thử nghiệm. Chuyện gì sẽ xảy ra nếu một thành phần đang xử lý tin nhắn một cách chủ động nhưng làm nhiễu tin nhắn đi ra do lỗi nội bộ? |
![]() | Khách hàng giao dịch Làm thế nào một khách hàng có thể kiểm soát các giao dịch của mình với hệ thống nhắn tin? |
![]() | Ghi âm Wires: Làm thế nào để bạn kiểm tra các tin nhắn di chuyển trên kênh Điểm-đến-Điểm? |
Ask anything about this book.