扫盲系列之JMS简介

来源:互联网 发布:聊天室挂机赚钱软件 编辑:程序博客网 时间:2024/06/05 04:40

前言

今天早上在微信公众号上看到一个推送的消息,说阿里的捐赠给Apache的RocketMQ成为顶级项目,作为一个开源项目,这是阿里人值得庆贺的。对于这个RocketMQ,可能有部分人不太熟悉。在日常开发中用的比较多的可能是ActiveMQ,RabbitMQ,或者是重量级的kafka。但是不管是使用哪一种技术,这是都是JMS规范的一种实现。java 消息服务虽然出来很早,但是在现在的分布式应用依旧火热。他的地位依旧无法撼动,这里主要和大家一起学习一下这个java消息服务,同时结合ActiveMQ来进行小例子演示学习。

JMS的作用

JMS被称为消息服务,这个规范到底有什么作用,他在日常企业项目扮演什么样的一个角色?其实JMS主要是一套消息交互服务规范。他封装了RPC远程过程调用和socket底层通信。让开发者只需要关注消息服务的发送和接收,不必关注底层信息的传输细节。同时他提供了MOM消息中间件,是的各个项目之间的松散耦合做的很好,对于后期的项目拓展和维护都比较方便。

JMS中的各个接口解析

要理解清楚JMS具体的原理和功能,我们必须先了解清楚JMS中的各个接口的功能,废话不多说,先上图,再结合图来解析各个接口。
这里写图片描述

  • ConnectionFactory接口(连接工厂)
    利用工厂模式来创建连接的连接工厂,和Hibernate中的SessionFactory类似。不同之处是这里主要根据消息类型不同划分为两种,QueueConnectionFactory和TopicConnectionFactory,通常在开发中都是利用jndi在目录中查找对应的ConnectionFactory对象。

  • Connection接口(连接)
    Connection是由ConnectionFactory工厂进行创建连接,他表示客户端和JMS系统之间的连接。和上面的ConnectionFactory类似,也是有两种类型,QueueConnection和TopicConnection。如上图所示,Connection可以创建Session,继而创建后面的MessageProducer和MessageConsumer ,创建消息接收消息。

  • Session接口
    Session是我们操作消息的接口。表示一个单线程的上下文,用于发送和接收消息。由于会话是单线程的,所以消息是连续的,就是说消息是按照发送的顺序一个一个接收的。可以通过session创建生产者、消费者、消息等。Session提供了事务的功能。当我们需要使用session发送/接收多个消息时,可以将这些发送/接收动作放到一个事务中。

  • Destination 接口
    Destination 主要是用来中途保存消息的,MessageProducer将消息创建之后保存在Destination之中,然后MessageConsumer再从Destination中获取,同时根据消息的类型不一样,Destination实际上是两种类型的对象:Queue、Topic。

  • MessageProducer接口
    主要是用来创建,发送消息到队列或者主题之中,也就是上面的Destination。同样,消息生产者分两种类型:QueueSender和TopicPublisher。可以调用消息生产者的方法(send或publish方法)发送消息。

  • MessageConsumer接口
    MessageConsumer主要是从队列或者主题类型中获取消息的,他可以采用两种方式,分别是采用异步或者同步方式,这两种方式后面详细介绍

  • Message接口
    这个接口就是MessageProducer和MessageConsumer传输的主体,他主要有三个部分组成,第一个部分是消息头,包含用于识别和为消息寻找路由的操作设置,这个部分是必不可少的,第二部分是消息属性,这个部分是可选的,对于第三部分就是消息体,消息体中可以包含多种类型的消息进行传输,像文本信息,对应信息,字节信息等等。
    上面总结了各个接口在JMS中扮演的作用,这些接口协同合作才能进行消息的创建,传输,接收和响应。

JMS中的两种消息模型

