ActiveMQ入门
一、ActiveMQ简介
Apache ActiveMQ是Apache软件基金会所研发的开放源代码消息中间件;由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行。
它能很好地支持J2EE提出的JMS(Java Message Service,即Java消息服务)规范。JMS是一组Java应用程序接口,它提供消息的创建、发送、读取等一系列服务。JMS提供了一组公共应用程序接口和响应的语法,类似于Java数据库的统一访问接口JDBC,它是一种与厂商无关的API,使得Java程序能够与不同厂商的消息组件很好地进行通信。
二、消息中间件概述
1、中间件
非底层操作系统软件,非业务应用软件,不是直接给最终用户使用的,不能直接给客户带来价值的软件系统称为中间件。中间件(middleware)是基础软件的一大类,属于可复用软件的范畴。顾名思义,中间件处于操作系统软件与用户的应用软件的中间。
2、消息中间件
消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。
3、JMS概述
JMS即Java消息服务(Java Message Service的简称),是Java EE 的标准/规范之一。这种规范(标准)指出:消息的发送应该是异步的、非阻塞的。也就是说消息的发送者发送完消息后就直接返回了,不需要等待接收者返回后才能返回,发送者和接收者可以说是互不影响。所以这种规范(标准)能够减轻或消除系统瓶颈,实现系统之间去除耦合,提高系统的整体可伸缩性和灵活性。JMS只是Java EE中定义的一组标准API,它自身并不是一个消息服务系统,它是消息传送服务的一个抽象,也就是说它定义了消息传送的接口而并没有具体实现。
3.1、JMS组成
- JMS提供者
连接面向消息中间件的,JMS接口的一个实现。提供者可以是Java平台的JMS实现,也可以是非Java平台的面向消息中间件的适配器。 - JMS客户端
生产或消费基于消息的Java的应用程序或对象。 - JMS生产者
创建并发送消息的JMS客户。 - JMS消费者
接收消息的JMS客户。 - JMS消息
包括可以在JMS客户之间传递的数据的对象 - JMS队列
一个容纳那些被发送的等待阅读的消息的区域。与队列名字所暗示的意思不同,消息的接受顺序并不一定要与消息的发送顺序相同。一旦一个消息被阅读,该消息将被从队列中移走。 - JMS主题
一种支持发送消息给多个订阅者的机制。
3.2、对象模型
- JMS对象模型包含如下几个要素:
1)连接工厂:连接工厂(ConnectionFactory)是由管理员创建,并绑定到JNDI树中。客户端使用JNDI查找连接工厂,然后利用连接工厂创建一个JMS连接。
2)JMS连接:JMS连接(Connection)表示JMS客户端和服务器端之间的一个活动的连接,是由客户端通过调用连接工厂的方法建立的。
3)JMS会话:JMS会话(Session)表示JMS客户与JMS服务器之间的会话状态。JMS会话建立在JMS连接上,表示客户与服务器之间的一个会话线程。
4)JMS目的:JMS目的(Destination),又称为消息队列,是实际的消息源。
5)JMS生产者和消费者:生产者(Message Producer)和消费者(Message Consumer)对象由Session对象创建,用于发送和接收消息。
6)JMS消息通常有两种类型:
① 点对点(Point-to-Point):在点对点的消息系统中,消息分发给一个单独的使用者。点对点消息往往与队列(javax.jms.Queue)相关联。
② 发布/订阅(Publish/Subscribe):发布/订阅消息系统支持一个事件驱动模型,消息生产者和消费者都参与消息的传递。生产者发布事件,而使用者订阅感兴趣的事件,并使用事件。该类型消息一般与特定的主题(javax.jms.Topic)关联。
3.3、模型
Java消息服务应用程序结构支持两种模型:
-
点对点或队列模型
-
发布者/订阅者模型
在点对点或队列模型下,一个生产者向一个特定的队列发布消息,一个消费者从该队列中读取消息。这里,生产者知道消费者的队列,并直接将消息发送到消费者的队列。
这种模式被概括为:只有一个消费者将获得消息
生产者不需要在接收者消费该消息期间处于运行状态,接收者也同样不需要在消息发送时处于运行状态。
每一个成功处理的消息都由接收者签收
发布者/订阅者模型支持向一个特定的消息主题发布消息。0或多个订阅者可能对接收来自特定消息主题的消息感兴趣。在这种模型下,发布者和订阅者彼此不知道对方。这种模式好比是匿名公告板。
这种模式被概括为:多个消费者可以获得消息
在发布者和订阅者之间存在时间依赖性。发布者需要建立一个订阅(subscription),以便客户能够订阅。订阅者必须保持持续的活动状态以接收消息,除非订阅者建立了持久的订阅。在那种情况下,在订阅者未连接时发布的消息将在订阅者重新连接时重新发布。
使用Java语言,JMS提供了将应用与提供数据的传输层相分离的方式。同一组Java类可以通过JNDI中关于提供者的信息,连接不同的JMS提供者。这一组类首先使用一个连接工厂以连接到队列或主题,然后发送或发布消息。在接收端,客户接收或订阅这些消息。
3.4、传递方式
JMS有两种传递消息的方式:
- 标记为NON_PERSISTENT的消息最多投递一次;
- 而标记为PERSISTENT的消息将使用暂存后再转送的机理投递。
如果一个JMS服务离线,那么持久性消息不会丢失但是得等到这个服务恢复联机时才会被传递。所以默认的消息传递方式是非持久性的。即使使用非持久性消息可能降低内务和需要的存储器,并且这种传递方式只有当你不需要接收所有的消息时才使用。
虽然JMS规范并不需要JMS供应商实现消息的优先级路线,但是它需要递送加快的消息优先于普通级别的消息。
JMS定义了从0到9的优先级路线级别,0是最低的优先级而9则是最高的。更特殊的是0到4是正常优先级的变化幅度,而5到9是加快的优先级的变化幅度。举例来说: topicPublisher.publish (message, DeliveryMode.PERSISTENT, 8, 10000); //Pub-Sub 或 queueSender.send(message,DeliveryMode.PERSISTENT, 8, 10000);//P2P 这个代码片断,有两种消息模型,映射递送方式是持久的,优先级为加快型,生存周期是10000 (以毫秒度量)。如果生存周期设置为零,这则消息将永远不会过期。当消息需要时间限制否则将使其无效时,设置生存周期是有用的。
JMS定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。
- StreamMessage :Java原始值的数据流
- MapMessage:一套名称-值对
- TextMessage:一个字符串对象
- ObjectMessage: 一个序列化的 Java对象
- BytesMessage:一个未解释字节的数据流
3.5、JMS编码接口
ConnectionFactory 接口(连接工厂)
用户用来创建到JMS提供者的连接的被管对象。JMS客户通过可移植的接口访问连接,这样当下层的实现改变时,代码不需要进行修改。管理员在JNDI名字空间中配置连接工厂,这样,JMS客户才能够查找到它们。根据消息类型的不同,用户将使用队列连接工厂,或者主题连接工厂。
Connection 接口(连接)
连接代表了应用程序和消息服务器之间的通信链路。在获得了连接工厂后,就可以创建一个与JMS提供者的连接。根据不同的连接类型,连接允许用户创建会话,以发送和接收队列和主题到目标。
Destination 接口(目标)
目标是一个包装了消息目标标识符的被管对象,消息目标是指消息发布和接收的地点,或者是队列,或者是主题。JMS管理员创建这些对象,然后用户通过JNDI发现它们。和连接工厂一样,管理员可以创建两种类型的目标,点对点模型的队列,以及发布者/订阅者模型的主题。
Session 接口(会话)
表示一个单线程的上下文,用于发送和接收消息。由于会话是单线程的,所以消息是连续的,就是说消息是按照发送的顺序一个一个接收的。会话的好处是它支持事务。如果用户选择了事务支持,会话上下文将保存一组消息,直到事务被提交才发送这些消息。在提交事务之前,用户可以使用回滚操作取消这些消息。一个会话允许用户创建消息,生产者来发送消息,消费者来接收消息。
MessageConsumer 接口(消息消费者)
由会话创建的对象,用于接收发送到目标的消息。消费者可以同步地(阻塞模式),或(非阻塞)接收队列和主题类型的消息。
MessageProducer 接口(消息生产者)
由会话创建的对象,用于发送消息到目标。用户可以创建某个目标的发送者,也可以创建一个通用的发送者,在发送消息时指定目标。
Message 接口(消息)
是在消费者和生产者之间传送的对象,也就是说从一个应用程序传送到另一个应用程序。一个消息有三个主要部分:
消息头(必须):包含用于识别和为消息寻找路由的操作设置。
一组消息属性(可选):包含额外的属性,支持其他提供者和用户的兼容。可以创建定制的字段和过滤器(消息选择器)。
一个消息体(可选):允许用户创建五种类型的消息(文本消息,映射消息,字节消息,流消息和对象消息)。
消息接口非常灵活,并提供了许多方式来定制消息的内容。
三、安装ActiveMQ
1、官网:http://activemq.apache.org/activemq-5140-release.html
2、下载安装包:
wget https://archive.apache.org/dist/activemq/5.14.0/apache-activemq-5.14.0-bin.tar.gz
解压包:tar -xzvf apache-activemq-5.14.0-bin.tar.gz
bin目录下启动: [root@mzf bin]# ./activemq start
查看activeqm是否启动:[root@mzf bin]# ps -ef|grep activemq
浏览器访问测试:http://172.22.219.197:8161/
注意:ActiveMQ的端口是:8161
默认用户名和密码都是:admin
关闭:bin目录下: [root@mzf bin]# ./activemq stop
四、队列模式(Queue)消息入门使用体验
1、创建消息生产者项目
1.1、引入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.com.qihang.activemq</groupId>
<artifactId>activemq-producer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>activemq-producer</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.15.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
1.2、代码
public class ActiveMQQueueApp {
private static final String URL = "tcp://172.22.219.197:61616";
private static final String queueName = "activemq_queue";
public static void main(String[] args) throws Exception {
// 1.创建连接工厂 ConnectionFactory
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(URL);
// 2.创建连接 Connection
Connection connection = connectionFactory.createConnection();
// 3.启动连接
connection.start();
// 4.创建会话 Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 5.创建一个目标 Destination
Destination destination = session.createQueue(queueName);
// 6.创建生产者 Producer
MessageProducer messageProducer = session.createProducer(destination);
for (int i = 0; i < 50; i++) {
// 7.创建消息 Message
TextMessage textMessage = session.createTextMessage("test" + i);
// 8.发布消息
messageProducer.send(textMessage);
System.out.println("发送消息:" + textMessage.getText());
}
//9.关闭连接
connection.close();
}
}
1.3、启动ActiveMQ服务访问测试 activemq start
- 运行run main 方法
2、创建消息消费者项目
2.1、代码
public class ActiveMQConsumerApp {
private static final String URL = "tcp://172.22.219.197:61616";
private static final String queueName = "activemq_queue";
public static void main(String[] args) throws Exception {
// 1.创建连接工厂 ConnectionFactory
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(URL);
// 2.创建连接 Connection
Connection connection = connectionFactory.createConnection();
// 3.启动连接
connection.start();
// 4.创建会话 Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 5.创建一个目标 Destination
Destination destination = session.createQueue(queueName);
// 6.创建消费者 Consumer
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();
}
}
});
// 8.关闭连接
//监听是异步的,所以关闭会出现收不到的问题
//connection.close();
}
}
2.2、测试消费刷新查看监控台信息
五、主题模式(Topic)消息入门体验
1、主题消息生产者代码
public class ActiveMQProducerApp {
private static final String URL = "tcp://172.22.219.197:61616";
private static final String queueName = "activemq_topic";
public static void main(String[] args) throws Exception {
// 1.创建连接工厂 ConnectionFactory
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(URL);
// 2.创建连接 Connection
Connection connection = connectionFactory.createConnection();
// 3.启动连接
connection.start();
// 4.创建会话 Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 5.创建一个目标 Destination
Destination destination = session.createTopic(queueName);
// 6.创建生产者 Producer
MessageProducer messageProducer = session.createProducer(destination);
for (int i = 0; i < 50; i++) {
// 7.创建消息 Message
TextMessage textMessage = session.createTextMessage("test" + i);
// 8.发布消息
messageProducer.send(textMessage);
System.out.println("发送消息:" + textMessage.getText());
}
//9.关闭连接
connection.close();
}
}
2、主题消息消费者代码
public class ActiveMQConsumerApp {
private static final String URL = "tcp://172.22.219.197:61616";
private static final String queueName = "activemq_topic";
public static void main(String[] args) throws Exception {
// 1.创建连接工厂 ConnectionFactory
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(URL);
// 2.创建连接 Connection
Connection connection = connectionFactory.createConnection();
// 3.启动连接
connection.start();
// 4.创建会话 Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 5.创建一个目标 Destination
Destination destination = session.createTopic(queueName);
// 6.创建消费者 Consumer
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();
}
}
});
// 8.关闭连接
//监听是异步的,所以关闭会出现收不到的问题
//connection.close();
}
}
3、启动测试:注意要先启动消息消费订阅者,然后再发送消息,不然会收不到消息。
更多可以学习:https://www.cnblogs.com/zeng1994/p/5f9cd67f9ca155e8329263a2e5467aa4.html