ActiveMQ之JMS及保证消息的可靠性<持久化、事务、签收>(三)

1.JAVAEE 是一套使用Java 进行企业级开发的13 个核心规范工业标准 , 包括:

 JDBC  数据库连接

 JNDI  Java的命名和目录接口

 EJB   Enterprise java bean

 RMI   远程方法调用    一般使用TCP/IP 协议

 Java IDL    接口定义语言

 JSP    

 Servlet 

 XML

 JMS    Java 消息服务

 JTA        

 JTS

 JavaMail

 JAF

 

JMS部件:

 5 个主要的消息头:

 

发送和接收的消息类型必须一致

消息属性:识别、去重、重点标注

 

2. 如何保证消息的可靠性 

    JMS 可靠性:Persistent   持久性  、 事务 、 Acknowledge  签收

   2.1 持久化

// 在队列为目的地的时候持久化消息
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);

// 队列为目的地的非持久化消息
messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);

 持久化的消息,服务器宕机后消息依旧存在,只是没有入队,当服务器再次启动,消息任就会被消费。

但是非持久化的消息,服务器宕机后消息永远丢失。 而当你没有注明是否是持久化还是非持久化时,默认是持久化的消息。

 

对于目的地为主题(topic)来说,默认就是非持久化的,让主题的订阅支持化的意义在于:对于订阅了公众号的人来说,当用户手机关机,在开机后任就可以接受到关注公众号之前发送的消息。

代码实现:持久化topic 的消费者

      ……    // 前面代码相同,不复制了      
        Topic topic = session.createTopic(TOPIC_NAME);
        TopicSubscriber topicSubscriber = session.createDurableSubscriber(topic,"remark...");

         // 5 发布订阅
        connection.start();

        Message message = topicSubscriber.receive();// 一直等
         while (null != message){
             TextMessage textMessage = (TextMessage)message;
             System.out.println(" 收到的持久化 topic :"+textMessage.getText());
             message = topicSubscriber.receive(3000L);    // 等1秒后meesage 为空,跳出循环,控制台关闭
         }
   ……

持久化生产者

          ……  
   
        MessageProducer messageProducer = session.createProducer(topic);
        // 6 通过messageProducer 生产 3 条 消息发送到消息队列中

        // 设置持久化topic 在启动
        messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT); 
        connection.start();
        for (int i = 1; i < 4 ; i++) {
            // 7  创建字消息
            TextMessage textMessage = session.createTextMessage("topic_name--" + i);
            // 8  通过messageProducer发布消息
            messageProducer.send(textMessage);

            MapMessage mapMessage = session.createMapMessage();
            //    mapMessage.setString("k1","v1");
            //     messageProducer.send(mapMessage);
        }
        // 9 关闭资源
      …… 

 

 

 当生产者启动后:

 

 

 消息被消费,并且:  (因为我在receive方法中设置了如果接收到消息后3秒还没有消息就离线,也也可以设置永久存活)

 

 2.2 事务

 

     createSession的第一个参数为true 为开启事务,开启事务之后必须在将消息提交,才可以在队列中看到消息

Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);

 提交:

session.commit(); 

事务开启的意义在于,如果对于多条必须同批次传输的消息,可以使用事务,如果一条传输失败,可以将事务回滚,再次传输,保证数据的完整性。

  对于消息消费者来说,开启事务的话,可以避免消息被多次消费,以及后台和服务器数据的不一致性。举个栗子:

如果消息消费的  createSession  设置为 ture  ,但是没有 commit ,此时就会造成非常严重的后果,那就是在后台看来消息已经被消费,但是对于服务器来说并没有接收到消息被消费,此时就有可能被多次消费。

 

 2.3 Acknowledge  签收  (俗称ack)

    非事务    :

Session.AUTO_ACKNOWLEDGE      自动签收,默认

Session.CLIENT_ACKNOWLEDGE     手动签收
手动签收需要acknowledge   
textMessage.acknowledge();

 而对于开启事务时,设置手动签收和自动签收没有多大的意义,都默认自动签收,也就是说事务的优先级更高一些。

Session session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);
//Session session = connection.createSession(true,Session.CLIENT_ACKNOWLEDGE);   //  也是自动签收   

        ……

session.commit(); 

 但是开启事务没有commit 任就会重复消费

 

小知识:  broker 

broker 就是实现了用代码形式启动 ActiveMQ 将 MQ 内嵌到 Java 代码中,可以随时启动,节省资源,提高了可靠性。

就是将 MQ 服务器作为了 Java 对象 

 

使用多个配置文件启动 activemq 

cp activemq.xml  activemq02.xml 

// 以active02 启动mq 服务器
./activemq start xbean:file:/myactivemq/apache-activemq-5.15.9/conf/activemq02.xml 

 把小型 activemq 服务器嵌入到 java 代码: 不在使用linux 的服务器

  需要的包:

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.5</version>
</dependency>

代码实现:

/**
*Embebroker Demo
*2019-12-23 17:31:34
*/
public
class Embebroker { public static void main(String[] args) throws Exception { // broker 服务 BrokerService brokerService = new BrokerService(); // 把小型 activemq 服务器嵌入到 java 代码 brokerService.setUseJmx(true); // 原本的是 192.…… 是linux 上的服务器,而这里是本地windows 的小型mq 服务器 brokerService.addConnector("tcp://localhost:61616"); brokerService.start(); } }
posted @ 2019-12-23 17:34  杭序小安  阅读(475)  评论(0编辑  收藏  举报