Giới thiệu về Spring Integration

Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh

Mình đã giới thiệu với các bạn về MuleSoft, một low code platform giúp chúng ta hiện thực các ứng dụng Enterprise Service Bus với nhiều Enterprise Integration Pattern một cách dễ dàng. Vấn đề là MuleSoft không free mặc dù nó cũng có bản community nên chúng ta cần có những giải pháp ít tốn chi phí hơn. Một trong số những giải pháp mà mình muốn giới thiệu với các bạn trong bài viết này là Spring Integration. Cụ thể là như thế nào? Chúng ta hãy cùng nhau tìm hiểu trong bài viết này các bạn nhé!

Cơ bản về Spring Integration

Điều đầu tiên mà các bạn cần biết là, tương tự như MuleSoft, Spring Integration giúp chúng ta hiện thực các ứng dụng middleware, integrate các ứng dụng trong một hệ thống với nhau. Nó sử dụng messaging strategy để giữ và truyền thông tin giữa các component với nhau trong ứng dụng middleware hoặc giữa các ứng dụng với nhau.

Các khái niệm chính trong Spring Integration mà các bạn cần biết là MessageMessage Channel và Message EndpointMột message sẽ được gửi tới một Message Endpoint, các Message Endpoints sẽ được kết nối với nhau thông qua Message Channels, một Message Endpoint có thể nhận Message từ một Message Channel.

Spring Integration

Message

Một Message trong Spring Integration sẽ chứa các thông tin mà qua mỗi một Endpoint, các thông tin đó có thể sẽ bị thay đổi. Cấu trúc của một Message bao gồm Header và Payload như sau:

Interface Message của Spring Integration định nghĩa thông tin Message này đó các bạn!

package org.springframework.messaging;
 
public interface Message<T> {
 
  T getPayload();
 
  MessageHeaders getHeaders();
}

Implementation chính của interface Message này là class GenericMessage.
Thường thì Header của Message sẽ chứa các thông tin overview về message. Như các bạn thấy, class MessageHeaders sẽ chứa những thông tin overview này. Bản chất thì class MessageHeaders này implement interface Map với thông tin là các cặp key và value. Các bạn lưu ý là class MessageHeaders là immutable class, chúng ta không thể thay đổi thông tin trong Header một khi Message đã được khởi tạo.

Payload sẽ chứa thông tin chính của Message, được định nghĩa sử dụng bất kỳ loại dữ liệu Java nào mà các bạn muốn.

Message Channel

Message Channel dùng để connect các Message Endpoint với nhau, các Message Endpoint sẽ sử dụng Message Channel để truyền Message cho nhau.

Một Message Channel có thể có một (Point-to-Point Message Channel) hoặc nhiều Message Endpoint subscribe vào để nhận Message.

Một Message Endpoint thường sẽ có một Inbound Message Channel và một Outbound Message Channel. Nếu một Message Endpoint không có Outbound Message Channel thì Spring Integration sẽ tự động tạo tạm một Message Channel để trả về kết quả.

Message Endpoint

Mỗi khi Message được một Message Endpoint handle, tuỳ theo business requirement, Message sẽ được enrich, transform và thay đổi thông tin mà nó đang nắm giữ.

Ví dụ như nếu Message của các bạn đang chứa ID của sinh viên cần lấy thông tin trong database thì khi đi qua Message Endpoint lấy thông tin từ database, Message ở Outbound Message Channel của Message Endpoint lấy thông tin từ database này sẽ chứa thông tin sinh viên, không còn chứa ID của sinh viên nữa.

Các Message Endpoints có thể là:

  • Channel adapter: kết nối ứng dụng với một external system theo một chiều, chỉ gửi Message đi, không nhận respone Message về.
  • Gateway: kết nối ứng dụng với một external system theo hai chiều, gửi Message đi và nhận respone Message về.
  • Service Activator: được sử dụng để gọi một phương thức của một đối tượng Java.
  • Transformer: chuyển đổi nội dung của một Message.
  • Filter: xác định có tiếp tục process Message hay không?
  • Router: quyết định Message Channel nào mà Message sẽ được gửi.
  • Splitter: chia nhỏ Message ra thành nhiều phần.
  • Aggregator: combine vài Message thành một Message duy nhất.

Java job đãi ngộ hấp dẫn đang chờ bạn ứng tuyển tại đây

