ActiveMQ学习(一)

ActiveMQ简介

消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供·消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。

关注于数据的发送和接受,利用高效可靠的异步消息传递机制继承分布式系统。

应用场景

异步消息:

应用解耦:

流量削峰:

安装与启动ActiveMQ:

1.上传ActiveMQ.jar

2.tar -zxvf ActiveMQ.jar

3.bin目录下:sh activemq start  启动完成

4.访问address:port  我的是:http://192.168.74.131:8161/

为什么是8161?

通过查看conf下的jetty.xml,默认端口号是8161

JMS基本概念

Java消息服务(Java Message Service)是java平台中关于面向消息中间件的API,用于两个应用程序之间,或者分布式系统中发送消息,进行异步通信。

JMS是一个与具体平台无关,绝大多数MOM(面向消息中间件)提供商同对JMS提供了支持

什么是MOM:

消息传送提供者相当于数据库,消息被消费者得到后,就相当于执行了delete操作,将消息delete掉,其他的客户端就获取不到了。

第一个activeMQ程序

引入jar包:

采用点对点传递域(p2p):

1.每一个消息只能有一个消费者

2.消息的生产者与消费者之间没有任何时间上的相关性。无论消费者在生产者发送消息时是否处于运行状态,都可以提取消息。

消息发送者

public class JmsSender {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory=new ActiveMQConnectionFactory("" +
                "tcp://192.168.11.140:61616");
        Connection connection=null;
        try {
            //创建连接
            connection=connectionFactory.createConnection();
            connection.start();

            Session session=connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);

            //创建队列(如果队列已经存在则不会创建, first-queue是队列名称)
            //destination表示目的地
            Destination destination=session.createQueue("first-queue");
            //创建消息发送者
            MessageProducer producer=session.createProducer(destination);

            TextMessage textMessage=session.createTextMessage("hello, 菲菲,我是帅帅的mic");
            producer.send(textMessage);
            session.commit();
            session.close();
        } catch (JMSException e) {
            e.printStackTrace();
        }finally {
            if(connection!=null){
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

消息接受者

public class JmsReceiver {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("" +
                "tcp://192.168.11.140:61616");
        Connection connection = null;
        try {
            //创建连接
            connection = connectionFactory.createConnection();
            connection.start();

            Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);

            //创建队列(如果队列已经存在则不会创建, first-queue是队列名称)
            //destination表示目的地
            Destination destination = session.createQueue("first-queue");
            //创建消息接收者
            MessageConsumer consumer = session.createConsumer(destination);

            TextMessage textMessage = (TextMessage) consumer.receive();
            System.out.println(textMessage.getText());
            session.commit();
            session.close();
        } catch (JMSException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }


    }
}

 消息包括消息头,消息体,消息属性。消息体有:TextMessage、MapMessage、BytesMessage、StreamMessage、ObjectMessage。

为什么是61616?

在p2p模型中:

1.如果session关闭时,有一些消息已经收到,但还没有被签收,那么当消费者下次连接到相同队列时,消息还可以被签收。

2.如果用户在receive方法中设定消息选择条件,那么不符合条件的消息会留在队列中不会被接受。

3.队列可以长久保存消息直到消息被消费者签收。消费者无需担心因为消息丢失而时刻与jms provider保持连接状态。

发布订阅传递域(pub/sub)模型

每个消息可以有多个消费者,消息的生产者和消费者之间存在时间上的相关性,订阅一个主题的消费者只能消费自它订阅之后发布的消息。JMS允许客户端创建持久订阅。

1.订阅可以分为持久性订阅与非持久性订阅

2.当所有的消息必须接收时,需要用到持久订阅,反之,则用非持久性订阅。

非持久订阅消息发送者:

public class JmsTopicSender {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory=new ActiveMQConnectionFactory("" +
                "tcp://192.168.11.140:61616");
        Connection connection=null;
        try {
            //创建连接
            connection=connectionFactory.createConnection();
            connection.start();

            Session session=connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);

