基於spring來實現crqs的一些問題
初學CQRS架構,想在新專案中使用CQRS來進行架構,採用的是java來進行開發,架構採用傳統的springMvc+Jpa(Hibernate實現)+Spring4.0+Mysql,暫時沒有考慮EventSource的問題,因為事件溯源暫時還有些無法理解。
1、命令匯流排(CommandBus)實現:
命令匯流排使用一個Collection來儲存所有的命令執行器(ICommandExecutor),在Spring啟動的時候透過IOC進行載入注入,當命令進入的時候就去匯流排中透過反射查詢相應的Executor並向後執行(比如呼叫Domain或DomainService),程式碼如下:
@[author]Component[/author]
public class DefaultCommandBus implements ICommandBus<ICommandExecutor<ICommand>>{
@[author]Autowired[/author]
private List<ICommandExecutor> executors;
public DefaultCommandBus() {}
//執行命令
public void send(ICommand command) {
ICommandExecutor<ICommand> executor = findCommandExecutor(command);
executor.execute(command);
}
//在所有的命令執行器集合中查詢符合條件的執行器
private ICommandExecutor<ICommand> findCommandExecutor(ICommand command){
for (ICommandExecutor<ICommand> ce : executors) {
CommandListener ric = ce.getClass().getAnnotation(CommandListener.class);
Class<? extends ICommand> clazz = ric.commandClass();
if(clazz.getName().equals(command.getClass().getName())){
return ce;
}
}
return null;
}
}
2、事件聚合器(IEventAggragete)實現:(暫時沒支援非同步事件)
採用了和命令匯流排差不多的實現方法。
但由於事件和事件處理器是一對多的關係,所以這裡採用了Map來實現,Key為指定事件的名稱,Values為一個List<IEventHandler>,當Domain或DomainService使用聚合器Pulish一個訊息的時候,就去聚合器中查詢相應事件對應的一組事件處理器,並迴圈執行,程式碼如下:
@[author]Component[/author]
public class EventAggregate implements IEventAggregate {
//實現執行結果回撥
private ICallBack callBack;
//註冊所有的事件及對應的監聽器組
private Map<String,List<IEventHandler<IEvent>>> handlers = new HashMap<String, List<IEventHandler<IEvent>>>();
@[author]Autowired[/author]
private List<IEventHandler> eventHandlers;
//自動訂閱事件監聽器
@PostConstruct
public void autoSubcribe() {
for (IEventHandler<IEvent> eventHandler : eventHandlers) {
EventListener eventAnno = eventHandler.getClass().getAnnotation(EventListener.class);
if(eventAnno != null){
String eventTypeName = eventAnno.eventClass().getName();//獲取該handler感興趣的事件類的名稱
List<IEventHandler<IEvent>> ehs = findEventType(eventTypeName);//在聚合中查詢是否有該事件的處理器已經註冊
if(ehs != null){//如果存在
ehs.add(eventHandler);
handlers.put(eventTypeName, ehs);
}else{
ehs = new ArrayList<IEventHandler<IEvent>>();
ehs.add(eventHandler);
handlers.put(eventTypeName, ehs);
}
}
}
}
private List<IEventHandler<IEvent>> findEventType(String eventTypeName){
if(handlers.size() != 0){
return handlers.get(eventTypeName);
}
return null;
}
//訂閱事件
public <TEvent extends IEvent> void subcribe(IEventHandler<IEvent> handler) {
}
//解約事件處理器
public <TEvent extends IEvent> void desubcribe(IEventHandler<IEvent> handler) {
}
//領域物件釋出訊息
public <TEvent extends IEvent> void publish(TEvent event) {
String eventTypeName = event.getClass().getName();
List<IEventHandler<IEvent>> ehs = findEventType(eventTypeName);
if(ehs != null){
for (IEventHandler<IEvent> iEventHandler : ehs) {
iEventHandler.handle(event);
if(callBack != null){
callBack.callBack();
}
}
}
}
public void setCallBack(ICallBack callBack) {
this.callBack = callBack;
}
}
支援回撥,如果需要進行回撥,則需要注入ICallback介面的實現類(一般是實現了ICallback介面的Domain或DominService物件)
以上兩點就是CQRS的Command部分的核心實現了,但總覺得有些問題:
1、SpringMVC的前端控制器是DispatherServlet,其實也是servlet,所以必須基於容器來接受請求,當客戶端請求進來之後,容器(比如Jetty)會從執行緒池中調取一個空閒的執行緒來為該客戶端服務,這就保證了每個客戶端都有一個指定的執行緒來處理,即不存在資源競爭的問題(Spring採用了大量的ThreadLocal來保證了執行緒安全),那是否還需要採用類似Disruptor這種框架來封裝命令或事件的派發,因為Disruptor框架也是用來解決安全的傳送訊息問題的框架;
2、領域物件和領域服務會顯示的和事件聚合器發生耦合。(這裡如果採用Disruptor這類框架來封裝訊息的傳送,比如封裝為靜態方法,這才會出現資源競爭的問題,但只有這樣才能和Domain或DomainService解耦)
不知道大家對以上兩點的看法是怎麼樣的?效能上的問題還未考慮,如果只是單執行緒沒有資源競爭的情況下,效能應該沒有太大問題(一個類似於Tomcat或Jetty的web伺服器400左右的併發應該不錯了,畢竟是Http的短連線)
1、命令匯流排(CommandBus)實現:
命令匯流排使用一個Collection來儲存所有的命令執行器(ICommandExecutor),在Spring啟動的時候透過IOC進行載入注入,當命令進入的時候就去匯流排中透過反射查詢相應的Executor並向後執行(比如呼叫Domain或DomainService),程式碼如下:
@[author]Component[/author]
public class DefaultCommandBus implements ICommandBus<ICommandExecutor<ICommand>>{
@[author]Autowired[/author]
private List<ICommandExecutor> executors;
public DefaultCommandBus() {}
//執行命令
public void send(ICommand command) {
ICommandExecutor<ICommand> executor = findCommandExecutor(command);
executor.execute(command);
}
//在所有的命令執行器集合中查詢符合條件的執行器
private ICommandExecutor<ICommand> findCommandExecutor(ICommand command){
for (ICommandExecutor<ICommand> ce : executors) {
CommandListener ric = ce.getClass().getAnnotation(CommandListener.class);
Class<? extends ICommand> clazz = ric.commandClass();
if(clazz.getName().equals(command.getClass().getName())){
return ce;
}
}
return null;
}
}
2、事件聚合器(IEventAggragete)實現:(暫時沒支援非同步事件)
採用了和命令匯流排差不多的實現方法。
但由於事件和事件處理器是一對多的關係,所以這裡採用了Map來實現,Key為指定事件的名稱,Values為一個List<IEventHandler>,當Domain或DomainService使用聚合器Pulish一個訊息的時候,就去聚合器中查詢相應事件對應的一組事件處理器,並迴圈執行,程式碼如下:
@[author]Component[/author]
public class EventAggregate implements IEventAggregate {
//實現執行結果回撥
private ICallBack callBack;
//註冊所有的事件及對應的監聽器組
private Map<String,List<IEventHandler<IEvent>>> handlers = new HashMap<String, List<IEventHandler<IEvent>>>();
@[author]Autowired[/author]
private List<IEventHandler> eventHandlers;
//自動訂閱事件監聽器
@PostConstruct
public void autoSubcribe() {
for (IEventHandler<IEvent> eventHandler : eventHandlers) {
EventListener eventAnno = eventHandler.getClass().getAnnotation(EventListener.class);
if(eventAnno != null){
String eventTypeName = eventAnno.eventClass().getName();//獲取該handler感興趣的事件類的名稱
List<IEventHandler<IEvent>> ehs = findEventType(eventTypeName);//在聚合中查詢是否有該事件的處理器已經註冊
if(ehs != null){//如果存在
ehs.add(eventHandler);
handlers.put(eventTypeName, ehs);
}else{
ehs = new ArrayList<IEventHandler<IEvent>>();
ehs.add(eventHandler);
handlers.put(eventTypeName, ehs);
}
}
}
}
private List<IEventHandler<IEvent>> findEventType(String eventTypeName){
if(handlers.size() != 0){
return handlers.get(eventTypeName);
}
return null;
}
//訂閱事件
public <TEvent extends IEvent> void subcribe(IEventHandler<IEvent> handler) {
}
//解約事件處理器
public <TEvent extends IEvent> void desubcribe(IEventHandler<IEvent> handler) {
}
//領域物件釋出訊息
public <TEvent extends IEvent> void publish(TEvent event) {
String eventTypeName = event.getClass().getName();
List<IEventHandler<IEvent>> ehs = findEventType(eventTypeName);
if(ehs != null){
for (IEventHandler<IEvent> iEventHandler : ehs) {
iEventHandler.handle(event);
if(callBack != null){
callBack.callBack();
}
}
}
}
public void setCallBack(ICallBack callBack) {
this.callBack = callBack;
}
}
支援回撥,如果需要進行回撥,則需要注入ICallback介面的實現類(一般是實現了ICallback介面的Domain或DominService物件)
以上兩點就是CQRS的Command部分的核心實現了,但總覺得有些問題:
1、SpringMVC的前端控制器是DispatherServlet,其實也是servlet,所以必須基於容器來接受請求,當客戶端請求進來之後,容器(比如Jetty)會從執行緒池中調取一個空閒的執行緒來為該客戶端服務,這就保證了每個客戶端都有一個指定的執行緒來處理,即不存在資源競爭的問題(Spring採用了大量的ThreadLocal來保證了執行緒安全),那是否還需要採用類似Disruptor這種框架來封裝命令或事件的派發,因為Disruptor框架也是用來解決安全的傳送訊息問題的框架;
2、領域物件和領域服務會顯示的和事件聚合器發生耦合。(這裡如果採用Disruptor這類框架來封裝訊息的傳送,比如封裝為靜態方法,這才會出現資源競爭的問題,但只有這樣才能和Domain或DomainService解耦)
不知道大家對以上兩點的看法是怎麼樣的?效能上的問題還未考慮,如果只是單執行緒沒有資源競爭的情況下,效能應該沒有太大問題(一個類似於Tomcat或Jetty的web伺服器400左右的併發應該不錯了,畢竟是Http的短連線)
[該貼被wilsonp於2014-03-16 20:40修改過]
[該貼被wilsonp於2014-03-16 20:42修改過]
[該貼被wilsonp於2014-03-16 21:51修改過]
[該貼被wilsonp於2014-03-16 21:52修改過]
相關文章
- 基於spring boot admin 做監控的一些問題記錄Spring Boot
- 使用wxpy這個基於python實現的微信工具庫的一些常見問題Python
- Spring Aop基於註解的實現Spring
- Spring AOP基於xml的方式實現SpringXML
- 基於 Jepsen 來發現幾個 Raft 實現中的一致性問題(2)Raft
- 基於spring實現事件驅動Spring事件
- 基於Spring的流量拷貝框架實現Spring框架
- 關於在基於spring的框架中使用static 方法的問題Spring框架
- 基於mysql資料庫 關於sql優化的一些問題MySql資料庫優化
- spring和ehcache整合,實現基於註解的快取實現Spring快取
- 關於Redis的一些小問題Redis
- 請問為什麼越來越多的技術偏向於基於註解的實現方式?
- 基於Redis實現Spring Cloud Gateway的動態管理RedisSpringCloudGateway
- 基於Docker的MongoDB實現授權訪問DockerMongoDB
- Spring Security實現基於RBAC的許可權表示式動態訪問控制Spring
- 基環樹的一些基本問題
- 基礎揹包問題的一些題目!!
- [原始碼和文件分享]基於JAVA實現的農夫過河問題原始碼Java
- 未來物聯網的一些問題
- 關於介面實現的一個小問題
- 基於Spring Boot和Spring Cloud實現微服務架構Spring BootCloud微服務架構
- 基於ZooKeeper,Spring設計實現的引數系統Spring
- spring基於註解配置實現事務控制Spring
- 基於HttpClient實現Http訪問工具類HTTPclient
- 關於Java NIO的一些問題,求助。Java
- 實戰來了,基於DDD實現庫存扣減~
- 關於介面的一些問題
- 關於c#實現影音嗅探的問題C#
- 關於突破 SESSION 0 隔離場景發現的一些問題Session
- 基於Spring Security實現許可權管理系統Spring
- 使用註解來構造IoC容器 & 基於Spring、Hibernate的通用DAO層與Service層的實現Spring
- 基於jquery實現的ExceljQueryExcel
- 基於JVMTI的Agent實現JVM
- 關於瀏覽器相容的一些問題瀏覽器
- 解答關於學習前端的一些問題前端
- Spring 下,關於動態資料來源的事務問題的探討Spring
- 關於原始碼的學習的一些問題原始碼
- 關於CSS一些細節問題CSS