ActiveMQ

ActiveMQ


一、 ActiveMQ 简介


1 什么是 ActiveMQ


ActiveMQ 是 Apache 出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个
完全支持 JMS1.1 和 J2EE 1.4 规范的 JMS Provider 实现,尽管 JMS 规范出台已经是很久
的事情了,但是 JMS 在当今的 J2EE 应用中间仍然扮演着特殊的地位。


2 什么是消息


“消息”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;
也可以更复杂,可能包含嵌入对象。


3 什么是队列

4 什么是消息队列


“消息队列”是在消息的传输过程中保存消息的容器。


5 常用消息服务应用


5.1ActiveMQ


ActiveMQ 是 Apache 出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完
全支持 JMS1.1 和 J2EE 1.4 规范的 JMS Provider 实现。


5.2RabbitMQ


RabbitMQ 是一个在 AMQP 基础上完成的,可复用的企业消息系统。他遵循 Mozilla Public
License 开源协议。开发语言为 Erlang。


5.3RocketMQ


由阿里巴巴定义开发的一套消息队列应用服务。


二、 消息服务的应用场景


消息队列的主要特点是异步处理,主要目的是减少请求响应时间和解耦。所以主要的使
用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。同
时由于使用了消息队列,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,
也不需要受对方的影响,即解耦和。

5.1异步处理


5.1.1 用户注册


用户注册流程:
1)注册处理以及写数据库
2)发送注册成功的手机短信
3)发送注册成功的邮件信息
如果用消息中间件:则可以创建两个线程来做这些事情,直接发送消息给消息中间件,
然后让邮件服务和短信服务自己去消息中间件里面去取消息,然后取到消息后再自己做对应
的业务操作。就是这么方便


5.2应用的解耦


5.2.1 订单处理


生成订单流程:
1)在购物车中点击结算
2)完成支付
3)创建订单
4)调用库存系统
订单完成后,订单系统并不去直接调用库存系统,而是发送消息到消息中间件,写入一
个订单信息。库存系统自己去消息中间件上去获取,然后做发货处理,并更新库存,这样能
够实现互联网型应用追求的快这一个属性。而库存系统读取订单后库存应用这个操作也是非
常快的,所以有消息中间件对解耦来说也是一个不错的方向。


5.3流量的削峰


5.3.1 秒杀功能


秒杀流程:
1)用户点击秒杀
2)发送请求到秒杀应用
3)在请求秒杀应用之前将请求放入到消息队列
4)秒杀应用从消息队列中获取请求并处理。
比如,系统举行秒杀活动,热门商品。流量蜂拥而至 100 件商品,10 万人挤进来怎么
办?10 万秒杀的操作,放入消息队列。秒杀应用处理消息队列中的 10 万个请求中的前 100
个,其他的打回,通知失败。流量峰值控制在消息队列处,秒杀应用不会瞬间被怼死

 

三、 JMS


1 什么是 JMS


JMS(Java Messaging Service)是 Java 平台上有关面向消息中间件的技术规范,它便于
消息系统中的 Java 应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接
口,简化企业应用的开发。


2 JMS 模型


2.1点对点模型(Point To Point)


生产者发送一条消息到 queue,只有一个消费者能收到

2.2发布订阅模型(Publish/Subscribe)


发布者发送到 topic 的消息,只有订阅了 topic 的订阅者才会收到消息

四、 ActiveMQ 安装


1 下载资源


ActiveMQ 官网: http://activemq.apache.org

1.1版本说明


ActiveMQ5.10.x 以上版本必须使用 JDK1.8 才能正常使用。
ActiveMQ5.9.x 及以下版本使用 JDK1.7 即可正常使用。


2 上传至 Linux 服务器


3 解压安装文件


tar -zxf apache-activemq-5.9.0-bin.tar.gz


4 检查权限


ls -al apache-activemq-5.9.0/bin
如果权限不足,则无法执行,需要修改文件权限:
chmod 755 activemq

5 复制应用至本地目录

cp -r apache-activemq-5.9.0 /usr/local/activemq


6 启动 ActiveMQ


/usr/local/activemq/bin/activemq start


7 测试 ActiveMQ

7.1检查进程

ps aux | grep activemq


见到下述内容即代表启动成功

7.2管理界面


