發佈訂閱模式是怎樣的? 現在市面上流行的很多消息中間件就是採用的該種模式,這種模式 在實際業務中 將 事件發佈者(Publisher) 與 事件訂閱者 (Subscriber)通過額外的事件通道(Event Channel)來解耦,其基本原理與先前提到的觀察者模式有些許類似,但發佈訂閱模式額外存在了 ...
發佈訂閱模式是怎樣的?
現在市面上流行的很多消息中間件就是採用的該種模式,這種模式 在實際業務中 將 事件發佈者(Publisher) 與 事件訂閱者 (Subscriber)通過額外的事件通道(Event Channel)來解耦,其基本原理與先前提到的觀察者模式有些許類似,但發佈訂閱模式額外存在了Event Channel
的概念,也因此解決了 主題(Subject)和 Observer(觀察者)之間的耦合,發佈者和訂閱者就交互細節上不再需要相互關聯,下圖可以看到兩種模式之間的區別。
在 Spring 中的實際應用
在Spring框架中,發佈-訂閱模式是通過事件驅動的方式實現的,用於解耦應用程式中的組件。Spring的事件機制允許應用程式中的各個部分以鬆散耦合的方式進行通信,這種方式在日常編碼中最適合應對一些需要狀態機的業務模型, 下麵就來講下 在 Spring 中的發佈訂閱涉及到的概念
- 事件(Event):事件是應用程式中的狀態變化或動作,對應於某個特定的行為或狀態。在Spring中,事件通常是一個POJO(Plain Old Java Object)類,它包含了與該事件相關的信息。
- 事件發佈者(Event Publisher):事件發佈者是負責發佈事件的組件。在Spring中,ApplicationContext(應用程式上下文)充當了事件發佈者的角色。通過ApplicationContext,應用程式可以發佈事件,並將其傳遞給已註冊的事件監聽器。
- 事件訂閱者(Event Subscriber):事件訂閱者是負責處理特定類型事件的組件。在Spring中,事件訂閱者通常是實現了ApplicationListener介面的類,用於監聽並處理髮布的事件。
- 事件推送(ApplicationEventPublisher):事件推送是指通過ApplicationEventPublisher介面在Spring中發佈事件的過程。這個介面可以在ApplicationContext中使用,用於向已註冊的監聽器廣播事件的發生。
設計步驟
- 定義事件類:首先,定義應用中的各種事件,這些事件可以是任何與應用狀態變化或行為相關的事情。事件通常是簡單的POJO類。
- 定義發佈者:創建事件發佈者(Publisher)組件,它負責發佈事件。在Spring中,你可以使用ApplicationEventPublisher介面或者直接在Bean方法上標註@EventListener註解來實現。
- 定義訂閱者:創建事件訂閱者(Subscriber)組件,它負責訂閱感興趣的事件並對事件做出響應。在Spring中,你可以定義實現ApplicationListener介面的類來作為事件監聽器,或者使用@EventListener註解在方法上訂閱事件。
- 觸發事件:在適當的時候,通過發佈者發佈事件。一旦事件被髮布,所有已經註冊的訂閱者將會收到事件通知並執行相應的邏輯。
這裡會以簡單的 用戶註冊的場景來介紹下 Spring ApplicationEventPublisher
的使用方式
定義事件類UserRegisteredEvent
import org.springframework.context.ApplicationEvent;
public class UserRegisteredEvent extends ApplicationEvent {
private final String username;
public UserRegisteredEvent(Object source, String username) {
super(source);
this.username = username;
}
public String getUsername() {
return username;
}
}
創建UserRegistrationService服務,負責註冊新用戶併發布事件
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
@Service
public class UserRegistrationService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void registerUser(String username) {
// 註冊新用戶邏輯
// ...
// 發佈用戶註冊事件,這裡使用 eventPublisher 將 預先定義好的事件交由 Spring 的Event Channel 管理
eventPublisher.publishEvent(new UserRegisteredEvent(this, username));
}
}
創建UserNotificationService服務,訂閱UserRegisteredEvent事件併發送通知
@Service
public class UserNotificationService {
@EventListener
public void handleUserRegisteredEvent(UserRegisteredEvent event) {
// 處理用戶註冊事件,例如發送通知
String username = event.getUsername();
System.out.println("Notification sent for user: " + username);
}
}
創建 Spring 啟動類
@SpringBootApplication
@RequiredArgsConstructor
public class Application implements CommandLineRunner {
private final UserRegistrationService userRegistrationService;
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setWebApplicationType(WebApplicationType.NONE);
app.run(args);
}
@Override
public void run(String... args) {
// 在啟動時註冊新用戶
userRegistrationService.registerUser("peng");
}
}
最後程式的輸出結果 如下所示:
Notification sent for user: peng
案例中的代碼已發佈在 github倉庫 , 路徑為package com.github.meeting.demo.pattern.pubsub;
.