Ứng dụng ví dụ

Để có cái nhìn sơ qua về cách Spring Integration làm việc, mình sẽ làm một ứng dụng cơ bản, cứ sau 5s sẽ gửi một Message với payload là tên của mình từ Message Endpoint này sang Message Endpoint khác để Message Endpoint khác đó in ra dòng chữ “Hello Khanh from Huong Dan Java” các bạn nhé!

Mình sẽ tạo một Maven project

 

với Spring Integration dependency để làm ví dụ:

<dependency>
  <groupId>org.springframework.integration</groupId>
  <artifactId>spring-integration-core</artifactId>
  <version>5.5.12</version>
</dependency>

Có 2 cách để cấu hình Spring Integration: sử dụng tập tin XML và sử dụng Java code. Trong bài viết này, chúng ta sẽ sử dụng tập tin XML các bạn nhé!

Mình sẽ tạo mới tập tin spring-integration.xml trong thư mục src/main/resources để cấu hình cho Spring Integration, với nội dung ban đầu như sau:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:int="http://www.springframework.org/schema/integration"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-5.2.xsd">
 
</beans>

Khác với Spring framework schema, tập tin http://www.springframework.org/schema/beans/spring-beans.xsd luôn được cập nhập đến latest version của Spring, đối với Spring Integration schema, các bạn cần sử dụng latest version, hiện tại là 5.2 http://www.springframework.org/schema/integration/spring-integration-5.2.xsd, các bạn nhé!

Đầu tiên, mình sẽ định nghĩa Message Channel trong Spring container làm nhiệm vụ truyền Message từ Message Endpoint tạo payload qua Message Endpoint in dòng chữ “Hello Khanh from Huong Dan Java “!

Các bạn sử dụng tag <int:channel> để định nghĩa một Message Channel các bạn nhé:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:int="http://www.springframework.org/schema/integration"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-5.2.xsd">
 
  <int:channel id="channel" />
  
</beans>

Các Message Channel identify với nhau bằng bean ID của các Message Channel đó. Trong ví dụ này, mình chỉ cần tạo một Message Channel là đủ, các bạn có thể tạo nhiều nếu muốn!

Để ứng dụng của chúng ta có thể cứ sau 5s thì gửi một Message, chúng ta sẽ định nghĩa một Message Endpoint sử dụng Polling Channel Adapter của Spring Integration với tag <int:inbound-channel-adapter/> như sau:

<int:inbound-channel-adapter channel="channel" expression="{'Khanh'}">
  <int:poller fixed-delay="5000" />
</int:inbound-channel-adapter>

Thuộc tính expression sẽ giúp chúng ta định nghĩa data sẽ được tạo ra khi Poller được trigger. Giá trị của thuộc tính expression này hỗ trợ Spring Expression Language, nên các bạn có thể bất kỳ giá trị nào, miễn thoả mãn Spring Expression Language là được!

Thuộc tính channel dùng để định nghĩa Message Channel mà data được tạo ra sẽ được chuyển đi. Giá trị của thuộc tính channel này là bean ID của Message Channel các bạn nhé!

Bên trong tag <int:inbound-channel-adapter/>, chúng ta định nghĩa tag <int:poller/> với thuộc tính fixed-deplay có giá trị là 5s để sau 5s thì Poller của chúng ta sẽ được trigger đó các bạn!

Bây giờ chúng ta sẽ sử dụng Logging Channel Adapter với tag <int:logging-channel-adapter/> để consume Message từ Polling Channel Adapter và in ra dòng chữ “Hello Khanh from Huong Dan Java”, như sau:

<int:logging-channel-adapter channel="channel"
  logger-name="com.huongdanjava.springintegration"
  expression="'Hello '.concat(payload).concat(' from Huong Dan Java')" />

Logging Channel Adapter sẽ consume Message từ channel có bean ID là “channel”, data được log sẽ được lấy từ thuộc tính expression của tag <int:logging-channel-adapter/>. Các bạn cần thêm tập tin cấu hình của Logging Framework để log message theo ý của mình nhé!

Để chạy ứng dụng này, mình sẽ tạo một class với main() method với nội dung như sau:

package com.huongdanjava.springintegration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Application {
 public static void main(String[] args) {
    new ClassPathXmlApplicationContext("spring-integration.xml");
  }
}

Kết quả khi chạy ứng dụng trên như sau: