ActiveMQ(3)

1. ActiveMQ 协议

官网地址:http://activemq.apache.org/configuring-version-5-transports 从
5.13.0 开始,ActiveMQ 支持通过 TCP、SSL、NIO 和 NIO SSL 自动检测有线协议。支持 OpenWire、STOMP、AMQP 和 MQTT。有关详细信息,请参阅AUTO传输参考。

activemq连接支持多种协议,常用的是openwire,默认是tcp协议,使用的是BIO。
可以通过配置,修改为NIO。NIO也是基于tcp协议的。
这些是配置在activemq.xml文件中的Broker标签下的:

        <transportConnectors>
            <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
            <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        </transportConnectors>

1.1 修改tcp为nio

修改配置

<transportConnector name="nio" uri="nio://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>

修改连接

        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(
                ActiveMQConnectionFactory.DEFAULT_USER,
                ActiveMQConnectionFactory.DEFAULT_PASSWORD,
                "nio://localhost:61616?jms.producerWindowSize=1048576"
        );

1.2 自动适应协议

修改配置

<transportConnector name="auto+nio" uri="auto+nio://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>

修改连接

        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(
                ActiveMQConnectionFactory.DEFAULT_USER,
                ActiveMQConnectionFactory.DEFAULT_PASSWORD,
                "auto+nio://localhost:61616?jms.producerWindowSize=1048576"
        );

1.3 openwire(tcp)连接的配置项

在创建ActiveMQConnectionFactory 时,可以在连接后面加很多的配置
很多配置可以加载brokerURL参数的后面用?隔开。
一下是详细的配置项。不需要记住,知道就行。

<transportConnectors>
  <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?wireFormat.maxInactivityDuration=30000&amp;wireFormat.maxInactivityDurationInitalDelay=10000"/>
</transportConnectors>

OptionDefaultDescription
cacheEnabledtrueShould commonly repeated values be cached so that less marshaling occurs?
cacheSize1024When cacheEnabled=true then this parameter is used to specify the number of values to be cached.
maxInactivityDuration30000The maximum inactivity duration (before which the socket is considered dead) in milliseconds. On some platforms it can take a long time for a socket to die. Therefore allow the broker to kill connections when they have been inactive for the configured period of time. Used by some transports to enable a keep alive heart beat feature. Inactivity monitoring is disabled when set to a value <= 0.
maxInactivityDurationInitalDelay10000The initial delay before starting inactivity checks. Yes, the word 'Inital' is supposed to be misspelled like that.
maxFrameSizeMAX_LONGMaximum allowed frame size. Can help help prevent OOM DOS attacks.
sizePrefixDisabledfalseShould the size of the packet be prefixed before each packet is marshaled?
stackTraceEnabledtrueShould the stack trace of exception that occur on the broker be sent to the client?
tcpNoDelayEnabledtrueDoes not affect the wire format, but provides a hint to the peer that TCP_NODELAY should be enabled on the communications Socket.
tightEncodingEnabledtrueShould wire size be optimized over CPU usage?

Transport 可用配置选项

