如何配置activemq ex。排队时间,或者将消息保持在队列中直到一段时间或行动?

时间:2018-01-23 12:57:34

标签: spring-boot activemq stomp spring-websocket server-push

我正在使用 spring boot websocket 构建通知系统,我使用 ActiveMQ 为离线用户保留队列,它是' s工作完美。

我需要编辑一些配置,例如队列时间才能生效,将消息保留在队列中直到用户阅读它,我不知道如何配置它?

以下是其实施:

@Configuration
@EnableWebSocketMessageBroker 
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

      @Override
        public void configureMessageBroker(MessageBrokerRegistry config) {
            /*config.enableSimpleBroker("/topic");
            config.setApplicationDestinationPrefixes("/app");*/

          config
            .setApplicationDestinationPrefixes("/app")
            .setUserDestinationPrefix("/user")
            .enableStompBrokerRelay("/topic","/queue","/user")

            .setRelayHost("localhost")
            .setRelayPort(61613)
            .setClientLogin("guest")
            .setClientPasscode("guest");


        }


        public void registerStompEndpoints(StompEndpointRegistry registry) {
            registry.addEndpoint("/websocket").withSockJS();
        }

}

@Service
public  class NotificationWebSocketService {
@Autowired
private SimpMessagingTemplate messagingTemplate;

public void initiateNotification(WebSocketNotification notificationData) throws InterruptedException {

messagingTemplate.convertAndSendToUser(notificationData.getUserID(), "/reply", notificationData.getMessage());

}
}

在调用NotificationWebSocketService之后,它将创建队列" / user / Johon / reply"在activemq中包含用户订阅此队列消息时将收到的消息。

如何配置队列生存时间,将消息保留在队列中直到用户阅读它?

2 个答案:

答案 0 :(得分:0)

&#34; stompClient.subscribe(&#39; / user / Johon / reply&#39; - &gt;&#39; / user / Johon / reply&#39;是主题,而不是队列。< / p>

如果您的Stomp客户端未连接到主题&#39; / user / Johon / reply&#39;他将丢失发送给该主题的每条消息。

