ActiveMQ 是Apache出品的开源消息总线。完全支持JMS1.1规范
首先我们要了解一下JMS
Java消息服务(Java Message Service,JMS)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。
Java消息服务的规范包括两种消息模式,点对点和发布者/订阅者。许多提供商支持这一通用框架因此,程序员可以在他们的分布式软件中实现面向消息的操作,这些操作将具有不同面向消息中间件产品的可移植性。
Java消息服务支持同步和异步的消息处理,在某些场景下,异步消息是必要的;在其他场景下,异步消息比同步消息操作更加便利。
Java消息服务支持面向事件的方法接收消息,事件驱动的程序设计现在被广泛认为是一种富有成效的程序设计范例
在应用系统开发时,Java消息服务可以推迟选择面对消息中间件产品,也可以在不同的面对消息中间件切换。
JMS由以下7个元素组成
1.JMS提供者(JMS provider)
连接面向消息中间件的,JMS接口的一个实现。提供者可以是Java平台的JMS实现,也可以是非Java平台的面向消息中间件的适配器。
2. JMS客户(JMS client)
生产或消费消息的基于Java的应用程序或对象。
3. JMS生产者(JMS producer/publisher)
创建并发送消息的JMS客户。
4. JMS消费者(JMS consumer/subscriber)
接收消息的JMS客户。
5. JMS消息(JMS message)
包括可以在JMS客户之间传递的数据的对象
6. JMS队列(JMS queue)
一个容纳那些被发送的等待阅读的消息的区域。队列暗示,这些消息将按照顺序发送。一旦一个消息被阅读,该消息将被从队列中移走。
7. JMS主题(JMS topic)
一种支持发送消息给多个订阅者的机制。
Java消息服务应用程序结构支持两种模型:
一个生产者向一个特定的队列发布消息,一个消费者从该队列中读取消息。这里,生产者知道消费者的队列,并直接将消息发送到消费者的队列。这种模式被概括为:
· 只有一个消费者将获得消息
· 生产者不需要在接收者消费该消息期间处于运行状态,接收者也同样不需要在消息发送时处于运行状态。
· 每一个成功处理的消息都由接收者签收
支持向一个特定的消息主题发布消息。0或多个订阅者可能对接收来自特定消息主题的消息感兴趣。在这种模型下,发布者和订阅者彼此不知道对方。这种模式好比是匿名公告板。这种模式被概括为:
· 多个消费者可以获得消息
· 在发布者和订阅者之间存在时间依赖性。发布者需要建立一个订阅(subscription),以便客户能够购订阅。订阅者必须保持持续的活动状态以接收消息,除非订阅者建立了持久的订阅。在那种情况下,在订阅者未连接时发布的消息将在订阅者重新连接时重新发布。
使用Java语言,JMS提供了将应用与提供数据的传输层相分离的方式。同一组Java类可以通过JNDI中关于提供者的信息,连接不同的JMS提供者。这一组类首先使用一个连接工厂以连接到队列或主题,然后发送或发布消息。在接收端,客户接收或订阅这些消息。
Java消息服务的API在javax.jms(J2EE)
包中提供。
ConnectionFactory 接口(连接工厂)
用户用来创建到JMS提供者的连接的被管对象。JMS客户通过可移植的接口访问连接,这样当下层的实现改变时,代码不需要进行修改。 管理员在JNDI名字空间中配置连接工厂,这样,JMS客户才能够查找到它们。根据消息类型的不同,用户将使用队列连接工厂,或者主题连接工厂。
Connection 接口(连接)
连接代表了应用程序和消息服务器之间的通信链路。在获得了连接工厂后,就可以创建一个与JMS提供者的连接。根据不同的连接类型,连接允许用户创建会话,以发送和接收队列和主题到目标。
Destination 接口(目标)
目标是一个包装了消息目标标识符的被管对象,消息目标是指消息发布和接收的地点,或者是队列,或者是主题。JMS管理员创建这些对象,然后用户通过JNDI发现它们。和连接工厂一样,管理员可以创建两种类型的目标,点对点模型的队列,以及发布者/订阅者模型的主题。
MessageConsumer 接口(消息消费者)
由会话创建的对象,用于接收发送到目标的消息。消费者可以同步地(阻塞模式),或异步(非阻塞)接收队列和主题类型的消息。
MessageProducer 接口(消息生产者)
由会话创建的对象,用于发送消息到目标。用户可以创建某个目标的发送者,也可以创建一个通用的发送者,在发送消息时指定目标。
Message 接口(消息)
是在消费者和生产者之间传送的对象,也就是说从一个应用程序创送到另一个应用程序。一个消息有三个主要部分:
1. 消息头(必须):包含用于识别和为消息寻找路由的操作设置。
2. 一组消息属性(可选):包含额外的属性,支持其他提供者和用户的兼容。可以创建定制的字段和过滤器(消息选择器)。
3. 一个消息体(可选):允许用户创建五种类型的消息(文本消息,映射消息,字节消息,流消息和对象消息)。
消息接口非常灵活,并提供了许多方式来定制消息的内容。
Session 接口(会话)
表示一个单线程的上下文,用于发送和接收消息。由于会话是单线程的,所以消息是连续的,就是说消息是按照发送的顺序一个一个接收的。会话的好处是它支持事务。如果用户选择了事务支持,会话上下文将保存一组消息,直到事务被提交才发送这些消息。在提交事务之前,用户可以使用回滚操作取消这些消息。一个会话允许用户创建消息生产者来发送消息,创建消息消费者来接收消息。
在早期版本的 JMS 中,必须使用的 pub/sub 和点对点编程模型具有不同的类层次结构。保留这些类层次结构是为了支持与早期版本的 JMS API 的向后兼容,但鼓励客户端开发人员使用通用接口。
PTP 与 Pub/Sub 接口之间的关系
JMS 通用 | PTP 域 | Pub/Sub 域 |
ConnectionFactory | QueueConnectionFactory | TopicConnectionFactory |
Connection | QueueConnection | TopicConnection |
Destination | Queue | Topic |
Session | QueueSession | TopicSession |
MessageProducer | QueueSender | TopicPublisher |
MessageConsumer | QueueReceiver | TopicSubscriber |
下面对这些 JMS 概念进行简单定义。有关更多信息,请参阅 JMS 规范的 PTP 和 Pub/Sub 章节。
ConnectionFactory - 客户端用于创建 Connection 的管理对象
Connection - 到 JMS 提供者的活动连接
Destination - 封装消息目的地标识的管理对象
Session - 发送和接收消息的单线程上下文
MessageProducer - Session 创建的对象,用于将消息发送到目的地
MessageConsumer - Session 创建的对象,用于接收发送到目的地的消息
首先我们可以到官方下载页去下载最新的ActiveMQ的部署程序(http://activemq.apache.org/download-archives.html)
将程序解压后如果已经配置了java环境可以直接运行安装目录/bin下的activemq.bat来启动activemq程序,系统会自动执行启动过程,当然一般安装失败的情况是没有装JVM环境,启动成功应该是这样
activemq使用了jetty服务器来进行管理,可以在conf/jetty.xml文件中对其配置,conf/activemq.xml文件中对activemq进行配置
打开浏览器输入http://localhost:8161/admin/默认配置是这个,当然你也可以更改这个配置
在Java项目中使用activemq
在java工程中导入ActiveMQ需要的包
需要如下包:
· activemq-core.jar
· activeio-core.jar
· *kahadb.jar (if you wish to use persistence,如果要使用持久化需要此jar包)
· slf4j-api.jar
· J2EE Jars
geronimo-spec-jms.jar
geronimo-spec-jta.jar
geronimo-spec-j2ee-management.jar
也可以使用默认的activemq-all.jar,下载地址http://mvnrepository.com/artifact/org.apache.activemq/activemq-all)
import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; public class Sender { private static final int SEND_NUMBER = 5; public static void main(String[] args) { // ConnectionFactory :连接工厂,JMS 用它创建连接 ConnectionFactory connectionFactory; // Connection :JMS 客户端到JMS Provider 的连接 Connection connection = null; // Session: 一个发送或接收消息的线程 Session session; // Destination :消息的目的地;消息发送给谁. Destination destination; // MessageProducer:消息发送者 MessageProducer producer; // TextMessage message; // 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar connectionFactory = new ActiveMQConnectionFactory( ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, "tcp://localhost:61616"); try { // 构造从工厂得到连接对象 connection = connectionFactory.createConnection(); // 启动 connection.start(); // 获取操作连接 session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE); // 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置 destination = session.createQueue("FirstQueue"); // 得到消息生成者【发送者】 producer = session.createProducer(destination); // 设置不持久化,此处学习,实际根据项目决定 producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); // 构造消息,此处写死,项目就是参数,或者方法获取 sendMessage(session, producer); session.commit(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (null != connection) connection.close(); } catch (Throwable ignore) { } } } public static void sendMessage(Session session, MessageProducer producer) throws Exception { for (int i = 1; i <= SEND_NUMBER; i++) { TextMessage message = session .createTextMessage("ActiveMq 发送的消息" + i); // 发送消息到目的地方 System.out.println("发送消息:" + "ActiveMq 发送的消息" + i); producer.send(message); } } }
import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.MessageConsumer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; public class Receiver { public static void main(String[] args) { // ConnectionFactory :连接工厂,JMS 用它创建连接 ConnectionFactory connectionFactory; // Connection :JMS 客户端到JMS Provider 的连接 Connection connection = null; // Session: 一个发送或接收消息的线程 Session session; // Destination :消息的目的地;消息发送给谁. Destination destination; // 消费者,消息接收者 MessageConsumer consumer; connectionFactory = new ActiveMQConnectionFactory( ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, "tcp://localhost:61616"); try { // 构造从工厂得到连接对象 connection = connectionFactory.createConnection(); // 启动 connection.start(); // 获取操作连接 session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置 destination = session.createQueue("FirstQueue"); consumer = session.createConsumer(destination); while (true) { //设置接收者接收消息的时间,为了便于测试,这里谁定为100s TextMessage message = (TextMessage) consumer.receive(100000); if (null != message) { System.out.println("收到消息" + message.getText()); } else { break; } } } catch (Exception e) { e.printStackTrace(); } finally { try { if (null != connection) connection.close(); } catch (Throwable ignore) { } } } }
消息消费者有两种消息接收方式
1. 上面示例中的调用receive方法,使用阻塞的方式获取消息
2. 使用MessageConsumer对象的setMessageListener方法设置监听的方式,设置监听后如果关闭Consumer、session或connection将终止监听
JMS API 定义了五种消息正文类型:
Stream(流)- StreamMessage 对象的消息正文包含 Java 编程语言原始值流(“Java 基本类型”)。按顺序填充和读取。
Map(映射)- MapMessage 对象的消息正文包含一组名称-值对,其中名称是 String 对象,值是 Java 基本类型。可以根据名称按顺序或随机访问这些条目。条目的顺序是不确定的。
Text(文本)- TextMessage 对象的消息正文包含 java.lang.String 对象。此消息类型可用于传输纯文本消息和 XML 消息。
Object(对象)- ObjectMessage 对象的消息正文包含 Serializable Java 对象。
Byte(字节)- BytesMessage 对象的消息正文包含未解释的字节流。此消息类型可以按字面意义编码正文,以匹配现有的消息格式。在大多数情况下,可以使用更易用的其他正文类型。尽管 JMS API 允许将消息属性用于字节消息,但一般不使用它们,因为包含属性可能会影响格式。
确认模式用来指示会话如何确认收到消息,在使用Connection的createSession方法时需要指定此选项,在JMS的Session接口中包含下面四个选项
· AUTO_ACKNOWLEDGE = 1 自动确认
当会话从对 receive
的调用成功返回时,或在会话已调用的用于处理消息的消息侦听器成功返回时,会话会自动确认客户端的消息接收。
· CLIENT_ACKNOWLEDGE = 2 客户端手动确认
通过此确认模式,客户端通过调用消息的 acknowledge 方法确认已使用的消息。 确认已使用的消息将确认该会话已使用的所有消息。
· DUPS_OK_ACKNOWLEDGE = 3 自动批量确认
此确认模式指示会话延迟确认消息的传送。这可能在 JMS 提供者失败的情况下导致传送某些重复消息,因此只有能允许重复消息的使用方才应使用此模式。使用此模式可以通过最大限度地减少会话为防止重复所做的工作,从而减少会话开销。
· SESSION_TRANSACTED = 0 事务提交并确认
如果会话是事务的则使用此模式,忽略设置的其他模式值
在事务开启之后,和session.commit()之前,所有消费的消息,要么全部正常确认,要么全部redelivery。这种严谨性,通常在基于GROUP(消息分组)或者其他场景下特别适合。