Option NameDefault ValueDescription
backlog5000Specifies the maximum number of connections waiting to be accepted by the transport server socket.
closeAsynctrueIf true the socket close call happens asynchronously. This parameter should be set to false for protocols like STOMP, that are commonly used in situations where a new connection is created for each read or write. Doing so ensures the socket close call happens synchronously. A synchronous close prevents the broker from running out of available sockets owing to the rapid cycling of connections.
connectionTimeout30000If >=1 the value sets the connection timeout in milliseconds. A value of 0 denotes no timeout. Negative values are ignored.
daemonfalseIf true the transport thread will run in daemon mode. Set this parameter to true when embedding the broker in a Spring container or a web container to allow the container to shut down correctly.
dynamicManagementfalseIf true the TransportLogger can be managed by JMX.
ioBufferSize8 * 1024Specifies the size of the buffer to be used between the TCP layer and the OpenWire layer where wireFormat based marshaling occurs.
jmxPort1099(Client Only) Specifies the port that will be used by the JMX server to manage the TransportLoggers. This should only be set, via URI, by either a client producer or consumer as the broker creates its own JMX server. Specifying an alternate JMX port is useful for developers that test a broker and client on the same machine and need to control both via JMX.
keepAlivefalseIf true, enables TCP KeepAlive on the broker connection to prevent connections from timing out at the TCP level. This should not be confused with KeepAliveInfo messages as used by the InactivityMonitor.
logWriterNamedefaultSets the name of the org.apache.activemq.transport.LogWriter implementation to use. Names are mapped to classes in the resources/META-INF/services/org/apache/activemq/transport/logwriters directory.
maximumConnectionsInteger.MAX_VALUEThe maximum number of sockets allowed for this broker.
minmumWireFormatVersion0The minimum remote wireFormat version that will be accepted (note the misspelling). Note: when the remote wireFormat version is lower than the configured minimum acceptable version an exception will be thrown and the connection attempt will be refused. A value of 0 denotes no checking of the remote wireFormat version.
socketBufferSize64 * 1024Sets the size, in bytes, for the accepted socket’s read and write buffers.
soLingerInteger.MIN_VALUESets the socket’s option soLinger when the value is > -1. When set to -1 the soLinger socket option is disabled.
soTimeout0Sets the socket’s read timeout in milliseconds. A value of 0 denotes no timeout.
soWriteTimeout0Sets the socket’s write timeout in milliseconds. If the socket write operation does not complete before the specified timeout, the socket will be closed. A value of 0 denotes no timeout.
stackSize0Set the stack size of the transport’s background reading thread. Must be specified in multiples of 128K. A value of 0 indicates that this parameter is ignored.
startLoggingtrueIf true the TransportLogger object of the Transport stack will initially write messages to the log. This parameter is ignored unless trace=true.
tcpNoDelayfalseIf true the socket’s option TCP_NODELAY is set. This disables Nagle’s algorithm for small packet transmission.
threadNameN/AWhen this parameter is specified the name of the thread is modified during the invocation of a transport. The remote address is appended so that a call stuck in a transport method will have the destination information in the thread name. This is extremely useful when using thread dumps for degugging.
tracefalseCauses all commands that are sent over the transport to be logged. To view the logged output define the Log4j logger: log4j.logger.org.apache.activemq.transport.TransportLogger=DEBUG.
trafficClass0The Traffic Class to be set on the socket.
diffServ0(Client only) The preferred Differentiated Services traffic class to be set on outgoing packets, as described in RFC 2475. Valid integer values: [0,64]. Valid string values: EF, AF[1-3][1-4] or CS[0-7]. With JDK 6, only works when the JVM uses the IPv4 stack. To use the IPv4 stack set the system property java.net.preferIPv4Stack=true. Note: it’s invalid to specify both ‘diffServ and typeOfService’ at the same time as they share the same position in the TCP/IP packet headers
typeOfService0(Client only) The preferred Type of Service value to be set on outgoing packets. Valid integer values: [0,256]. With JDK 6, only works when the JVM is configured to use the IPv4 stack. To use the IPv4 stack set the system property java.net.preferIPv4Stack=true. Note: it’s invalid to specify both ‘diffServ and typeOfService’ at the same time as they share the same position in the TCP/IP packet headers.
useInactivityMonitortrueWhen false the InactivityMonitor is disabled and connections will never time out.
useKeepAlivetrueWhen true KeepAliveInfo messages are sent on an idle connection to prevent it from timing out. If this parameter is false connections will still timeout if no data was received on the connection for the specified amount of time.
useLocalHostfalseWhen true local connections will be made using the value localhost instead of the actual local host name. On some operating systems, such as OS X, it’s not possible to connect as the local host name so localhost is better.
useQueueForAccepttrueWhen true accepted sockets are placed onto a queue for asynchronous processing using a separate thread.
wireFormatdefaultThe name of the wireFormat factory to use.
wireFormat.*N/AProperties with this prefix are used to configure the wireFormat.

2. ActiveMQ服务监控Hawtio

官方网站:https://hawt.io/
可以下载两种方式,jar 或者 war

2.1 单独jar运行

2.2 war包嵌入ActiveMQ

  1. 下载war包,将 war包复制到ActiveMQ的webapps目录下
  2. 在jetty.xml文件中 bean 标签下
<bean class="org.eclipse.jetty.webapp.WebAppContext">        
	<property name="contextPath" value="/hawtio" />        
	<property name="war" value="${activemq.home}/webapps/hawtio.war" />        
	<property name="logUrlOnStart" value="true" />  
</bean>
  1. 在ActiveMQ.bat 文件下添加

if “%ACTIVEMQ_OPTS%” == “” set ACTIVEMQ_OPTS=-Xms1G -Xmx1G -Dhawtio.realm=activemq -Dhawtio.role=admins -Dhawtio.rolePrincipalClasses=org.apache.activemq.jaas.GroupPrincipal -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config="%ACTIVEMQ_CONF%\login.config"

3. JMS消息结构

Message主要由三部分组成,分别是Header,Properties,Body

Header消息头,所有类型的这部分格式都是一样的
Properties属性,按类型可以分为应用设置的属性,标准属性和消息中间件定义的属性
Body消息正文,指我们具体需要消息传输的内容。