使用浏览器访问 ActiveMQ 管理应用, 地址如下:
http://ip:8161/admin/
用户名: admin
密码: admin
ActiveMQ 使用的是 jetty 提供 HTTP 服务.启动稍慢,建议短暂等待再访问测试.
见到如下界面代表服务启动成功

7.3修改访问端口


修改 ActiveMQ 配置文件: /usr/local/activemq/conf/jetty.xml

配置文件修改完毕,保存并重新启动 ActiveMQ 服务。


7.4修改用户名和密码


修改 conf/users.properties 配置文件.内容为: 用户名=密码
保存并重启 ActiveMQ 服务即可.


8 重启 ActiveMQ


/usr/local/activemq/bin/activemq restart


9 关闭 ActiveMQ


/usr/local/activemq/bin/activemq stop


10 配置文件 activemq.xml


配置文件中,配置的是 ActiveMQ 的核心配置信息. 是提供服务时使用的配置. 可以修改
启动的访问端口. 即 java 编程中访问 ActiveMQ 的访问端口.
默认端口为 61616.
使用协议是: tcp 协议.
修改端口后, 保存并重启 ActiveMQ 服务即可.


11 ActiveMQ 目录介绍


从它的目录来说,还是很简单的:
* bin 存放的是脚本文件
* conf 存放的是基本配置文件
* data 存放的是日志文件
* docs 存放的是说明文档
* examples 存放的是简单的实例
* lib 存放的是 activemq 所需 jar 包
* webapps 用于存放项目的目录


五、 ActiveMQ 术语


1 Destination
目的地,JMS Provider(消息中间件)负责维护,用于对 Message 进行管理的对象。
MessageProducer 需要指定 Destination 才能发送消息,MessageReceiver 需要指定 Destination
才能接收消息。


2 Producer


消息生成者,负责发送 Message 到目的地。


3 Consumer | Receiver


消息消费者,负责从目的地中消费【处理|监听|订阅】Message。


4 Message


消息,消息封装一次通信的内容。


六、 ActiveMQ 应用


1 ActiveMQ 常用 API 简介


下述 API 都是接口类型,由定义在 javax.jms 包中.
是 JMS 标准接口定义.


1.1ConnectionFactory


链接工厂, 用于创建链接的工厂类型.


1.2Connection


链接. 用于建立访问 ActiveMQ 连接的类型, 由链接工厂创建.


1.3Session


会话, 一次持久有效有状态的访问. 由链接创建.


1.4Destination & Queue


目的地, 用于描述本次访问 ActiveMQ 的消息访问目的地. 即 ActiveMQ 服务中的具体队
列. 由会话创建.
interface Queue extends Destination


1.5MessageProducer


消息生成者, 在一次有效会话中, 用于发送消息给 ActiveMQ 服务的工具. 由会话创建.


1.6MessageConsumer


消息消费者【消息订阅者,消息处理者】, 在一次有效会话中, 用于从 ActiveMQ 服务中
获取消息的工具. 由会话创建.


1.7Message


消息, 通过消息生成者向 ActiveMQ 服务发送消息时使用的数据载体对象或消息消费者
从 ActiveMQ 服务中获取消息时使用的数据载体对象. 是所有消息【文本消息,对象消息等】
具体类型的顶级接口. 可以通过会话创建或通过会话从 ActiveMQ 服务中获取

.2 JMS-HelloWorld

 


2.1处理文本消息


2.1.1 创建消息生产者


2.1.1.1 创建工程

2.1.1.2 修改 POM 文件添加 ActiveMQ 坐标

<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instan
ce"
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>com.bjsxt</groupId>
 <artifactId>mq-producer</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 
 <dependencies>
 <!--
https://mvnrepository.com/artifact/org.apache.acti
vemq/activemq-all -->
<dependency>
 <groupId>org.apache.activemq</groupId>
 <artifactId>activemq-all</artifactId>
 <version>5.9.0</version>
</dependency>
View Code

2.1.1.3 编写消息的生产者

