扫盲系列之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
- 扫盲系列之JMS简介
- 扫盲系列之集群分布式简介
- java之jms简介
- JMS 之 ActiveMQ 简介
- JMS之——JMS简介
- 扫盲系列之http缓存
- JMS&MQ系列之JMS概述
- 扫盲系列—机械硬盘简介
- JMS简介之ActiveMQ实例
- c++扫盲系列之--指针专题
- 扫盲系列之负载均衡算法
- 扫盲系列之字符集编码常识
- JMS&MQ系列之简单JMS应用程序编写步骤
- JMS&MQ系列之JMS的请求和回应
- 深入浅出JMS--JMS简介
- JMS学习之ActiveMQ简介与安装
- JMS简介
- JMS简介
- Python 列表(List)
- mysql根据数据文件恢复数据
- JEESZ-SSO解决方案
- Kafka学习整理九(集群的扩容)
- 设计模式之状态模式State
- 扫盲系列之JMS简介
- centos新服务器配置环境—
- PHP将数据库中的html标签转换到页面显示
- 用递归程序求解随机产生一个正整数n(n>=100000),确定n是否是它所有因子之和
- 【Android】混淆导致json解析出错
- Unity的Mono内存管理
- MySQL数据库优化的八种方式(经典必看)
- 查看进程使用端口号及结束进程 使用命令 sudo netstat -ntlp,可以查看到目前系统网络服务器的运行情况,然后使用 sudo kill -9 pid,结束进程。
- 输入接口返回值,然后得到一个含有所有参数名称的列表