Fork me on GitHub

以ActiveMQ为例JAVA消息中间件学习【1】

前言

在慢慢的接触大型的javaweb的项目就会接触到很多的中间件系统。

其中消息中间件在很多场景下会被运用。

这里主要就对最近所学习到的消息中间件知识做一个笔记,为以后的实际运用打下一个良好的基础。

 

什么是中间件,什么是消息中间件

最近被很多人问到,所以这里解释一下,我只是讲我的理解,也没有什么官方的定义。所谓中间件,顾名思义,是在一个过程中中间使用的元件。具体一点说:在整个业务系统中,用户看不到,但是也不是最底层的操作,在中间实现桥梁作用的技术或者是软件都可以称为中间件。

那么消息中间件,重点就在消息上面了。

消息就存在两个步骤,第一个步骤是发送,第二个步骤是接收,而这个两个步骤是异步的。完成这两个步骤的中间件就是消息中间件了。

听到这里你肯定还不是很明白。我就比较的并且白话的来说。

没有消息中间件,那就是我告诉你做什么,你就马上做什么,就像我们写的普通的接口服务一样。

有消息中间件,那就是,我告诉中间件你要做什么,我的中间件发送消息给你的中间件,你的中间件收到消息告诉你,你再开始做。

要是再不理解也没关系,继续看下去。

 

什么是JMS,什么是AMQP

java message service(java消息服务)

面向消息中间件的API,用于发送消息,进行异步通信

AMQP是一个提供统一消息的应用层标准协议,是一个统一的消息模型,为了跨平台而生。

简单的说,因为发送消息必须先要有规定,就和HTTP一样,要通信就必须要有协议去规定(规定消息怎么发,消息长成什么样等),而JMS是针对与java的协议,而AMQP是面向应用的协议。

 

几种消息中间件

image

 

JMS中的相关称呼

提供者:提供服务的中间件服务器

客户端:发送和接收消息的应用程序

生产者、发布者:创建并发送消息的客户端

消费者、订阅者:接受并处理消息的客户端

消息:传送的数据内容

消息模式:不同的消息模式对应不同的消息传递方式

 

队列模式:

队列中的消息只能被一个消费者消费

消费者可以随时消费队列中的消息

 

主题模式:

消息被所有订阅者消费,每个订阅者都能收到消息,就和我们现在的微博一样,只要你关注了,那就能都能收到消息。

消费者不能消费之前发送主题的消息,也就是说在你订阅之后才会收到消息,但是之前的历史消息你是看不到的。

 

ConnectionFactory:用于创建连接到消息中间件的连接工厂

Connection:代表应用程序和消息服务器之间的通信链路

Destination:消息发布和接收的地点

Session:会话,表示一个单线程的上下文,用于发送和接收消息

MessageConsumer:由会话创建,用于接收发送到目标的消息

MessageProducer:由会话创建,用于发送消息到目标

Message:是在消费者和生产者之间传送的对象,消息头,一组消息属性,一个消息体

 

上面所有类的关系

image

 

简单的实现(队列模式)

我们使用ActiveMQ进行实现

下载地址:http://activemq.apache.org/download.html

解压后找到\bin\win64目录下的activemq.bat直接运行即可

 

使用maven导入依赖

<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.9.0</version>
</dependency>
 
编写消息的提供者
import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * 消息的提供者
 */
public class Producer {
    //ActiveMQ的地址
    private static final String URL = "tcp://127.0.0.1:61616";
    //队列的名字
    private static final String QUEUE_NAME = "active-test_queue";

    public static void main(String[] args) throws JMSException {
        //1、创建工厂
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(URL);

        //2、创建连接
        Connection connection = connectionFactory.createConnection();

        //3、启动连接
        connection.start();

        //4、创建会话
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        //5、创建目的地
        Destination destination = session.createQueue(QUEUE_NAME);

        //6、创建一个生产者
        MessageProducer producer = session.createProducer(destination);

        for (int i = 0; i < 10; i++) {
            //7、创建消息
            TextMessage textMessage = session.createTextMessage("testMessage " + i);
            //8、发送消息
            producer.send(destination, textMessage);
            System.out.println("发送消息:" + textMessage.getText());
        }

        //9、关闭连接
        connection.close();
    }
}

然后运行

 

本地ActiveMQ访问地址是

http://127.0.0.1:8161/

点击Manage ActiveMQ broker

帐号密码都是admin

然后点击上面的

image

image

其中10就是我们发送的10条消息

 

然后我们编写消费者

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * 消息的消费者
 */
