2016-11-24 148 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这样的内存数据库?以这种方式,您可以扩展您的应用程序,并且所有实例可以共享相同的数据库您还保证数据的完整性。