使用spring-websocket和rabbitmq-stomp时,不会向所有活动订阅者发送消息

时间:2017-03-01 07:46:33

标签: rabbitmq stomp spring-websocket spring-rabbitmq rabbitmq-stomp

我有一个基于弹簧腹架的网络应用程序(由弹簧靴1.5.1提供动力)。我使用带有stomp插件的Rabbitmq(3.6.6)作为完整功能代理。

根据the doc of stomp,来自/ topic /的目的地消息将发送给所有活跃订阅者。

  

主题目的地

     

对于提供副本的简单主题目的地   每条消息给所有活动订阅者,表单的目的地   / topic /可以使用。主题目标支持所有路由   AMQP主题交换的模式。

     

发送到没有活动订阅者的主题目标的邮件   被丢弃了。

但行为与我的应用中的上述声明一致!

我在两个浏览器中打开了同一页面。因此,有两个客户端连接到websocket服务器。他们都订阅了以/topic/开头的相同目的地。

我将邮件发送到目标/topic/<route key>后,但只有一个客户端会收到该邮件。两个客户端将轮流接收来自同一目的地的消息。

在我的春季服务器端应用程序中,我将消息发送到目的地,如下所示,

    @Secured(User.ROLE_USER)
@MessageMapping("/comment/{liveid}")
@SendTo("/topic/comment-{liveid}")
public CommentMessage userComment(@DestinationVariable("liveid") String liveid,
                                     @AuthenticationPrincipal UserDetails activeUser, UserComment userComment) {
    logger.debug("Receiving comment message '{}' of live '{}' from user '{}'.",
            userComment,liveid, activeUser.getUsername());
    final User user = userService.findByUsername(activeUser.getUsername()).get();
    return CommentMessage.builder().content(userComment.getContent()).sender(user.getNickname())
            .senderAvatar(user.getAvatar()).build();
}

在我的客户端,它订阅耐用主题,如下所示,

$stomp.subscribe('/topic/comment-' + $scope.lives[i].id, function(payload, headers, res) {
                                // do something
                            }, {
                                'durable': true,
                                'auto-delete': false
                            });

以下是我春季应用程序中websocket的配置,

@Configuration
@EnableWebSocketMessageBroker

public class WebSocketConfig extends AbstractSessionWebSocketMessageBrokerConfigurer<ExpiringSession> {

@Value("${stompBroker.host:localhost}")
String brokerHost;
@Value("${stompBroker.port:61613}")
int brokerPort;
@Value("${stompBroker.login:guest}")
String brokerLogin;
@Value("${stompBroker.passcode:guest}")
String brokerPasscode;
@Value("${stompBroker.vhost:myvhost}")
String brokerVHost;

@Override
protected void configureStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/live/ws").withSockJS();
}

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableStompBrokerRelay("/topic/").setRelayHost(brokerHost).setRelayPort(
            brokerPort).setSystemLogin(brokerLogin).setSystemPasscode(brokerPasscode).setVirtualHost(brokerVHost);

    /**
     * Both of two subscribers can receive the message if using simple broker 
    registry.enableSimpleBroker("/topic/");
     */
    registry.setApplicationDestinationPrefixes("/app");
}

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages.simpDestMatchers("/app/*").hasRole("USER");
    }

    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }
}
}

我的RabbitMQ和Stomp插件配置有什么问题吗?使用SimpleMessageBroker而不是RabbitMQ时,它运行良好。

1 个答案:

答案 0 :(得分:0)

rabbimq-users group中的讨论解决了这个问题。

我使用了持久订阅,使用相同的ID,消费者成为有竞争力的消费者。

在使用持久队列或使用自动删除队列时指定不同的客户端ID解决了问题。