public class Consumer {
    //ActiveMQ的地址
    private static final String URL = "tcp://127.0.0.1:61616";
    //队列的名字
    private static final String QUEUE_NAME = "active-test_queue";

    public static void main(String[] args) throws JMSException {
        //1、创建工厂
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(URL);

        //2、创建连接
        Connection connection = connectionFactory.createConnection();

        //3、启动连接
        connection.start();

        //4、创建会话
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        //5、创建目的地
        Destination destination = session.createQueue(QUEUE_NAME);

        //6、创建一个消费者
        MessageConsumer messageConsumer = session.createConsumer(destination);

        //7、创建一个监听器
        messageConsumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                TextMessage textMessage = (TextMessage) message;
                try {
                    System.out.println("接收到消息" + textMessage.getText());
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

然后运行之后查看队列中的消息

image

可以看到已经被消费了

 

当我们启动多个消费者,然后再启动生产者,我们可以看到在队列模式下一个消息只能被一个消费者消费

第一个

接收到消息testMessage 0
接收到消息testMessage 3
接收到消息testMessage 6
接收到消息testMessage 9

第二个

接收到消息testMessage 1
接收到消息testMessage 4
接收到消息testMessage 7

第三个

接收到消息testMessage 2
接收到消息testMessage 5
接收到消息testMessage 8

 

简单的实现(主题模式)

代码上面就改动一点点

/**
 * 消息的提供者
 */
public class Producer {
    //ActiveMQ的地址
    private static final String URL = "tcp://127.0.0.1:61616";
    //主题的名字
    private static final String TOPIC_NAME = "active-test_topic";

    public static void main(String[] args) throws JMSException {
        //1、创建工厂
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(URL);

        //2、创建连接
        Connection connection = connectionFactory.createConnection();

        //3、启动连接
        connection.start();

        //4、创建会话
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        //5、创建目的地
        Destination destination = session.createTopic(TOPIC_NAME);

        //6、创建一个生产者
        MessageProducer producer = session.createProducer(destination);

        for (int i = 0; i < 10; i++) {
            //7、创建消息
            TextMessage textMessage = session.createTextMessage("testMessage " + i);
            //8、发送消息
            producer.send(destination, textMessage);
            System.out.println("发送消息:" + textMessage.getText());
        }

        //9、关闭连接
        connection.close();
    }
}
/**
 * 消息的订阅者
 */
public class Consumer {
    //ActiveMQ的地址
    private static final String URL = "tcp://127.0.0.1:61616";
    //主题的名字
    private static final String TOPIC_NAME = "active-test_topic";

    public static void main(String[] args) throws JMSException {
        //1、创建工厂
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(URL);

        //2、创建连接
        Connection connection = connectionFactory.createConnection();

        //3、启动连接
        connection.start();

        //4、创建会话
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        //5、创建目的地
        Destination destination = session.createTopic(TOPIC_NAME);

        //6、创建一个消费者
        MessageConsumer messageConsumer = session.createConsumer(destination);

        //7、创建一个监听器
        messageConsumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                TextMessage textMessage = (TextMessage) message;
                try {
                    System.out.println("接收到消息" + textMessage.getText());
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

然后我们先启动消息的发送者,然后再启动订阅者试试

我们发现订阅者没有接收到任何消息,因为在主题模式下只有先订阅再接收,你是不能收到一个主题下的历史消息的。

然后我们关闭所有,然后启动两个订阅者,然后再启动发送者。

我们看到

第一个

接收到消息testMessage 0
接收到消息testMessage 1
接收到消息testMessage 2
接收到消息testMessage 3
接收到消息testMessage 4
接收到消息testMessage 5
接收到消息testMessage 6
接收到消息testMessage 7
接收到消息testMessage 8
接收到消息testMessage 9

第二个

接收到消息testMessage 0
接收到消息testMessage 1
接收到消息testMessage 2
接收到消息testMessage 3
接收到消息testMessage 4
接收到消息testMessage 5
接收到消息testMessage 6
接收到消息testMessage 7
接收到消息testMessage 8
接收到消息testMessage 9

说明在主题模式下,每一个订阅者都会收到一条一模一样的消息。

 

总结

至此我们已经可以简单的使用ActiveMQ了。我们第一阶段也就完成了。

思考几个问题,我们需要熟悉整个过程,在整个过程中那些东西是会被多次使用的,那些使用后马上需要关闭,而那些是不能马上关闭的?

主题模式和队列模式分别应该应用在实际中的哪种场景?

后面我们会慢慢继续学习。

posted @ 2017-09-12 15:32  LinkinStar  阅读(797)  评论(0编辑  收藏  举报