            //创建队列(如果队列已经存在则不会创建, first-queue是队列名称)
            //destination表示目的地
            Destination destination=session.createTopic("first-topic");
            //创建消息发送者
            MessageProducer producer=session.createProducer(destination);
            TextMessage textMessage=session.createTextMessage("今天心情,晴转多云");
            producer.send(textMessage);
            session.commit();
            session.close();
        } catch (JMSException e) {
            e.printStackTrace();
        }finally {
            if(connection!=null){
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

非持久订阅消息接受者:

public class JmsTopicReceiver {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.74.131:61616");
        Connection connection = null;
        try {
            //创建连接
            connection = connectionFactory.createConnection();
            connection.start();

            Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);

            //创建队列(如果队列已经存在则不会创建, first-queue是队列名称)
            //destination表示目的地
            Destination destination = session.createTopic("first-topic");
            //创建消息接收者
            MessageConsumer consumer = session.createConsumer(destination);
            TextMessage textMessage = (TextMessage) consumer.receive();
            System.out.println(textMessage.getText());
            session.commit();
            session.close();
        } catch (JMSException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

持久订阅消息接受者: 先启动一下,创建持久订阅,第二次启动时就可以订阅启动前创建的消息

public class JmsTopicPersistenteReceiver {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.74.131:61616");
        Connection connection = null;
        try {
            //创建连接
            connection = connectionFactory.createConnection();
            connection.setClientID("DUBBO-ORDER"); //设置持久订阅
            connection.start();

            Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);

            //创建队列(如果队列已经存在则不会创建, first-queue是队列名称)
            //destination表示目的地
            Topic topic = session.createTopic("first-topic");
            //创建消息接收者
//            MessageConsumer consumer = session.createConsumer(destination);
            MessageConsumer consumer = session.createDurableSubscriber(topic,"DUBBO-ORDER");
            TextMessage textMessage = (TextMessage) consumer.receive();
            System.out.println(textMessage.getText());
            session.commit();
            session.close();
        } catch (JMSException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

JMS的可靠性机制

JMS消息被确认后,才会认为是被成功消费。消息的消费阶段包含三个阶段:客户端接收消息、客户端处理消息、消息被确认。

事务性会话

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

上面代码,当true时,消息会在session.commit后自动提交,不commit就不会被提交。如果将sender的commit注释掉,消息将不会被发送,将receiver的commit注释掉,消息将会一直能读取,而不是读取一次后就被删除了。同时,第二个参数将会毫无意义。源码如下:

public Session createSession(boolean transacted, int acknowledgeMode) throws JMSException {
      this.checkClosedOrFailed();
      this.ensureConnectionInfoSent();
      if (!transacted) {
         if (acknowledgeMode == 0) {
            throw new JMSException("acknowledgeMode SESSION_TRANSACTED cannot be used for an non-transacted Session");
         }

         if (acknowledgeMode < 0 || acknowledgeMode > 4) {
            throw new JMSException("invalid acknowledgeMode: " + acknowledgeMode + ". Valid values are Session.AUTO_ACKNOWLEDGE (1), Session.CLIENT_ACKNOWLEDGE (2), Session.DUPS_OK_ACKNOWLEDGE (3), ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE (4) or for transacted sessions Session.SESSION_TRANSACTED (0)");
         }
      }

      return new ActiveMQSession(this, this.getNextSessionId(), transacted ? 0 : acknowledgeMode, this.isDispatchAsync(), this.isAlwaysSessionAsync());
   }

非事务性会话

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

在该模式下,消息何时被确认取决于创建会话时的应答模式,这时commit就没有作用了。

AUTO_ACKNOWLEDGE

当客户端成功从recive方法返回以后,或者[MessageListener.onMessage]方法成功返回后,会话会自动确认该消息。

CLIENT_ACKNOWLEDGE

客户端通过调用消息的textMessage.ackonwledge()确认消息。

这种模式下,如果一个消息消费者消费一共10个消息,那么消费了5个消息,然后在第5个消息通过textMessage.acknowledge(),那么之前的所有消息都会被消息确认。

DUPS_OK_ACKNOWLEDGE

延迟确认

Broker

当前允许的activeMQ就是一个broker实例,可以自己构建一个brokerServer

public class DefineBrokerServer {

    public static void main(String[] args) {
        BrokerService brokerService=new BrokerService();
        try {
            brokerService.setUseJmx(true);
            brokerService.addConnector("tcp://localhost:61616");
            brokerService.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然后可以将前面代码中的地址改为"tcp://localhost:61616",发现也可以正常使用。

猜你喜欢

转载自blog.csdn.net/qq_37113604/article/details/94376526