刚才在介绍JMS接口中也提到,JMS中的两种消息模型,那这两种模型究竟有什么区别呢?

  • 点对点模型(p2p)

    所谓的点对点模型是指,Sender创建之后,被传输到Queue之中,在Queue之中进行排队等候,然后由Reciever接收。Queue中的一条消息只能由一个Reciever接收,接收之后保存在Queue中的消息就会消失。具体如下图所示
    p2p模型之中,对时间没有绝对的依赖,当消息被创建发送到Queue之中,Reciever可以不是运行状态,消息被保存在Queue之中,等Reciever执行的时候,再从Queue之中获取消息,当然前提是消息没有过期。p2p有以下几个特点
    1、每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)
    2、提供者和消费者之间在时间上没有依赖性,也就是说当提供者发送了消息之后,不管消费者有没有正在运行,它不会影响到消息被发送到队列
    3、每条消息仅会传送给一个消费者。可能会有多个消费者在一个队列中侦听,但是每个队列中的消息只能被队列中的一个消费者所消费。
    4、消息存在先后顺序。一个队列会按照消息服务器将消息放入队列中的顺序,把它们传送给消费者。当已被消费时,就会从队列头部将它们删除(除非使用了消息优先级)。
    5、消费者在成功接收消息之后需向队列应答成功

  • 发布订阅模型(pub-sub模型)
    所谓的发布订阅模型是指,消费者要想获取到信息先要订阅,也就是消息创建发送到Topic之前,订阅者要先启动,然后订阅消息。这样消息一到Topic就可以被消费,一条消息可以传递给所有订阅的人。具体见下图
    这里写图片描述
    pub-sub有以下几个特点
    1、每个消息可以有多个消费者
    2、发布者和订阅者之间有时间上的依赖性。针对某个主题的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息,而且为了消费消息,订阅者必须保持运行的状态。
    3、为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。
    4、每条消息都会传送给称为订阅者的多个消息消费者。订阅者有许多类型,包括持久型、非持久型和动态型。
    5、发布者通常不会知道、也意识不到哪一个订阅者正在接收主题消息。
    6、消息被推送给消费者,这意味着消息会传送给消费者,而无须请求。

ActiveMQ小例子

首先是消息创建者

/** * @ClassName: Producer* @Description: TODO(消息产生者)* @author 爱琴孩*/public class Producer {    public static void main(String[] args) throws JMSException {        String jmsProviderAddress = "tcp://localhost:61616";// 地址        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(                jmsProviderAddress);        // 这里是在main中测试,没有在jndi中获取ConnectionFactory对象,直接利用构造器构造        Connection connection = connectionFactory.createConnection();// 创建连接        Session session = connection.createSession(false,                Session.AUTO_ACKNOWLEDGE);// 打开会话        Destination dest = session.createQueue("demoQueue");// 消息目的地        MessageProducer producer = session.createProducer(dest);// 消息发送者        Message message1 = session.createTextMessage("进击的大牛");// 消息        producer.send(message1);// 发送        Message message2 = session.createTextMessage("你好 ,大牛!");// 消息        producer.send(message2);// 发送        Message message3 = session.createTextMessage("你好 ,明天!");// 消息        producer.send(message3);// 发送        producer.close();// 关闭        session.close();        connection.close();    }}

接着是消息接收者

/** * * @ClassName: Consumer* @Description: TODO(这里用一句话描述这个类的作用)* @author 爱琴孩**/public class Consumer {    public static void main(String[] args) throws JMSException {        String jmsProviderAddress = "tcp://localhost:61616";// 地址        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(                jmsProviderAddress);// 连接器        Connection connection = connectionFactory.createConnection();// 创建连接        Session session = connection.createSession(false,                Session.AUTO_ACKNOWLEDGE);// 打开会话        String destinationName = "demoQueue";        Destination dest = session.createQueue(destinationName);// 消息目的地        MessageConsumer consumer = session.createConsumer(dest);        connection.start();         while (true) {             //设置接收者接收消息的时间             TextMessage message = (TextMessage) consumer.receive(100000);             if (null != message) {                 System.out.println("从ActiveMQ中取消息:" + message.getText());             } else {                 break;             }         }        consumer.close();        session.close();        connection.close();    }}

上面是在main中执行的小例子,没有结合spring运行环境,对应获取也是直接通过构造器新建。在消费者中,获取消息是直接采用同步模式,设置固定时间,如果在这时间之内没有获取到消息,就直接返回null。当然我们我们也可以采用异步的方式。
先执行创建者,在执行消费者,运行结果如下
这里写图片描述

总结

上面简单介绍了JMS中的小概念,只能做大致的了解,其中很多细节没有介绍,有兴趣的小伙伴可查阅资料学习。

参考文献

http://www.cnblogs.com/whsa/p/4223728.html

原创粉丝点击