Java 使用弹簧腹板套筒';具有多端点配置的s SimpMessageTemplate

Java 使用弹簧腹板套筒';具有多端点配置的s SimpMessageTemplate,java,spring,websocket,spring-websocket,spring-4,Java,Spring,Websocket,Spring Websocket,Spring 4,我将Spring4.3.5和WebSocket与SockJS、STOMP和SimpleBrokerMessageHandler一起使用 在我的应用程序中,有三个独立的WebSocket端点运行在不同的地址上:/endPointA、/ednpointB、/endpointC 更具体地说,我用@configuration@EnableWebSocketMessageBroker注释了三个独立的配置类 我还有一个类有@Autowired SimpMessagingTemplate 最后,我有三个客户端

我将Spring4.3.5和WebSocket与SockJS、STOMP和SimpleBrokerMessageHandler一起使用

在我的应用程序中,有三个独立的WebSocket端点运行在不同的地址上:/endPointA、/ednpointB、/endpointC 更具体地说,我用@configuration@EnableWebSocketMessageBroker注释了三个独立的配置类

我还有一个类有@Autowired SimpMessagingTemplate

最后,我有三个客户端,每个客户端连接到一个不同的端点。 然而,它们都订阅了“相同”的频道地址,即/topic/messages

  • ClientOne已连接到端点A
  • ClientTwo已连接endpointB
  • 客户端三已连接到端点C
当我使用SimpMessagingTemplate向/topic/messages发送内容时,所有客户端都会收到此消息

之后我有两个问题:

  • 有没有办法“隔离”web套接字端点,以便消息不会传播到所有端点
  • 这到底是为什么
  • 我做了一些调查(堆转储分析),发现对于我的配置,我有:

    • SimpMessageTemplate的三个实例,但我始终使用同一个实例发送消息(因为@Autowire-另外,我正在打印SimpMessageTemplate.toString()
    • SimpleBrokerMessageHandler的一个实例
    • SockJsWebSocketHandler的三个实例

    因此,我想知道,在所有端点上的消息传播是否是SimpleBrokerMessageHandler或SimpMessageTemplate的“功能”。

    我在多租户应用程序中遇到了同样的问题,这要归功于:

    我的websocket端点是:
    ws://127.0.0.1/My-context-app/ws
    ,java配置文件为:

    @Configuration
    @EnableWebSocketMessageBroker
    public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    
       @Override
       public void registerStompEndpoints(StompEndpointRegistry registry) {       
          registry.addEndpoint("/ws").setAllowedOrigins("*");
          registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS(); 
       }
    }
    
    我的websocket队列url表单以租户id为前缀:
    /[tenant id]/[url of queue]

    每个客户端都使用自己的租户id进行订阅。由于
    WebSocketSecurityConfig.configureInbound(MessageSecurityMetadataSourceRegistry)
    方法和具有“websocket队列订阅安全检查”方法的自定义spring bean,它无法订阅另一个客户端的队列:

    @Configuration
    public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    
        protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
            messages
              .simpSubscribeDestMatchers("/**")
              .access("@customWSSecurityCheck.isSubscriptionAllowed(authentication, message)");
        }
    
    }
    
    我的名为customWSSecurityCheck的自定义bean检查是否允许经过身份验证的用户在队列上订阅。请记住,
    CustomAuthentication
    使用附加的tenantId属性实现
    org.springframework.security.core.Authentication
    ,该属性由自定义spring安全筛选器/验证方法中未提及的附加代码填充:

    @Bean()
    public class CustomWSSecurityCheck {
    
        public boolean isSubscriptionAllowed(CustomAuthentication authentication, Message message) {
    
           StompHeaderAccessor sha = StompHeaderAccessor.wrap(message);
           String url = sha.getDestination().substring(1);
           String tenantId = url.substring(0, url.indexOf("/"));
    
           return tenantId.equals(authentication.getTenantId());
        }
    }
    

    当然,它涉及到服务器发送的每条消息都应该以正确的租户id作为前缀:
    MessagingService.convertAndSend(“[租户id]/[url Of queue]”,messagePayload)

    我也有类似的问题。你还记得你是怎么解决的吗?嗨,不幸的是我们没有。我们接受现实——这是概念验证应用程序。虽然我仍然好奇它背后的原因是什么。原因取决于你的配置。可能所有的客户端都订阅了相同的主题。相反,它们应该订阅各自的队列。虽然我认为在具有不同名称的端点之间存在主题隔离,但它们订阅了相同的主题。不,消息传递不是这样工作的。隔离可以通过专用队列完成。