2016-11-24 180 views
4

在我的應用程序中有一個列表publisherPostListenerList,它從RabbitMQ隊列接收實時用戶帖子以發送給訂閱者/消費者。該列表是ApplicationListener類的屬性,該類監聽pubsub隊列的事件。下面的控制器方法通過基於邏輯推送帖子給訂閱者的getter方法&獲取列表元素。爲集羣環境創建列表

的流程如下

用戶寫入一個後 - >發佈進入DB +隊列 - >從隊列消息列表中的哪個是publisherPostListenerList被推向用戶的用戶加入。

正如我們所見,publisherPostListenerList是n個併發請求的共同列表,因爲ApplicationListener是一個單身人士。對於單個實例的安裝工作正常,但會在羣集環境中失敗,因爲每個節點都會有自己的個人publisherPostListenerList名單。

我該如何處理這種情況?我不能讓ApplicationListener類無狀態我需要列表來存儲從隊列中收到的帖子元素。我是否將列表放入分佈式內存緩存中?或者還有其他傳統方式?

ApplicationListener.java

@Component 
public class ApplicationEventListener { 

    private List<Post> publisherPostListenerList = new CopyOnWriteArrayList<Post>(); 

    private static final Logger logger = Logger.getLogger(ApplicationEventListener.class); 

    @EventListener 
    public void postSubmissionEventHandler(PostSubmissionEvent event) throws IOException { 
     Post post = event.getPost(); 
     logger.debug("application published user post received " + post); 
     publisherPostListenerList.add(post); 
    } 

    public List<Post> getPublisherPostListenerList() { 
     return publisherPostListenerList; 
    } 

    public void setPublisherPostListenerList(List<Post> publisherPostListenerList) { 
     this.publisherPostListenerList = publisherPostListenerList; 
    } 
} 

控制器方法用於推動消息發送到訂戶

@RequestMapping(value="/getRealTimeServerPushUserPosts") 
    public SseEmitter getRealTimeServerPushUserPosts(@RequestParam("userId") int userId){ 
     SseEmitter sseEmitter = new SseEmitter(); 
     CustomUserDetail myUserDetails = currentUserAccessor.getCurrentLoggedInUser(); 
     User loggedInUser=myUserDetails.getUser(); 

     List<Integer> userPublisherIDList = this.userService.loadUserPublisherIdListWhichLoggedInUserFollows(loggedInUser); 
     List<Post> postList =eventListener.getPublisherPostListenerList(); 


     for(Integer userPublisherId : userPublisherIDList){ 
      for(Post post:postList){ 
        if((userPublisherId.intValue()) == (post.getUser().getUserId().intValue())){ 
         try { 
         sseEmitter.send(post); 
         postList.remove(post); //removes the post for all the subscribers as the list acts as a global list. 
        } catch (IOException e) { 
         logger.error(e); 
        } 
       } 
      } 
     } 
     return sseEmitter; 
    } 
+0

誰將會調用控制器的方法? – developer

+0

我使用的服務器發送的事件推消息發送到客戶端/與loggedInUser – underdog

+0

爲什麼不能ü使用數據庫呢? – developer

回答

2

可以使用Hazelcast IList。它遵循j.u.List語義並適用於分佈式/集羣環境。

你可以找到一個文檔here和例子here。 另一種選擇是使用又名IMap分佈圖。

讓我知道如果您有關於實施細節的具體問題。

謝謝

-1

ApplicationListener被設計爲用於處理應用程序上下文中的事件。爲了解決您的問題,您可能需要部署一些消息技術(JMS主題)。 而不是增加PostSubmmittion到列表中,您postSubmissionEventHandler()將創建併發送消息來表示對JMS主題活動。 現在在您的控制器方法中,您可以讀取主題中的消息,然後將它們發佈給連接的用戶。

希望這有助於

1

把列表緩存存儲在應用程序可能會導致一些問題(如低的可擴展性...)。爲什麼不使用像Redis這樣的內存數據庫?以這種方式,您可以擴展您的應用程序,並且所有實例可以共享相同的數據庫您還保證數據的完整性。