消息头

public interface Message {
    String getJMSMessageID() throws JMSException;
    void setJMSMessageID(String id) throws JMSException;
    long getJMSTimestamp() throws JMSException;
    void setJMSTimestamp(long timestamp) throws JMSException;
    byte[] getJMSCorrelationIDAsBytes() throws JMSException;
    void setJMSCorrelationIDAsBytes(byte[] correlationID) throws JMSException;
    void setJMSCorrelationID(String correlationID) throws JMSException;
    String getJMSCorrelationID() throws JMSException;
    Destination getJMSReplyTo() throws JMSException;
    void setJMSReplyTo(Destination replyTo) throws JMSException;
    Destination getJMSDestination() throws JMSException;
    void setJMSDestination(Destination destination) throws JMSException;
    int getJMSDeliveryMode() throws JMSException;
    void setJMSDeliveryMode(int deliveryMode) throws JMSException;
    boolean getJMSRedelivered() throws JMSException;
    void setJMSRedelivered(boolean redelivered) throws JMSException;
    String getJMSType() throws JMSException;
    void setJMSType(String type) throws JMSException;
    long getJMSExpiration() throws JMSException;
    void setJMSExpiration(long expiration) throws JMSException;
    int getJMSPriority() throws JMSException;
    void setJMSPriority(int priority) throws JMSException;
}

消息头分为自动设置 和手动设置

3.1 自动设置

,会有一个默认值。当然也可以自定义指定。

JMSDeliveryMode消息的发送模式,分为NON_PERSISTENTPERSISTENT,即非持久性模式的和持久性模式。默认设置为PERSISTENT(持久性)。一条持久性消息应该被传送一次(就一次),这就意味着如果JMS提供者出现故障,该消息并不会丢失; 它会在服务器恢复正常之后再次传送。一条非持久性消息最多只会传送一次,这意味着如果JMS提供者出现故障,该消息可能会永久丢失。在持久性和非持久性这两种传送模式中,消息服务器都不会将一条消息向同一消息者发送一次以上(成功算一次)。
JMSMessageID消息ID,需要以ID:开头,用于唯一地标识了一条消息
JMSTimestamp消息发送时的时间。这条消息头用于确定发送消息和它被消费者实际接收的时间间隔。时间戳是一个以毫秒来计算的Long类型时间值(自1970年1月1日算起)。
JMSExpiration消息的过期时间,以毫秒为单位,用来防止把过期的消息传送给消费者。任何直接通过编程方式来调用setJMSExpiration()方法都会被忽略。
JMSRedelivered消息是否重复发送过,如果该消息之前发送过,那么这个属性的值需要被设置为true, 客户端可以根据这个属性的值来确认这个消息是否重复发送过,以避免重复处理。
JMSPriority消息的优先级,0-4为普通的优化级,而5-9为高优先级,通常情况下,高优化级的消息需要优先发送。任何直接通过编程方式调用setJMSPriority()方法都将被忽略。
JMSDestination消息发送的目的地,是一个Topic或Queue

当发送消息时,不自定义设置,这些些值都会有默认值。
在这里插入图片描述
当然可以自定已进行设置。

MessageProducer producer = session.createProducer(mqqueue1);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
producer.setTimeToLive(10000);
producer.setPriority(9);

3.2 手动设置

根据以上图,发现这几个都没有值,默认为空。可以进行手动设置

JMSReplyTo消息回复的目的地,其值为一个Topic或Queue, 这个由发送者设置,但是接收者可以决定是否响应
JMSType由消息发送者设置的消息类型,代表消息的结构,有的消息中间件可能会用到这个,但这个并不是是批消息的种类,比如TextMessage之类的
JMSCorrelationID关联的消息ID,这个通常用在需要回传消息的时候

3.2.1. JMSReplyTo使用

指定响应目的地,Destination

在这里插入图片描述

