有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何计划通过websocket向不同的用户发送不同的消息

不同的用户会在系统中设置不同的提醒,这样一旦登录系统,他/她就可以在指定的时间看到提醒

例如,有提醒please handle this booking,提醒时间为2020-07-05 10:00,那么浏览器应该在2020-07-05 10:00提醒此消息

还有一个时间表任务,每30分钟收到一次提醒

为了实现它,我打算使用websocket。我正在使用struts2 and spring

我的代码如下所示:

@ServerEndpoint(value="/ws/{userId}")
public class Test {
        
    private String userId;
    
    private static Map<String, Session> map = new HashMap<>();    
   
    @OnOpen
    public void onOpen(@PathParam("userId") String userId,Session session) throws IOException{
        
        this.userId = userId;       
        map.put(userId, session);
    }    
   
    @OnClose
    public void onClose(){

        map.remove(userId);
    }    
   
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        ...
    }    
    
    @OnError
    public void onError(Session session, Throwable error){
        ...
    }

    public static Map<String, Session> getMap() {
        return map;
    }

    public static void setMap(Map<String, Session> map) {
        Test.map = map;
    }

}

时间表如下:

@EnableScheduling
@Component
public class ScheduleAction {   

    @Scheduled(cron = "0 0,30 * * * ?")
    public void listReminder(){
       
        Map<String, Session> map = Test.getMap();
        
        Iterator<String> ite = map.keySet().iterator();
        
        while(ite.hasNext()) {
            
            String userId = ite.next();
            //get the reminders of this user
            map.get(userId).getAsyncRemote().sendText(allRemindersOfThisUser);
        }
    }

}

我的问题是:

  1. 代码正确吗?现在最多只有200个用户同时使用这个系统
  2. 如果有更多用户同时使用此系统,代码是否正确

提前谢谢


共 (1) 个答案

  1. # 1 楼答案

    假设您已经计算出了如何跨两个bean传递userId+会话映射的细节(如果没有dobut,这是非常可行的),上述方法将用于发送通知

    话虽如此,下一个挑战是可伸缩性。我在给出的代码/设计大纲中看到了两个潜在的挑战

    1. 随着用户群的增长,顺序处理性质可能会延迟用户事件的处理,这还取决于“获取此用户的提醒”例程所花费的时间
    2. 实际上,您正在轮询事件,因此,在两个轮询周期之间创建的任何新事件都不会立即提供给用户

    #1可以通过spring async和适当的executor配置轻松解决。下面的代码片段展示了使用@Async的解决方案概要

    @EnableScheduling
    
    @Component
    public class ScheduleAction {
        @Autowired
        private UserNotifier userNotifier;
    
        @Scheduled(cron = "0 0,30 * * * ?")
        public void listReminder(){
            Map<String, Session> map = Test.getMap();
    
            map.forEach((user, session) ->
                userNotifier.sendNotificaitonsForUser(user,session));
        }
    }
    
    /**
     * A separte bean is neccesary for spring to execute the notification
     * asynchronously using executor of it's own.
     */
    @Component
    public class UserNotifier {
        @Async
        public void sendNotificaitonsForUser(String user, Session session) {
            //get the reminders of this user
            session.getAsyncRemote().sendText(allRemindersOfThisUser);
        }
    }
    

    @Async的更多细节可以在How To Do @Async in Spring文章中找到

    对于#2,它需要在核心应用程序本身中进行另一种基于事件的设计。在业务层中创建/更新的任何新事件都应生成一个事件,该事件应通过适当的侦听器进行评估,并发送给受影响的用户Spring Events将是制定此解决方案大纲的良好起点。话虽如此,如果您的用例不要求立即通知新事件,那么轮询就足够了,并且您不必制定这些额外的基于事件的通知

    希望有帮助