所以你的解决方案是:

  1. 转换您的主题&#39; / user / Johon / reply&#39;到队列,因此消息将无限期地保留在队列中,或者直到服务器对消息进行最终处理。
  2. 使用追溯消费者&amp;订阅恢复政策
  3.   

    追溯消费者只是常规的JMS主题消费者   表示在订阅开始时,每次尝试都应该是   曾经回到过去并发送任何旧消息(或最后一条消息   消费者可能错过了该主题。   http://activemq.apache.org/retroactive-consumer.html

         

    订阅恢复政策允许您及时返回   你订阅了一个主题。   http://activemq.apache.org/subscription-recovery-policy.html

    1. 使用持久订阅者
    2.   

      长时间离线的持久主题订阅者   通常在系统中不需要。原因是这样的   经纪人需要保留发送给这些主题的所有消息   订阅者说。这个消息打桩可以随着时间的推移经纪人   以存储限制为例,导致整体放缓   系统。   http://activemq.apache.org/manage-durable-subscribers.html

      Stomp持久订阅者: http://activemq.apache.org/stomp.html#Stomp-ActiveMQExtensionstoSTOMP

        

      CONNECT client-id string指定在其中使用的JMS clientID   与activemq.subcriptionName组合以表示持久性   订户。

      关于TTL的一些解释

        

      客户端可以为每个值指定生存时间值(以毫秒为单位)   它发送的消息。此值定义消息到期时间   消息的生存时间和GMT发送时的总和(for   事务发送,这是客户端发送消息的时间,而不是   提交交易的时间。)

           

      默认生存时间为0,因此消息仍保留在队列中   无限期地或直到服务器结束消息

      <强>更新

      如果您想使用外部ActiveMQ Broker

      删除@EnableWebSocketMessageBroker并添加到连接器下面的activemq.xml并重新启动代理。

       <transportConnector name="stomp" uri="stomp://localhost:61613"/>
      

      如果要嵌入ActiveMQ Broker,请向您添加bean WebSocketConfig:

       @Bean(initMethod = "start", destroyMethod = "stop")
          public BrokerService broker() throws Exception {
              final BrokerService broker = new BrokerService();
              broker.addConnector("stomp://localhost:61613");    
              return broker;
          }
      

      和必需的依赖项

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-activemq</artifactId>
          </dependency>
          <dependency>
              <groupId>org.apache.activemq</groupId>
              <artifactId>activemq-stomp</artifactId>
          </dependency>
      

      完整的例子 Spring Boot WebSocket with embedded ActiveMQ Broker

      http://www.devglan.com/spring-boot/spring-boot-websocket-integration-example

答案 1 :(得分:0)

单元测试,用于说明如何在用户队列中设置消息的到期时间。 必需的tomcat-embedded,spring-messaging和active-mq

import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.tomcat.util.descriptor.web.ApplicationListener;
import org.apache.tomcat.websocket.server.WsContextListener;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.stomp.*;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.web.SpringServletContainerInitializer;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import static java.util.concurrent.TimeUnit.SECONDS;

public class Test48402361 {

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

    private static TomcatWebSocketTestServer server = new TomcatWebSocketTestServer(33333);

    @BeforeClass
    public static void beforeClass() throws Exception {
        server.deployConfig(Config.class);
        server.start();
    }

    @AfterClass
    public static void afterClass() throws Exception {
        server.stop();
    }

    @Test
    public void testUser() throws Exception {

        WebSocketStompClient stompClient = new WebSocketStompClient(new SockJsClient(Collections.singletonList(new WebSocketTransport(new StandardWebSocketClient()))));

        BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();
        StompSession session = stompClient
                .connect("ws://localhost:" + server.getPort() + "/test", new WebSocketHttpHeaders(), new StompSessionHandlerAdapter() {
                })
                .get();
        // waiting until message 2 expired
        Thread.sleep(3000);
        session.subscribe("/user/john/reply", new StompFrameHandler() {
            @Override
            public Type getPayloadType(StompHeaders headers) {
                return byte[].class;
            }

            @Override
            public void handleFrame(StompHeaders headers, Object payload) {
                String message = new String((byte[]) payload);
                logger.debug("message: {}, headers: {}", message, headers);
                blockingQueue.add(message);
            }
        });
        String message = blockingQueue.poll(1, SECONDS);
        Assert.assertEquals("1", message);
        message = blockingQueue.poll(1, SECONDS);
        Assert.assertEquals("3", message);

    }

    public static class Config extends AbstractAnnotationConfigDispatcherServletInitializer {

        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class[] { };
        }

        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class[] { Mvc.class };
        }

        @Override
        protected String[] getServletMappings() {
            return new String[] { "/" };
        }
    }

    @Configuration
    @EnableWebSocketMessageBroker
    public static class Mvc extends AbstractWebSocketMessageBrokerConfigurer {

        @Override
        public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {

            stompEndpointRegistry.addEndpoint("/test")
                    .withSockJS()
                    .setWebSocketEnabled(true);
        }

        @Override
        public void configureMessageBroker(MessageBrokerRegistry registry) {
            registry.enableStompBrokerRelay("/user").setRelayHost("localhost").setRelayPort(61614);
        }

        @Autowired
        private SimpMessagingTemplate template;

        @Override
        public void configureClientInboundChannel(ChannelRegistration registration) {
            registration.setInterceptors(new ChannelInterceptorAdapter() {
                @Override
                public Message<?> preSend(Message<?> message, MessageChannel channel) {

                    StompHeaderAccessor sha = StompHeaderAccessor.wrap(message);
                    switch (sha.getCommand()) {
                        case CONNECT:
    // after connect we send 3 messages to user john, one will purged after 2 seconds.
                            template.convertAndSendToUser("john", "/reply", "1");
                            Map<String, Object> headers = new HashMap<>();
                            headers.put("expires", System.currentTimeMillis() + 2000);
                            template.convertAndSendToUser("john", "/reply", "2", headers);
                            template.convertAndSendToUser("john", "/reply", "3");
                            break;
                    }
                    return super.preSend(message, channel);
                }
            });
        }
    }

    public static class TomcatWebSocketTestServer {

        private static final ApplicationListener WS_APPLICATION_LISTENER =
                new ApplicationListener(WsContextListener.class.getName(), false);

        private final Tomcat tomcatServer;

        private final int port;

        private Context context;


        public TomcatWebSocketTestServer(int port) {

            this.port = port;

            Connector connector = new Connector(Http11NioProtocol.class.getName());
            connector.setPort(this.port);

            File baseDir = createTempDir("tomcat");
            String baseDirPath = baseDir.getAbsolutePath();

            this.tomcatServer = new Tomcat();
            this.tomcatServer.setBaseDir(baseDirPath);
            this.tomcatServer.setPort(this.port);
            this.tomcatServer.getService().addConnector(connector);
            this.tomcatServer.setConnector(connector);
        }

        private File createTempDir(String prefix) {
            try {
                File tempFolder = File.createTempFile(prefix + '.', "." + getPort());
                tempFolder.delete();
                tempFolder.mkdir();
                tempFolder.deleteOnExit();
                return tempFolder;
            } catch (IOException ex) {
                throw new RuntimeException("Unable to create temp directory", ex);
            }
        }

        public int getPort() {
            return this.port;
        }


        @SafeVarargs
        public final void deployConfig(Class<? extends WebApplicationInitializer>... initializers) {

            this.context = this.tomcatServer.addContext("", System.getProperty("java.io.tmpdir"));

            // Add Tomcat's DefaultServlet
            Wrapper defaultServlet = this.context.createWrapper();
            defaultServlet.setName("default");
            defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet");
            this.context.addChild(defaultServlet);

            // Ensure WebSocket support
            this.context.addApplicationListener(WS_APPLICATION_LISTENER);

            this.context.addServletContainerInitializer(
                    new SpringServletContainerInitializer(), new HashSet<>(Arrays.asList(initializers)));
        }

        public void start() throws Exception {
            this.tomcatServer.start();
        }

        public void stop() throws Exception {
            this.tomcatServer.stop();
        }

    }

}