public class HelloWorldProducer {
/**
* 生产消息
*/
public void sendHelloWorldActiveMQ(String 
msgTest){
//定义链接工厂
ConnectionFactory connectionFactory = null;
//定义链接对象
Connection connection = null;
//定义会话
Session session = null;
//目的地
Destination destination = null;
//定义消息的发送者
MessageProducer producer = null;
//定义消息
Message message = null;
try{
/**
* userName:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过
jetty-ream.properties 文件进行修改
* password:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过
jetty-ream.properties 文件进行修改
* brokerURL:访问 ActiveMQ 服务的路径地址。
路径结构为:协议名://主机地址:端口号
*/
connectionFactory = new
ActiveMQConnectionFactory("admin", "admin", 
"tcp://192.168.70.151:61616");
//创建连接对象
connection = 
connectionFactory.createConnection();
//启动连接
connection.start();
/**
* transacted:是否使用事务 可选值为:
true|false
* true:使用事务 当设置次变量
值。Session.SESSION_TRANSACTED
* false:不适用事务,设置次变量
则 acknowledgeMode 参数必须设置
* acknowledgeMode:
* Session.AUTO_ACKNOWLEDGE:自动消息确认
机制
* Session.CLIENT_ACKNOWLEDGE:客户端确认
机制
* Session.DUPS_OK_ACKNOWLEDGE:有副本的客
户端确认消息机制
*/
session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
//创建目的地,目的地名称即队列的名称。消息的
消费者需要通过此名称访问对应的队列
destination = 
session.createQueue("helloworld-destination");
//创建消息的生产者
producer = 
session.createProducer(destination);
//创建消息对象
message = 
session.createTextMessage(msgTest);
//发送消息
producer.send(message);
}catch(Exception e){
e.printStackTrace();
}finally{
//回收消息发送者资源
if(producer != null){
try {
producer.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(session != null){
try {
session.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
View Code

2.1.2 创建消息消费者


2.1.2.1 创建工程

2.1.2.2 修改 POM 文件添加 ActiveMQ 坐标

<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instan
ce"
xsi:schemaLocation="http://maven.apache.org/P
OM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bjsxt</groupId>
<artifactId>mq-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!--
https://mvnrepository.com/artifact/org.apache.acti
vemq/activemq-all -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.9.0</version>
</dependency>
</dependencies>
</project>
View Code

2.1.2.3 编写消息的消费者

public class HelloWorldConsumer {
/**
* 消费消息
*/
public void readHelloWorldActiveMQ() {
// 定义链接工厂
ConnectionFactory connectionFactory = null;
// 定义链接对象
Connection connection = null;
// 定义会话
Session session = null;
// 目的地
Destination destination = null;
// 定义消息的发送者
MessageConsumer consumer = null;
// 定义消息
Message message = null;
try {
/**
* userName:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过 jetty-ream.
* properties 文件进行修改
* password:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过 jetty-ream.
* properties 文件进行修改 brokerURL:访问
ActiveMQ 服务的路径地址。路径结构为:协议名://主机地址:
端口号
*/
connectionFactory = new
ActiveMQConnectionFactory("admin", "admin", 
"tcp://192.168.70.151:61616");
// 创建连接对象
connection = 
connectionFactory.createConnection();
// 启动连接
connection.start();
/**
* transacted:是否使用事务 可选值为:
true|false true:使用事务
* 当设置次变量值。
Session.SESSION_TRANSACTED false:不适用事务,设置次变
量
* 则 acknowledgeMode 参数必须设置
acknowledgeMode:
* Session.AUTO_ACKNOWLEDGE:自动消息确认机
制
* Session.CLIENT_ACKNOWLEDGE:客户端确认
机制
* Session.DUPS_OK_ACKNOWLEDGE:有副本的客
户端确认消息机制
*/
session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
// 创建目的地,目的地名称即队列的名称。消息
的消费者需要通过此名称访问对应的队列
destination = 
session.createQueue("helloworld-destination");
// 创建消息的消费者
consumer = 
session.createConsumer(destination);
// 创建消息对象
message = consumer.receive();
//处理消息
String msg = 
((TextMessage)message).getText();
System.out.println("从 ActiveMQ 服务中获取
的文本信息 "+msg);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 回收消息发送者资源
if (consumer != null) {
try {
consumer.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (session != null) {
try {
session.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
View Code

2.1.3 测试


2.1.3.1 Producer

public class Test {
public static void main(String[] args) {
HelloWorldProducer producer = new
HelloWorldProducer();
producer.sendHelloWorldActiveMQ("HelloWorld");
}
}
View Code

2.1.3.2 Consumer

public class Test {
public static void main(String[] args) {
HelloWorldConsumer consumer = new
HelloWorldConsumer();
consumer.readHelloWorldActiveMQ();
}
}
View Code

2.2处理对象消息


2.2.1 定义消息对象

public class Users implements Serializable{
private int userid;
private String username;
private int userage;
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getUserage() {
return userage;
}
public void setUserage(int userage) {
this.userage = userage;
}
@Override
public String toString() {
return "Users [userid=" + userid + ", 
username=" + username + ", userage=" + userage + "]";
}
}
View Code

2.2.2 创建生产者

public class HelloWorldProducer2 {
/**
* 生产消息
*/
public void sendHelloWorldActiveMQ(Users 
users){
//定义链接工厂
ConnectionFactory connectionFactory = null;
//定义链接对象
Connection connection = null;
//定义会话
Session session = null;
//目的地
Destination destination = null;
//定义消息的发送者
MessageProducer producer = null;
//定义消息
Message message = null;
try{
/**
* userName:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过
jetty-ream.properties 文件进行修改
* password:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过
jetty-ream.properties 文件进行修改
* brokerURL:访问 ActiveMQ 服务的路径地址。
路径结构为:协议名://主机地址:端口号
*/
connectionFactory = new
ActiveMQConnectionFactory("admin", "admin", 
"tcp://192.168.70.151:61616");
//创建连接对象
connection = 
connectionFactory.createConnection();
//启动连接
connection.start();
/**
* transacted:是否使用事务 可选值为:
true|false
* true:使用事务 当设置次变量值。
Session.SESSION_TRANSACTED
* false:不适用事务,设置次变量
则 acknowledgeMode 参数必须设置
* acknowledgeMode:
* Session.AUTO_ACKNOWLEDGE:自动消息确认机
制
* Session.CLIENT_ACKNOWLEDGE:客户端确认
机制
* Session.DUPS_OK_ACKNOWLEDGE:有副本的客
户端确认消息机制
*/
session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
//创建目的地,目的地名称即队列的名称。消息的
消费者需要通过此名称访问对应的队列
destination = 
session.createQueue("my-users");
//创建消息的生产者
producer = 
session.createProducer(destination);
//创建消息对象
message = 
session.createObjectMessage(users);
//发送消息
producer.send(message);
}catch(Exception e){
e.printStackTrace();
}finally{
//回收消息发送者资源
if(producer != null){
try {
producer.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(session != null){
try {
session.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
View Code

2.2.3 定义消息消费者

public class HelloWorldConsumer2 {
/**
* 消费消息
*/
public void readHelloWorldActiveMQ() {
// 定义链接工厂
ConnectionFactory connectionFactory = null;
// 定义链接对象
Connection connection = null;
// 定义会话
Session session = null;
// 目的地
Destination destination = null;
// 定义消息的发送者
MessageConsumer consumer = null;
// 定义消息
Message message = null;
try {
/**
* userName:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过 jetty-ream.
* properties 文件进行修改
* password:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过 jetty-ream.
* properties 文件进行修改 brokerURL:访问
ActiveMQ 服务的路径地址。路径结构为:协议名://主机地址:
端口号
*/
connectionFactory = new
ActiveMQConnectionFactory("admin", "admin", 
"tcp://192.168.70.151:61616");
// 创建连接对象
connection = 
connectionFactory.createConnection();
// 启动连接
connection.start();
/**
* transacted:是否使用事务 可选值为:
true|false true:使用事务
* 当设置次变量值。
Session.SESSION_TRANSACTED false:不适用事务,设置次变
量
* 则 acknowledgeMode 参数必须设置
acknowledgeMode:
* Session.AUTO_ACKNOWLEDGE:自动消息确认机
制
* Session.CLIENT_ACKNOWLEDGE:客户端确认
机制
* Session.DUPS_OK_ACKNOWLEDGE:有副本的客
户端确认消息机制
*/
session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
// 创建目的地,目的地名称即队列的名称。消息
的消费者需要通过此名称访问对应的队列
destination = 
session.createQueue("my-users");
// 创建消息的消费者
consumer = 
session.createConsumer(destination);
// 创建消息对象
message = consumer.receive();
//处理消息
ObjectMessage objMessage = 
(ObjectMessage)message;
Users users = 
(Users)objMessage.getObject();
System.out.println(users);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 回收消息发送者资源
if (consumer != null) {
try {
consumer.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (session != null) {
try {
session.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
View Code

3 JMS - 实现队列服务监听


队列服务监听使用的观察者设计模式


3.1创建消息生产者

public class HelloWorldProducer3 {
/**
* 生产消息
*/
public void sendHelloWorldActiveMQ(String 
msgTest){
//定义链接工厂
ConnectionFactory connectionFactory = null;
//定义链接对象
Connection connection = null;
//定义会话
Session session = null;
//目的地
Destination destination = null;
//定义消息的发送者
MessageProducer producer = null;
//定义消息
Message message = null;
try{
/**
* userName:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过
jetty-ream.properties 文件进行修改
* password:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过
jetty-ream.properties 文件进行修改
* brokerURL:访问 ActiveMQ 服务的路径地址。
路径结构为:协议名://主机地址:端口号
*/
connectionFactory = new
ActiveMQConnectionFactory("admin", "admin", 
"tcp://192.168.70.151:61616");
//创建连接对象
connection = 
connectionFactory.createConnection();
//启动连接
connection.start();
/**
* transacted:是否使用事务 可选值为:
true|false
* true:使用事务 当设置次变量值。
Session.SESSION_TRANSACTED
* false:不适用事务,设置次变量
则 acknowledgeMode 参数必须设置
* acknowledgeMode:
* Session.AUTO_ACKNOWLEDGE:自动消息确认机
制
* Session.CLIENT_ACKNOWLEDGE:客户端确认
机制
* Session.DUPS_OK_ACKNOWLEDGE:有副本的客
户端确认消息机制
*/
session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
//创建目的地,目的地名称即队列的名称。消息的
消费者需要通过此名称访问对应的队列
destination = 
session.createQueue("my-destination");
//创建消息的生产者
producer = 
session.createProducer(destination);
//创建消息对象
message = 
session.createTextMessage(msgTest);
//发送消息
producer.send(message);
}catch(Exception e){
e.printStackTrace();
}finally{
//回收消息发送者资源
if(producer != null){
try {
producer.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(session != null){
try {
session.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
View Code

3.2消息消费者

public class HelloWorldConsumer3 {
/**
* 消费消息
*/
public void readHelloWorldActiveMQ() {
// 定义链接工厂
ConnectionFactory connectionFactory = null;
// 定义链接对象
Connection connection = null;
// 定义会话
Session session = null;
// 目的地
Destination destination = null;
// 定义消息的发送者
MessageConsumer consumer = null;
// 定义消息
Message message = null;
try {
/**
* userName:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过 jetty-ream.
* properties 文件进行修改
* password:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过 jetty-ream.
* properties 文件进行修改 brokerURL:访问
ActiveMQ 服务的路径地址。路径结构为:协议名://主机地址:
端口号
*/
connectionFactory = new
ActiveMQConnectionFactory("admin", "admin", 
"tcp://192.168.70.151:61616");
// 创建连接对象
connection = 
connectionFactory.createConnection();
// 启动连接
connection.start();
/**
* transacted:是否使用事务 可选值为:
true|false true:使用事务
* 当设置次变量值。
Session.SESSION_TRANSACTED false:不适用事务,设置次变
量
* 则 acknowledgeMode 参数必须设置
acknowledgeMode:
* Session.AUTO_ACKNOWLEDGE:自动消息确认机
制
* Session.CLIENT_ACKNOWLEDGE:客户端确认
机制
* Session.DUPS_OK_ACKNOWLEDGE:有副本的客
户端确认消息机制
*/
session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
// 创建目的地,目的地名称即队列的名称。消息
的消费者需要通过此名称访问对应的队列
destination = 
session.createQueue("my-destination");
// 创建消息的消费者
consumer = 
session.createConsumer(destination);
consumer.setMessageListener(new
MessageListener() {
//ActiveMQ 回调的方法。通过该方法将消息传
递到 consumer
@Override
public void onMessage(Message message) 
{
//处理消息
String msg=null;
try {
msg = 
((TextMessage)message).getText();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("从 ActiveMQ 服务
中获取的文本信息 "+msg);
}
});
} catch (Exception e) {
e.printStackTrace();
} 
}
}
View Code

4 Topic 模型


4.1Publish/Subscribe 处理模式(Topic)


消息生产者(发布)将消息发布到 topic 中,同时有多个消息消费者(订阅)消费该消息。

和点对点方式不同,发布到 topic 的消息会被所有订阅者消费。
当生产者发布消息,不管是否有消费者。都不会保存消息
一定要先有消息的消费者,后有消息的生产者。

4.2创建生产者

public class HelloWorldProducerTopic {
/**
* 生产消息
*/
public void sendHelloWorldActiveMQ(String 
msgTest){
//定义链接工厂
ConnectionFactory connectionFactory = null;
//定义链接对象
Connection connection = null;
//定义会话
Session session = null;
//目的地
Destination destination = null;
//定义消息的发送者
MessageProducer producer = null;
//定义消息
Message message = null;
try{
/**
* userName:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过
jetty-ream.properties 文件进行修改
* password:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过
jetty-ream.properties 文件进行修改
* brokerURL:访问 ActiveMQ 服务的路径地址。
路径结构为:协议名://主机地址:端口号
*/
connectionFactory = new
ActiveMQConnectionFactory("admin", "admin", 
"tcp://192.168.70.151:61616");
//创建连接对象
connection = 
connectionFactory.createConnection();
//启动连接
connection.start();
/**
* transacted:是否使用事务 可选值为:
true|false
* true:使用事务 当设置次变量值。
Session.SESSION_TRANSACTED
* false:不适用事务,设置次变量
则 acknowledgeMode 参数必须设置
* acknowledgeMode:
* Session.AUTO_ACKNOWLEDGE:自动消息确认机
制
* Session.CLIENT_ACKNOWLEDGE:客户端确认
机制
* Session.DUPS_OK_ACKNOWLEDGE:有副本的客
户端确认消息机制
*/
session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
//创建目的地,目的地名称即队列的名称。消息的
消费者需要通过此名称访问对应的队列
destination = 
session.createTopic("test-topic");
//创建消息的生产者
producer = 
session.createProducer(destination);
//创建消息对象
message = 
session.createTextMessage(msgTest);
//发送消息
producer.send(message);
}catch(Exception e){
e.printStackTrace();
}finally{
//回收消息发送者资源
if(producer != null){
try {
producer.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(session != null){
try {
session.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
View Code

4.3创建消费者

public class HelloWorldConsumerTopic1 implements
Runnable{
/**
* 消费消息
*/
public void readHelloWorldActiveMQ() {
// 定义链接工厂
ConnectionFactory connectionFactory = null;
// 定义链接对象
Connection connection = null;
// 定义会话
Session session = null;
// 目的地
Destination destination = null;
// 定义消息的发送者
MessageConsumer consumer = null;
// 定义消息
Message message = null;
try {
/**
* userName:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过 jetty-ream.
* properties 文件进行修改
* password:访问 ActiveMQ 服务的用户名。用户
密码。默认的为 admin。用户名可以通过 jetty-ream.
* properties 文件进行修改 brokerURL:访问
ActiveMQ 服务的路径地址。路径结构为:协议名://主机地址:
端口号
*/
connectionFactory = new
ActiveMQConnectionFactory("admin", "admin", 
"tcp://192.168.70.151:61616");
// 创建连接对象
connection = 
connectionFactory.createConnection();
// 启动连接
connection.start();
/**
* transacted:是否使用事务 可选值为:
true|false true:使用事务
* 当设置次变量值。
Session.SESSION_TRANSACTED false:不适用事务,设置次变
量
* 则 acknowledgeMode 参数必须设置
acknowledgeMode:
* Session.AUTO_ACKNOWLEDGE:自动消息确认机
制
* Session.CLIENT_ACKNOWLEDGE:客户端确认
机制
* Session.DUPS_OK_ACKNOWLEDGE:有副本的客
户端确认消息机制
*/
session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
// 创建目的地,目的地名称即队列的名称。消息
的消费者需要通过此名称访问对应的队列
destination = 
session.createTopic("test-topic");
// 创建消息的消费者
consumer = 
session.createConsumer(destination);
consumer.setMessageListener(new
MessageListener() {
//ActiveMQ 回调的方法。通过该方法将消息传
递到 consumer
@Override
public void onMessage(Message message) 
{
//处理消息
String msg=null;
try {
msg = 
((TextMessage)message).getText();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("从 ActiveMQ 服务
中获取的文本信息 ---topic1 "+msg);
}
});
} catch (Exception e) {
e.printStackTrace();
} 
}
@Override
public void run() {
this.readHelloWorldActiveMQ();
}
}
View Code

七、 Spring 整合 ActiveMQ


1 创建 spring-activemq-producer


1.1修改 POM 文件

<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instan
ce"
xsi:schemaLocation="http://maven.apache.org/P
OM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.bjsxt</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>spring-activemq-producer</artifac
tId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- ActiveMQ 客户端完整 jar 包依赖 -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
</dependency>
<!-- ActiveMQ 和 Spring 整合配置文件标签处理 jar
包依赖 -->
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
</dependency>
<!-- Spring-JMS 插件相关 jar 包依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<!-- 日志处理 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<!-- JSP 相关 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 配置 Tomcat 插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<path>/</path>
<port>8080</port>
</configuration>
</plugin>
</plugins>
</build>
</project>
View Code

1.2整合 ActiveMQ

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans
"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-i
nstance"
xmlns:jms="http://www.springframework.org/sch
ema/jms"
xmlns:context="http://www.springframework.org
/schema/context"
xmlns:amq="http://activemq.apache.org/schema/
core"
xsi:schemaLocation="
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spr
ing-beans.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/sprin
g-jms.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq
-core.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/s
pring-context.xsd">
<!-- 需要创建一个连接工厂,连接 ActiveMQ. 
ActiveMQConnectionFactory. 需要依赖 ActiveMQ 提供的
amq 标签 -->
<!-- amq:connectionFactory 是 bean 标签的子标签, 
会在 spring 容器中创建一个 bean 对象.
可以为对象命名. 类似: <bean id="" 
class="ActiveMQConnectionFactory"></bean>
-->
<amq:connectionFactory
brokerURL="tcp://192.168.70.151:61616"
userName="admin" password="admin"
id="amqConnectionFactory"/>
<!-- spring 管理 JMS 相关代码的时候,必须依赖 jms 标
签库. spring-jms 提供的标签库. -->
<!-- 定义 Spring-JMS 中的连接工厂对象
CachingConnectionFactory - spring 框架提供的
连接工厂对象. 不能真正的访问 MOM 容器.
类似一个工厂的代理对象. 需要提供一个真实工
厂,实现 MOM 容器的连接访问.
-->
<bean id="pooledConnectionFactory"
class="org.apache.activemq.pool.PooledConnectio
nFactoryBean">
<property name="connectionFactory"
ref="amqConnectionFactory"></property>
<property name="maxConnections"
value="10"></property>
</bean>
<!-- 配置有缓存的 ConnectionFactory,session 的
缓存大小可定制。 -->
<bean id="connectionFactory"
class="org.springframework.jms.connection.Cachi
ngConnectionFactory">
<property name="targetConnectionFactory"
ref="pooledConnectionFactory"></property>
<property name="sessionCacheSize"
value="3"></property>
</bean>
<!-- JmsTemplate 配置 -->
<bean id="template"
class="org.springframework.jms.core.JmsTemplate">
<!-- 给定连接工厂, 必须是 spring 创建的连接工
厂. -->
<property name="connectionFactory"
ref="connectionFactory"></property>
<!-- 可选 - 默认目的地命名 -->
<property name="defaultDestinationName"
value="test-spring"></property>
</bean>
</beans>
View Code

2 创建 spring-activemq-consumer


是一个 jar 工程


2.1修改 POM 文件

<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instan
ce"
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>
 <parent>
 <groupId>com.bjsxt</groupId>
 <artifactId>parent</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 </parent>
 <groupId>com.bjsxt</groupId>
 
<artifactId>spring-activemq-consumer</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 
 <dependencies>
<!-- activemq 客户端 -->
<dependency>
 <groupId>org.apache.activemq</groupId>
 <artifactId>activemq-all</artifactId>
</dependency>
<!-- spring 框架对 JMS 标准的支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<!-- ActiveMQ 和 spring 整合的插件 -->
<dependency>
 <groupId>org.apache.xbean</groupId>
 <artifactId>xbean-spring</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
</dependencies>
</project>
View Code

2.2整合 ActiveMQ

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans
"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-i
nstance"
xmlns:jms="http://www.springframework.org/sch
ema/jms"
xmlns:amq="http://activemq.apache.org/schema/
core"
xsi:schemaLocation="
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spr
ing-beans.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/sprin
g-jms.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq
-core.xsd">
<!-- 需要创建一个连接工厂,连接 ActiveMQ. 
ActiveMQConnectionFactory. 需要依赖 ActiveMQ 提供的
amq 标签 -->
<!-- amq:connectionFactory 是 bean 标签的子标签, 
会在 spring 容器中创建一个 bean 对象.
可以为对象命名. 类似: <bean id="" 
class="ActiveMQConnectionFactory"></bean>
-->
<amq:connectionFactory
brokerURL="tcp://192.168.70.151:61616"
userName="admin" password="admin"
id="amqConnectionFactory"/>
<!-- spring 管理 JMS 相关代码的时候,必须依赖 jms 标
签库. spring-jms 提供的标签库. -->
<!-- 定义 Spring-JMS 中的连接工厂对象
CachingConnectionFactory - spring 框架提供的
连接工厂对象. 不能真正的访问 MOM 容器.
类似一个工厂的代理对象. 需要提供一个真实工
厂,实现 MOM 容器的连接访问.
-->
<bean id="connectionFactory"
class="org.springframework.jms.connection.Cachi
ngConnectionFactory">
<property name="targetConnectionFactory"
ref="amqConnectionFactory"></property>
<property name="sessionCacheSize"
value="3"></property>
</bean>
<!-- 注册监听器 -->
<!-- 开始注册监听. 
需要的参数有:
acknowledge - 消息确认机制
container-type - 容器类型 default|simple
simple:SimpleMessageListenerContainer 最
简单的消息监听器容器,只能处理固定数量的 JMS 会话,且不支
持事务。
default:DefaultMessageListenerContainer
是一个用于异步消息监听器容器 ,且支持事务 
destination-type - 目的地类型. 使用队列作
为目的地.
connection-factory - 连接工厂, spring-jms
使用的连接工厂,必须是 spring 自主创建的
不能使用三方工具创建的工程. 如: 
ActiveMQConnectionFactory.
-->
<jms:listener-container acknowledge="auto"
container-type="default"
destination-type="queue"
connection-factory="connectionFactory" >
<!-- 在监听器容器中注册某监听器对象.
destination - 设置目的地命名
ref - 指定监听器对象
-->
<jms:listener destination="test-spring"
ref="myListener"/>
</jms:listener-container>
</beans>
View Code

 

3 测试整合


需求:
1)在 producer 中创建 Users 对象
2)将 Users 对象传递到 ActiveMQ 中
3)在 Consumer 中获取 Users 对象并在控制台打印


3.1Producer 发送消息


3.1.1 如果使用了连接池需要添加两个坐标


PooledConnectionFactoryBean

<dependency>
 <groupId>org.apache.activemq</groupId>
 <artifactId>activemq-pool</artifactId>
 <version>5.9.0</version>
</dependency>
<dependency>
 <groupId>org.apache.activemq</groupId>
 
<artifactId>activemq-jms-pool</artifactId>
 <version>5.9.0</version>
</dependency>
View Code

3.1.2 发送消息

@Service
public class UserServiceImpl implements
UserService {
@Autowired
private JmsTemplate jmsTemplate;
@Override
public void addUser(final Users user) {
//发送消息
this.jmsTemplate.send(new MessageCreator() 
{
@Override
public Message createMessage(Session 
session) throws JMSException {
Message message = 
session.createObjectMessage(user);
return message;
}
});
}
}
View Code

3.2Consumer 接收消息


3.2.1 接收消息

@Component(value="myListener")
public class MyMessageListener implements
MessageListener{
@Autowired
private UserService userService;
@Override
public void onMessage(Message message) {
//处理消息
ObjectMessage objMessage = 
(ObjectMessage)message;
Users user=null;
try {
user = (Users)objMessage.getObject();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.userService.showUser(user);
}
}
View Code

 

posted @ 2019-06-20 21:33  wq9  阅读(1729)  评论(0编辑  收藏  举报