Provider端代码。

  1. 发送消息,消息中设置JMSRepalyTo目的地
  2. 设置consumer,监听JMSRepalyTo目的地
 		//provider发送消息
        textMessage.setText("hello world!");
        ActiveMQTempQueue testResponse = new ActiveMQTempQueue("testResponse");
        textMessage.setJMSReplyTo(testResponse);
        producer.send(textMessage);
        System.out.println("发送成功。。。");

        //创建consumer,用来监听JMSReplyTo 指定的目的地Destination
        MessageConsumer consumer = session.createConsumer(testResponse);

        //设置监听
        consumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                if(message instanceof  TextMessage){
                    try {
                        System.out.println("接收消息  = [" + ((TextMessage) message).getText() + "]");
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
                if(message instanceof  BytesMessage){
                    BytesMessage bytesMessage = (BytesMessage) message;
                    byte[] bytes = new byte[1024];
                    try {
                        int i = bytesMessage.readBytes(bytes);
                        System.out.println(i+"-------");
                        System.out.println(new String(bytes,0,i));
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
                if(message instanceof  ObjectMessage){
                    ObjectMessage objectMessage = (ObjectMessage) message;
                    try {
                        Serializable object = objectMessage.getObject();
                        Boy boy = (Boy) object;
                        System.out.println(boy.toString());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

Consumer端代码

  1. 监听provider端发送的目的地
  2. 获取到消息或,创建provider向JMSRelayTo设置的目的中放入响应消息
 MessageConsumer consumer = session.createConsumer(mqqueue1);

        //设置监听
        consumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                if(message instanceof  TextMessage){
                    try {
                        System.out.println("接收消息  = [" + ((TextMessage) message).getText() + "]");

                        Destination jmsReplyTo = message.getJMSReplyTo();
                        MessageProducer producer = session.createProducer(jmsReplyTo);
                        TextMessage testResponse = session.createTextMessage("收到消息");
                        producer.send(testResponse);

                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
                if(message instanceof  BytesMessage){
                    BytesMessage bytesMessage = (BytesMessage) message;
                    byte[] bytes = new byte[1024];
                    try {
                        int i = bytesMessage.readBytes(bytes);
                        System.out.println(i+"-------");
                        System.out.println(new String(bytes,0,i));
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
                if(message instanceof  ObjectMessage){
                    ObjectMessage objectMessage = (ObjectMessage) message;
                    try {
                        Serializable object = objectMessage.getObject();
                        Boy boy = (Boy) object;
                        System.out.println(boy.toString());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

3.2.2. JMSCorrelationID 的使用

用于消息之间的关联,给人一种会话的感觉,在provider端和consumer端,将JMSCorrelationID不停的传递,provider端 —>broker----->consumer端 -------->broker------->provider端。整个是一个会话。
在这里插入图片描述

provider端

 		//provider发送消息,设置JMSCorrelationID,设置标志
        textMessage.setText("hello world!");
        String uuid = String.valueOf(UUID.randomUUID());
        textMessage.setJMSCorrelationID(uuid);
        textMessage.setStringProperty("flag","0");
        producer.send(textMessage);
        System.out.println("发送成功。。。");
        //Consumer接收消息,利用JMSCorrelationID 和 标记进行筛选。
        MessageConsumer consumer = session.createConsumer(mqqueue1,"JMSCorrelationID='"+uuid+"'and flag='1'" );
        //设置监听
        consumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                if(message instanceof  TextMessage){
                    try {
                        System.out.println("接收消息  = [" + ((TextMessage) message).getText() + "]");
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
                if(message instanceof  BytesMessage){
                    BytesMessage bytesMessage = (BytesMessage) message;
                    byte[] bytes = new byte[1024];
                    try {
                        int i = bytesMessage.readBytes(bytes);
                        System.out.println(i+"-------");
                        System.out.println(new String(bytes,0,i));
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
                if(message instanceof  ObjectMessage){
                    ObjectMessage objectMessage = (ObjectMessage) message;
                    try {
                        Serializable object = objectMessage.getObject();
                        Boy boy = (Boy) object;
                        System.out.println(boy.toString());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            }

consumer端


         final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
         final Queue mqqueue1 = session.createQueue("testqueue");
        //接收消息,利用筛选器,选择标记为0的进行消费
        MessageConsumer consumer = session.createConsumer(mqqueue1,"flag='0'");
        //设置监听
        consumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                if(message instanceof  TextMessage){
                    try {
                        System.out.println("接收消息  = [" + ((TextMessage) message).getText() + "]");
                        //接收到消息后发送响应,设置uuid,设置标记为1
                        String jmsCorrelationID = message.getJMSCorrelationID();
                        MessageProducer producer = session.createProducer(mqqueue1);
                        TextMessage testResponse = session.createTextMessage("收到消息");
                        testResponse.setStringProperty("flag","1");
                        testResponse.setJMSCorrelationID(jmsCorrelationID);
                        producer.send(testResponse);
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
                if(message instanceof  BytesMessage){
                    BytesMessage bytesMessage = (BytesMessage) message;
                    byte[] bytes = new byte[1024];
                    try {
                        int i = bytesMessage.readBytes(bytes);
                        System.out.println(i+"-------");
                        System.out.println(new String(bytes,0,i));
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
                if(message instanceof  ObjectMessage){
                    ObjectMessage objectMessage = (ObjectMessage) message;
                    try {
                        Serializable object = objectMessage.getObject();
                        Boy boy = (Boy) object;
                        System.out.println(boy.toString());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

4. 高级使用

4.1 queue browser

可以查看队列中的消息而不消费,没有订阅的功能
只浏览消息,不会消费消息

Browse进行消息浏览

public static void main(String[] args) throws Exception{

        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(
                ActiveMQConnectionFactory.DEFAULT_USER,
                ActiveMQConnectionFactory.DEFAULT_PASSWORD,
                "tcp://localhost:61616?jms.producerWindowSize=1048576"
        );
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue mqqueue1 = session.createQueue("testqueue");
        //浏览消息
        QueueBrowser browser = session.createBrowser(mqqueue1);
        Enumeration enumeration = browser.getEnumeration();
        while(enumeration.hasMoreElements()){
            TextMessage textMessage = (TextMessage)enumeration.nextElement();
            String text = textMessage.getText();
            System.out.println("浏览消息:"+text);
        }
    }

4.2 QueueRequestor同步消息

可以发送同步消息
本质违背了mq的异步通讯原则
但是mq还是能够提供应用解耦、异构系统的特性
因为使用QueueRequestor发送消息后,会等待接收端的回复,如果收不到回复就会造成死等现象!
而且该方法没有设置超时等待的功能

流程:

  1. 发送端利用Message response = queueRequestor.request(textMessage); 进行发送,且发送的消息中会默认增加一个reply的值,临时queue,用来存放响应。调用该方法后,会阻塞等待。
  2. 接收端接收到消息后,需要放入一个响应消息到临时queue中。
  3. 此时发送端接收到临时queue中的响应消息,继续执行下面的流程。
    在这里插入图片描述

发送端:

    public static void main(String[] args) throws Exception{

        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(
                ActiveMQConnectionFactory.DEFAULT_USER,
                ActiveMQConnectionFactory.DEFAULT_PASSWORD,
                "nio://localhost:61616?jms.producerWindowSize=1048576"
        );

        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        QueueSession session = (QueueSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue mqqueue1 = session.createQueue("testqueue?producer.windowSize=1048576");
        TextMessage textMessage = session.createTextMessage();
        QueueRequestor queueRequestor = new QueueRequestor(session,mqqueue1);
        //provider发送消息
        textMessage.setText("hello world!");
        Message response = queueRequestor.request(textMessage);
        System.out.println(response);
        System.out.println("发送成功。。。");
        queueRequestor.close();
        session.close();
        connection.close();
    }

接收端

public static void main(String[] args) throws Exception{

        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(
                ActiveMQConnectionFactory.DEFAULT_USER,
                ActiveMQConnectionFactory.DEFAULT_PASSWORD,
                "tcp://localhost:61616?jms.producerWindowSize=1048576"
        );
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue mqqueue1 = session.createQueue("testqueue");
        MessageConsumer consumer = session.createConsumer(mqqueue1);
        consumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                if(message instanceof TextMessage){
                    TextMessage textMessage = (TextMessage) message;
                    try {
                        String text = textMessage.getText();
                        System.out.println(text);
                        Destination jmsReplyTo = textMessage.getJMSReplyTo();
                        MessageProducer producer = session.createProducer(jmsReplyTo);
                        TextMessage messageSend = session.createTextMessage("响应消息");
                        producer.send(messageSend);
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

5. 消息异步发送

默认情况下,开启事务的持久化发送是发送异步的。不开启事务持久化是发送同步的。
当然也可以强制设置异步发送。但是建议用默认的。否则可能会丢消息。
异步发送丢失消息的场景是:生产者设置UseAsyncSend=true,使用producer.send(msg)持续发送消息。由于消息不阻塞,生产者会认为所有send的消息均被成功发送至MQ。如果服务端突然宕机,此时生产者端内存中尚未被发送至MQ的消息都会丢失。

强制设置异步方式: new
ActiveMQConnectionFactory(“tcp://locahost:61616?jms.useAsyncSend=true”);
((ActiveMQConnectionFactory)connectionFactory).setUseAsyncSend(true);
((ActiveMQConnection)connection).setUseAsyncSend(true)

6. 批量确认消息

ActiveMQ 默认是支持批量确认的,批量确认可以提高性能。
如果不想批量确认,可以设置OptimizeAcknowledge=false;

new ActiveMQConnectionFactory(“tcp://locahost:61616?jms.optimizeAcknowledge=false”);
((ActiveMQConnectionFactory)connectionFactory).setOptimizeAcknowledge(false);
((ActiveMQConnection)connection).setOptimizeAcknowledge(true);

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值