笔记
- 下载
- 安装
- 使用XShell上传到Linux服务器
- 解压即可使用
- 版本查看可以通过release notes
- 配置
- 重要配置文件
- activemq.xml
- jetty.xml
- users.properties
- 启动
- 浏览器访问
- 开放8161端口
- 可通过浏览器访问
- 启动成功
- 重启
- 停止
- 简介
- 核心概念
- 开发相关知识
- 应用
- 开放61616端口
- 导包
- PTP处理模式(Queue)- 主动消费
- Producer
- Consumer
- PTP处理模式(Queue)- 观察者模式
- Producer
- Consumer
- 运行结果
- Publish & Subscribe处理模式(Topic)
- Producer
- Consumer
- 运行结果
- 安全认证
- 第一步:开启安全认证
- 第二步:提供用户名、密码
- 第三步:提供用户组信息
- 重新启动activemq服务即可
- 持久化策略
- kahadb方式(默认)
- JDBC+MySQL持久化
- 配置步骤
- 注意
- 图示:
- 主从模型
- 安装Zookeeper
- 下载并解压
- 配置Zookeeper
- 步骤
- 观察主从
- 访问
- ActiveMQ主从搭建
- 步骤
- java访问主从
- 集群
- Spring整合ActiveMQ
- 生产者
- 消费者
下载
安装
使用XShell上传到Linux服务器
解压即可使用
tar -zxvf 文件名
参数 | 含义 |
z | 通过gzip指令处理备份文件 |
x | 从备份文件中还原文件 |
v | 显示指令执行过程 |
f | 指定备份文件 |
版本查看可以通过release notes
因为我安装的JDK版本为1.7,所以下载了5.9.0版本的activemq;如果使用5.10.x,需要安装JDk1.8+;
配置
重要配置文件
activemq.xml
配置的是 ActiveMQ 应用使用的默认对象组件
jetty.xml
配置 jetty 服务器的默认对象组件
users.properties
内容信息: 用户名=密码,是用于配置客户端通过协议访问 ActiveMQ 时,使用的用户名和密码.
启动
命令:
路径/bin/activemq start
浏览器访问
activemq部署在jetty服务器上,启动activemq时,jetty相关服务也会被启动,我们可以通过浏览器访问!!!
开放8161端口
- jetty默认端口是8161,所以需要开放8161端口。修改
/etc/sysconfig/iptables
文件 - 重启服务:
service iptables restart
可通过浏览器访问
通过ip:8161/admin
访问,用户名和密码都为admin,因为users.properties
文件中最初就保存了这组用户名和密码。
启动成功
重启
命令:
路径/bin/activemq restart
停止
命令:
路径/bin/activemq stop
简介
核心概念
关键词 | 概念 |
Destination | 消息发送和获取的目的地,JMS Provider(消息中间件)负责维护,用于对 Message 进行管理的对象。 MessageProducer 需要指定 Destination 才能发送消息,MessageConsumer 需要指定 Destination 才能接收消息。 |
Producer | 消 息 生成 者 (客 户 端、 生 成 消 息 ), 负 责 发送 Message 到 目 的地 。 应 用 接口 为 MessageProducer。在 JMS 规范中,所有的标准定义都在 javax.jms 包中。 |
Consumer | 消息消费者(处理消息),负责从目的地中消费【处理|监听|订阅】Message。应用接口 为 MessageConsumer |
Message | 消息(Message),消息封装一次通信的内容。常见类型有:StreamMessage、BytesMessage、 TextMessage、ObjectMessage、MapMessage。 |
开发相关知识
关键词 | 概念 |
ConnectionFactory | 链接工厂, 用于创建链接的工厂类型。 注意,不能和 JDBC 中的 ConnectionFactory 混 淆。 |
Connection | 链接. 用于建立访问 ActiveMQ 连接的类型, 由链接工厂创建. 注意,不能和 JDBC 中的 Connection 混淆。 |
Session | 会话, 一次持久有效有状态的访问. 由链接创建. 是具体操作消息的基础支撑。 |
Queue | Queue 是队列形式的目的地,是 Destination 的子接口,Queue 特点: 队列中的消息,默认只能由唯一的一个消费者处理。一旦处理消息删除。 |
Topic | Topic 是主题形式目的地,是 Destination 的子接口,Topic 特点:主题中的消息,会发送给所有的消费者同时处理。只有在消息可以重复处理的业务场景中可使用。 |
PTP | Point to Point。点对点消息模型。就是基于 Queue 实现的消息处理方式。 |
PUB & SUB | Publish & Subscribe 。消息的发布/订阅模型。是基于 Topic 实现的消息处理方式。 |
应用
activemq默认端口为61616,所以发送消息和消费消息时,端口应该是61616,而不是jetty的8161。activemq是部署在jetty服务器上的类似于你将web项目部署在tomcat上。
开放61616端口
linux服务器需要开放61616端口,才能被外部主机访问到。
导包
导入
activemq-all-XXX.jar
- 如:
PTP处理模式(Queue)- 主动消费
Producer
- 代码
public class PTP_Producer {
// 连接工厂
private ConnectionFactory factory = null;
// 连接
private Connection conn = null;
// 会话
private Session session = null;
// 目的地
private Destination destination = null;
// 消息生产者
private MessageProducer producer = null;
// 消息
private TextMessage textMessage = null;
private void sendMessage(String message) {
factory = new ActiveMQConnectionFactory("admin", "admin", "tcp://192.168.65.128:61616");
try {
conn = factory.createConnection();
conn.start();
// 不是批量发送,不建议开启事务
// 开启客户端确认消息
session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
destination = session.createQueue("first");
producer = session.createProducer(destination);
textMessage = session.createTextMessage(message);
producer.send(textMessage);
System.out.println("消息已发送!");
} catch (JMSException e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
PTP_Producer p = new PTP_Producer();
p.sendMessage("hello world!");
}
}
- 运行结果
可以看到,消息生产者成功创建了一个名为first的队列,并发送了一条消息!!!
Consumer
public class PTP_Consumer {
// 连接工厂
private ConnectionFactory factory = null;
// 连接
private Connection conn = null;
// 会话
private Session session = null;
// 目的地
private Destination destination = null;
// 消息
private TextMessage message = null;
// 消息消费者
private MessageConsumer consumer = null;
// 返回结果
private static String text = null;
public String receive() {
factory = new ActiveMQConnectionFactory("admin", "admin", "tcp://192.168.65.128:61616");
try {
conn = factory.createConnection();
conn.start();
// 开启自动确认
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("first");
consumer = session.createConsumer(destination);
message = (TextMessage) consumer.receive();
text = message.getText();
} catch (JMSException e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
return text;
}
public static void main(String[] args) {
PTP_Consumer c = new PTP_Consumer();
String receive = c.receive();
System.out.println(receive);
}
}
- 运行结果
消费者从队列中取出消息并确认消费!!!并且,如果队列中没有消息时,消费者会阻塞等待,直到有生产者发送了消息,但可以设置等待时长!
PTP处理模式(Queue)- 观察者模式
对消费者使用监听的方式,实现消息的处理,可以一次性注册多个consumer。给consumer注册监听器后,只要线程不关闭,就会一直轮询处理Queue中的消息。
Producer
- 代码
public class PTP_Producer_Listener {
// 连接工厂
private ConnectionFactory factory = null;
// 连接
private Connection connection = null;
// 会话
private Session session = null;
// 目的地
private Destination destination = null;
// 消息生产者
private MessageProducer producer = null;
// 消息
private TextMessage textMessage = null;
public void sendMessage(String message) {
factory = new ActiveMQConnectionFactory("admin", "admin", "tcp://192.168.65.128:61616");
try {
connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
destination= session.createQueue("first-listener");
producer = session.createProducer(destination);
// 发送50条消息到队列中
for(int i = 0; i < 50; i++) {
textMessage = session.createTextMessage(message + " " + i);
producer.send(textMessage);
}
System.out.println("消息已发送!");
} catch (JMSException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
PTP_Producer_Listener p = new PTP_Producer_Listener();
p.sendMessage("hello world!");
}
}
Consumer
- 代码
public class PTP_Consumer_Listener {
// 连接工厂
private ConnectionFactory factory = null;
// 连接
private Connection connection = null;
// 会话
private Session session = null;
// 消费者
private MessageConsumer consumer = null;
// 目的地
private Destination destination = null;
// 消息
private TextMessage textMessage = null;
private void receive() {
factory = new ActiveMQConnectionFactory("admin", "admin", "tcp://192.168.65.128:61616");
try {
connection = factory.createConnection();
connection.start();
// 设置确认消息方式为客户端确认
session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
destination = session.createQueue("first-listener");
consumer = session.createConsumer(destination);
/**
* 设置消息监听器,当队列中有新消息时,会自动执行onMessage方法
*/
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
// 确认消息
try {
message.acknowledge();
textMessage = (TextMessage) message;
String text = textMessage.getText();
System.out.println(text);
} catch (JMSException e) {
e.printStackTrace();
}
}
});
// 阻塞,保证程序不会结束运行,监听不关闭
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
} catch (JMSException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
PTP_Consumer_Listener c = new PTP_Consumer_Listener();
c.receive();
}
}
运行结果
运行前,先启动两个consumer,再由producer发送50条消息到Queue中,观察结果。
可以看到,两个consumer交替从队列中取出消息。
Publish & Subscribe处理模式(Topic)
和PTP模式不同,发布到topic中的消息被所有订阅该topic的订阅者消费。当生产者发布消息时,无论有无消费者,topic都不做保留,无消费者时直接丢弃消息。所以,一定要先有消费者,后有生产者。
Producer
- 代码
public class Topic_Producer {
// 连接工厂
private ConnectionFactory factory = null;
// 连接
private Connection connection = null;
// 会话
private Session session = null;
// 目的地
private Destination destination = null;
// 生产者
private MessageProducer producer = null;
// 消息
private TextMessage textMessage = null;
private void sendMessage(String message) {
factory = new ActiveMQConnectionFactory("admin", "admin","tcp://192.168.65.128:61616");
try {
connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = session.createTopic("first-topic");
producer = session.createProducer(destination);
textMessage = session.createTextMessage(message);
producer.send(textMessage);
System.out.println("消息已发送!");
} catch (JMSException e) {
e.printStackTrace();
} finally{
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Topic_Producer p = new Topic_Producer();
p.sendMessage("this is a broadcast message!");
}
}
Consumer
- 代码
public class Topic_Consumer {
// 连接工厂
private ConnectionFactory factory = null;
// 连接
private Connection connection = null;
// 会话
private Session session = null;
// 目的地
private Destination destination = null;
// 生产者
private MessageConsumer consumer = null;
// 消息
private TextMessage textMessage = null;
private void receive() {
factory = new ActiveMQConnectionFactory("admin", "admin", "tcp://192.168.65.128:61616");
try {
connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = session.createTopic("first-topic");
consumer = session.createConsumer(destination);
textMessage = (TextMessage) consumer.receive();
String text = textMessage.getText();
System.out.println(text);
} catch (JMSException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Topic_Consumer c = new Topic_Consumer();
c.receive();
}
}
运行结果
先启动了3个consumer,接着启动producer发送消息。
结果显示,3个consumer都接收到了producer发送的消息。
安全认证
即用户名、密码登录规则,需要再核心配置中开启安全认证,即
conf/acticemq.xml
的broker
标签。
第一步:开启安全认证
在
<broker>
标签中添加<plugins>
标签
标签 | 作用 | 对应文件 |
| 配置安全认证信息 | – |
| 添加 jaas 认证插件,activemq 在 login.config 里面定义 |
|
| 层层嵌套,最中间添加详细配置 | – |
| 配置需要进行安全验证的topic,名字为“>”是代表全部 |
|
| 配置需要进行安全验证的queue,名字为“>”是代表全部 |
|
| 这个必须配置,不能少! | – |
| 这个必须配置,不能少! | – |
<plugins>
<!-- use JAAS to authenticate using the login.config file on the classpath to configure JAAS -->
<!-- 添加 jaas 认证插件 activemq 在 login.config 里面定义,详细见 login.config-->
<jaasAuthenticationPlugin configuration="activemq" />
<authorizationPlugin>
<map>
<authorizationMap>
<authorizationEntries>
<authorizationEntry topic=">" read="admins" write="admins" admin="admins" />
<authorizationEntry queue=">" read="admins" write="admins" admin="admins" />
<authorizationEntry topic="ActiveMQ.Advisory.>" read="admins" write="admins" admin="admins"/>
<authorizationEntry queue="ActiveMQ.Advisory.>" read="admins" write="admins" admin="admins"/>
</authorizationEntries>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
- login.config
第二步:提供用户名、密码
- users.properties
格式:
用户名=密码
第三步:提供用户组信息
- group.properties
格式:
用户组名=用户名,用户名,。。。。
重新启动activemq服务即可
- 这时,在创建ConnectionFactory是,需要如果访问某个设置了安全认证的topic或者queue,需要输入对应用户组中存在的用户名和密码,正确后才可访问!!!
持久化策略
指对消息数据的持久化,在ActiveMQ中,默认的消息是保存在内存中的,当内存容量不足,或ActiveMQ正常关闭的时候,会将内存中未处理的消息持久化到磁盘中,具体的持久化策略有配置文件中的具体配置决定。
持久化配置在conf/activemq.xml
该配置文件中,使用<broker>
标签定义。
kahadb方式(默认)
- 特点:
① 日志形式存储数据;
② 消息索引以B-Tree结构存储,可以快速更新;
③ 完全支持KMS事务;
④ 支持多种恢复机制;
- 配置
<persistenceAdapter>
<!-- directory: 保存数据的目录
journalMaxFileLength:保存消息的文件大小,每个文件
-->
<kahaDB directory="${activemq.data}/kahadb" journalMaxFileLegth="16mb"/>
</persistenceAdapter>
- 测试
① 先往队列中发送一条消息,如:“hello”;
② 不消费消息,关闭activemq服务;
③ 再次启动activemq服务,可看到消息还在队列中,取出消息;
JDBC+MySQL持久化
配置步骤
第一步:在
activemq.xml
中创建数据源
<bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activemq?relaxAutoCommit=true"/>
<property name="username" value="activemq"/>
<property name="password" value="activemq"/>
<property name="maxActive" value="200"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
第二步:在
<broker>
标签中配置mysql持久化
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#mysql-ds" createTablesOnStartup="false"/>
</persistenceAdapter>
第三步:将mysql的驱动包放入activemq的lib目录下,注意jdk版本哈,深坑,勿爬!
注意
ActiveMQ可自动创建表格,但是不能创建数据库。
createTablesOnStartup
默认为true,一般是第一次启动为true,之后修改为false,否则之前持久化的数据会被删除!!!
图示:
当第一次启动后,会自动创建3个表,查看数据库:
这时,要记得将
createTablesOnStartup
中的true
改成false
!!!
我们发送一条消息:
查看数据库:
数据已经持久化到数据库中
这时我们将这条消息消费掉:
数据库中的消息被删除!
主从模型
主从模式是一种高可用解决方案。在 ZooKeeper 中注册若干 ActiveMQ Broker,其中只 有一个 Broker 提供对外服务(Master),其他 Broker 处于待机状态(Slave)。当 Master 出现 故障导致宕机时,通过 ZooKeeper 内部的选举机制,选举出一台 Slave 替代 Master 继续对外 提供服务。
安装Zookeeper
ActiveMQ集群依赖于Zookeeper
下载并解压
我这里使用的是zookeeper-3.4.6这个版本。
配置Zookeeper
在本机搭建伪集群,安装三个Zookeeper实例,使用不同端口实现同时开启。端口分配如下:
主机 | 服务端口 | 投票端口 | 选举端口 |
192.168.65.128 | 2181 | 2881 | 3881 |
192.168.65.128 | 2182 | 2882 | 3882 |
192.168.65.128 | 2183 | 2883 | 3883 |
步骤
- ①修改名称:zk_01(可不修改)
mv zookeeper-3.4.6 zk_01
- ②在zk_01中创建data数据目录
mkdir data
- ③为zookeeper增加服务命名
在data目录中增加文件myid,内部定义每个服务的编号,编号要求为数字,是正整数,使用回声命名快捷定义myid文件:
echo 1 >> myid
- ④创建zookeeper配置文件
zookeeper默认读取
conf/zoo.cfg
配置文件,但是只提供给我们一个zoo_simple.cfg
文件,所以我们复制一份到zoo.cfg
- ⑤编写Zookeeper配置文件
1、修改数据目录为data目录
2、修改服务端口
3、配置集群,提供多节点服务:server.编号=IP:投票端口:选举端口
,三个zookeeper此应用配置一致;
- ⑥将zk_01复制三份,重复第⑤步,依次修改对应的服务编号、data目录和服务端口
- ⑦启动
命令:
bin/zkServer.sh start
观察主从
当启动完毕后,怎么判断哪个是主机哪个是从机呢?
命令:/bin/zkServer.sh status
从机:
主机:
访问
命令:
bin/zkCli.sh
ActiveMQ主从搭建
搭建ActiveMQ伪集群,安装三个实例,使用不同端口实现同时启动,端口分配如下:
主机 | M-S通讯端口 | 服务端口 | jetty端口 |
192.168.65.128 | 62626 | 61616 | 8161 |
192.168.65.128 | 62627 | 61617 | 8162 |
192.168.65.128 | 62628 | 61618 | 8163 |
步骤
- ①将activemq复制三份,分别命名为mq_1、mq-2、mq_3
- ②修改jetty端口,
conf/jetty.xml
端口分别是:8161、8162、8163
- ③统一所有主从节点broker命名,
conf/activemq.xml
修改
<broker>
标签属性brokerName="统一名称"
- ③修改持久化配置,
conf/activemq.xml
修改
<broker>
标签中的<persistenceAdapter>
相关内容:
属性 | 含义 |
replicas | 代表当前主从模型中的节点数量 |
bind | bind 属性中的端口为主从实例之间的通讯端口。代表当前实例对外开放端口是什么,三 个实例分别使用 62626、62627、62628 端口。 |
zkAddress | 代表 ZooKeeper 安装位置,安装具体情况设置 |
zkPath | 是 ActiveMQ 主从信息保存到 ZooKeeper 中的什么目录内 |
hostname | 为 ActiveMQ 实例安装 Linux 的主机名,可以在/etc/hosts 配置文件中设置。设 置格式为:IP 主机名。 如: 127.0.0.1 mq-server。这里需要修改主机名 |
<persistenceAdapter>
<!-- <kahaDB directory="${activemq.data}/kahadb"/> -->
<replicatedLevelDB
directory="${activemq.data}/levelDB"
replicas="3"
bind="tcp://0.0.0.0:62626"
zkAddress="192.168.65.128:2181,192.168.65.128:2182,192.168.65.128:2183"
zkPath="/activemq/leveldb-stores"
hostname="mq-server"
/>
</persistenceAdapter>
- ④修改主机名,
etc/hosts
在/etc/hosts 配置文件中设置。设 置格式为:IP 主机名。 如: 127.0.0.1 mq-server
修改完成:ping mq-server
- ⑤修改ActiveMQ对外提供服务的端口,
conf/activemq.xml
默认为61616,这里使用的是61616、61617、61618,依次做修改。修改
<broker>
标签的子标签<transportConnectors>
内容即可。
- ⑥启动主从
命令:
bin/activemq start
可通过jps
查看
- ⑦查看主从状态
使用客户端连接zookeeper:
${zkHome}/bin/zkCli.sh
查看状态信息:
连接成功后,可以使用命令ls /
查看 ZooKeeper 中的目录结构;
ls /activemq/leveldb-stores
找到对应的内容后,可以使用命令get
查看 ZooKeeper 中的数据内容
其中主节点的 elected 及 address 属性一定有数据。从节点则数据为‘null’。
主节点:
从节点:
- ⑧使用jetty访问时,只有主机的控制台可以访问,从机是不可访问的,只有等主机宕机后,由zookeeper投票选出主机后,那台主机的jetty控制台才可以被访问。
java访问主从
factory = new ActiveMQConnectionFactory("admin", "admin",
"failover:(tcp://192.168.65.128:61616,
tcp://192.168.65.128:61617,
tcp://192.168.65.128:61618)");
集群
准备多份主从模型。在所有的 ActiveMQ 节点中的
conf/activemq.xml
中增加下述配置: (每个主从模型中的 networkConnector 都指向另外一个主从模型)
<networkConnectors>
<networkConnector uri="static://(tcp://ip:port,tcp://ip:port)" duplex="false">
</networkConnector>
</networkConnectors>
注意配置顺序,Networks 相关配置必须在持久化相关配置之前。如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://activemq.apache.org/schema/core">
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="mq-cluster" dataDirectory="${activemq.data}" >
<networkConnectors>
<networkConnector uri=" static://(tcp://ip:port,tcp://ip:port)"/>
</networkConnectors>
<persistenceAdapter>
< replicatedLevelDB directory = "xxx"/>
</persistenceAdapter>
</broker>
</beans>
Spring整合ActiveMQ
生产者
- 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置ActiveMQ连接工厂信息 -->
<bean id="factory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="userName" value="admin"/>
<property name="password" value="admin"/>
<property name="brokerURL" value="tcp://192.168.65.128:61616"/>
</bean>
<!-- spring接管ActiveMQ连接工厂,产生jms连接工厂 -->
<bean id="jmsFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="factory"/>
</bean>
<!-- 配置生产者 -->
<!-- 配置spring提供的模板JMSTepleate-->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsFactory"/>
</bean>
<!-- 配置队列目的地-->
<bean id="myQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>
queue
</value>
</constructor-arg>
</bean>
<!-- 配置主题目的地 -->
<bean id="myTopic" class="org.apache.activemq.command.ActiveMQTempTopic">
<constructor-arg>
<value>
topic
</value>
</constructor-arg>
</bean>
</beans>
- 测试代码
public class Producer {
public static void main(String[] args) {
// 初始化spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext_producer.xml");
// 从spring容器中获取JMSTemplate
JmsTemplate template = ctx.getBean("jmsTemplate", JmsTemplate.class);
// 从spring容器中获取目的对象
Destination destination = ctx.getBean("myQueue", Destination.class);
// 发送消息
template.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage textMessage = session.createTextMessage("test spring-activemq");
return textMessage;
}
});
System.out.println("消息已发送");
}
}
消费者
- 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置ActiveMQ连接工厂信息 -->
<bean id="factory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="userName" value="admin"/>
<property name="password" value="admin"/>
<property name="brokerURL" value="tcp://192.168.65.128:61616"/>
</bean>
<!-- spring接管ActiveMQ连接工厂,产生jms连接工厂 -->
<bean id="jmsFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="factory"/>
</bean>
<!-- 配置消费者 -->
<!-- 配置spring提供的模板JMSTepleate-->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsFactory"/>
</bean>
<!-- 配置队列目的地-->
<bean id="myQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>
queue
</value>
</constructor-arg>
</bean>
<!-- 配置主题目的地 -->
<bean id="myTopic" class="org.apache.activemq.command.ActiveMQTempTopic">
<constructor-arg>
<value>
topic
</value>
</constructor-arg>
</bean>
<!-- 开启,配置消息监听器 -->
<!-- <bean id="listener" class="testConsumer.ConsumerListener"></bean> -->
<!-- 监听容器 -->
<!-- <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="jmsFactory"></property>
<property name="destination" ref="myQueue"></property>
<property name="messageListener" ref="listener"></property>
</bean> -->
</beans>
- 测试类
public class Consumer {
public static void main(String[] args) {
// 初始化spring容器
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath:applicationContext_consumer.xml");
// 无监听获取消息
method_noListener(ctx);
// 阻塞监听
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void method_noListener(ApplicationContext ctx) {
// 从spring容器中获取JMSTemplate
JmsTemplate template = ctx.getBean("jmsTemplate", JmsTemplate.class);
// 从spring容器中获取目的对象
Destination destination = ctx.getBean("myQueue", Destination.class);
// 接收消息
Message message = template.receive(destination);
TextMessage textMessage = (TextMessage) message;
try {
String text = textMessage.getText();
System.out.println(text);
} catch (JMSException e1) {
e1.printStackTrace();
}
}
}
- 如果开启了监听,需要一个监听器类
public class ConsumerListener implements MessageListener{
public void onMessage(Message message) {
TextMessage tm = (TextMessage) message;
try {
String text = tm.getText();
System.out.println("收到消息: "+text);
} catch (JMSException e) {
e.printStackTrace();
}
}
}