文章目录
ActiveMQ是什么
ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总想。
ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。
JMS是什么
Java消息服务(Java Message Service,即JMS)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API。
JMS的对象模型
ConnectionFactory | 连接工厂 |
---|---|
Connection | 连接 |
Session | 会话 |
Destination | 目的 |
MessageProducer | 生产者 |
MessageConsumer | 消费者 |
Message | 消息 |
Broker | 消息中间件的实例(ActiveMQ) |
JMS的消息模型
Point-to-Point (P2P) / 点对点
Publish/Subscribe (Pub/Sub) / 主题 (发布订阅)
JMS的消息结构
消息头
消息属性
消息属性
可以理解为消息的附加消息头,属性名可以自定义
属性值类型:boolean
、byte
、int
、long
、float
、double
、String
消息体
ActiveMQ的特性
- 支持多种编程语言
- 支持多种传输协议
- 有多种持久化方式
ActiveMQ安装
演示环境: Centos7、jdk8、activemq5.15.8
下载地址: http://activemq.apache.org/activemq-5158-release.html
或者cd /tmp
,再wget -c http://mirrors.shu.edu.cn/apache/activemq/5.15.8/apache-activemq-5.15.8-bin.tar.gz
,如果没有安装wget的话,可以先yum install wget
。
解压: tar -zxvf apache-activemq-5.15.8-bin.tar.gz -C /var
修改目录名称 mv /var/apache-activemq-5.15.8/ /var/activemq/
启动: ./bin/activemq start
停止:./bin/activemq stop
前面使用命令运行ActiveMQ,但最好的方法是将ActiveMQ作为服务启动,使用system服务将可以确保ActiveMQ能在系统启动时启动。
做成系统服务
1、创建一个systemd服务文件:vi /usr/lib/systemd/system/activemq.service
2、 放入内容
[Unit]
Description=ActiveMQ service
After=network.target
[Service]
Type=forking
ExecStart=/var/activemq/bin/activemq start
ExecStop=/var/activemq/bin/activemq stop
User=root
Group=root
Restart=always
RestartSec=9
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=activemq
[Install]
WantedBy=multi-user.target
3、 找到java命令所在的目录 whereis java
,复制路径填入下一步的JAVA_HOME中。
4、设置activemq配置文件/var/activemq/bin/env中的JAVA_HOME
# Location of the java installation
# Specify the location of your java installation using JAVA_HOME, or specify the
# path to the "java" binary using JAVACMD
# (set JAVACMD to "auto" for automatic detection)
JAVA_HOME="/usr/local/java/jdk1.8.0_181"
JAVACMD="auto"
5、 通过systemctl管理activemq启停
- 启动activemq服务:
systemctl start activemq
- 查看服务状态:
systemctl status activemq
- 创建软件链接:
ln -s /usr/lib/systemd/system/activemq.service /etc/systemd/system/multi-user.target.wants/activemq.service
- 开机自启:
systemctl enable activemq
- 检测是否开启成功(enable):
systemctl list-unit-files |grep activemq
6、 防火墙配置,Web管理端口默认为8161,通讯端口默认为61616
- 添加并重启防火墙
firewall-cmd --zone=public --add-port=8161/tcp --permanent
firewall-cmd --zone=public --add-port=61616/tcp --permanent
systemctl restart firewalld.service
- 或者直接关闭防火墙:
systemctl stop firewalld.service
- 如果你是阿里云服务器还需要开放控制台里的防火墙端口。
使用ActiveMQ的Web管理平台
ActiveMQ自带有管理平台,在游览器访问http://服务IP:8181/admin即可进入。
ActiveMQ的管理页面默认开启了身份校验
账号:admin
密码:admin
Web管理配置
ActiveMQ的Web管理平台是基于jetty运行,因此在/var/activemq/conf
目录可以看到jetty的配置文件。
修改web管理平台的默认端口,在/var/activemq/conf/jetty.xml
中。
在Java中使用ActiveMQ
Maven使用ActiveMQ
添加依赖
<dependencies>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.15.8</version>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
/**
* 简单生产者
*/
public class Producer {
public static void main(String[] args) {
new ProducerThread("tcp://123.57.246.250:61616", "queue1").start();
}
static class ProducerThread extends Thread {
String brokerUrl;
String destinationUrl;
public ProducerThread(String brokerUrl, String destinationUrl) {
this.brokerUrl = brokerUrl;
this.destinationUrl = destinationUrl;
}
@Override
public void run() {
ActiveMQConnectionFactory connectionFactory;
Connection conn;
Session session;
try {
// 1、创建连接工厂
connectionFactory = new ActiveMQConnectionFactory(brokerUrl);
// 2、创建连接对象md
conn = connectionFactory.createConnection();
conn.start();
// 3、创建会话
//第一个参数:是否开启事务。true:开启事务,第二个参数忽略。
//第二个参数:当第一个参数为false时,才有意义。消息的应答模式。1、自动应答2、手动应答。自动应答的意思是客户端收到消息后就删除,收到消息不代表正确使用,如果我们要确保消息正确被消费就要手动的。
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 4、创建点对点发送的目标
Destination destination = session.createQueue(destinationUrl);
// 5、创建生产者消息
MessageProducer producer = session.createProducer(destination);
// 设置生产者的模式,有两种可选 持久化 / 不持久化
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
// 6、创建一条文本消息
String text = "Hello world!";
TextMessage message = session.createTextMessage(text);
for (int i = 0; i < 1; i++) {
// 7、发送消息
producer.send(message);
}
// 8、 关闭连接
session.close();
conn.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
/**
* 简单消费者
*/
// http://activemq.apache.org/consumer-features.html
public class Consumer {
public static void main(String[] args) {
new ConsumerThread("tcp://123.57.246.250:61616", "queue1").start();
new ConsumerThread("tcp://123.57.246.250:61616", "queue1").start();
}
}
class ConsumerThread extends Thread {
String brokerUrl;
String destinationUrl;
public ConsumerThread(String brokerUrl, String destinationUrl) {
this.brokerUrl = brokerUrl;
this.destinationUrl = destinationUrl;
}
@Override
public void run() {
ActiveMQConnectionFactory connectionFactory;
Connection conn;
Session session;
MessageConsumer consumer;
try {
// brokerURL http://activemq.apache.org/connection-configuration-uri.html
// 1、创建连接工厂
connectionFactory = new ActiveMQConnectionFactory(this.brokerUrl);
// 2、创建连接对象
conn = connectionFactory.createConnection();
conn.start(); // 一定要启动
// 3、创建会话(可以创建一个或者多个session)
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 4、创建点对点接收的目标,queue - 点对点
Destination destination = session.createQueue(destinationUrl);
// 5、创建消费者消息 http://activemq.apache.org/destination-options.html
consumer = session.createConsumer(destination);
// 6、接收消息(没有消息就持续等待)
Message message = consumer.receive();
if (message instanceof TextMessage) {
System.out.println("收到文本消息:" + ((TextMessage) message).getText());
} else {
System.out.println(message);
}
consumer.close();
session.close();
conn.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
输出结果: 收到文本消息:Hello world!
springboot使用ActiveMQ
- pom文件导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--直接使用spring-boot-starter-activemq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!-- MQTT -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>
</dependencies>
- 写入配置 application.properties
spring.activemq.broker-url=tcp://123.57.246.250:61616
spring.activemq.user=admin
spring.activemq.password=admin
- Producer代码
@SpringBootApplication
public class Producer {
@Autowired
private JmsTemplate jmsTemplate;
@PostConstruct
public void init() {
jmsTemplate.convertAndSend("queue1", "Hello Spring 4");
}
public static void main(String[] args) {
SpringApplication.run(Producer.class, args);
}
}
- Consumer代码
@SpringBootApplication
@EnableJms
public class Consumer {
@JmsListener(destination = "queue1")
public void receive(String message) {
System.out.println("收到消息:" + message);
}
public static void main(String[] args) {
SpringApplication.run(Consumer.class, args);
}
}
手动配置多个ActiveMQ
- 需要添加一个JmsConfiguration类
@Configuration
@EnableJms
public class JmsConfiguration {
/**
* 连接工厂
* 配置多个ActiveMQ就把该方法复制一个,改下方法名,修改一些参数即可。
* @param brokerUrl
* @param userName
* @param password
* @return
*/
@Bean
public ConnectionFactory connectionFactory1(@Value("${spring.activemq.broker-url}") String brokerUrl, @Value("${spring.activemq.user}") String userName, @Value("${spring.activemq.password}") String password) {
return new ActiveMQConnectionFactory(userName, password, brokerUrl);
}
/**
* 连接工厂
*
* @param brokerUrl
* @param userName
* @param password
* @return
*/
@Bean
public ConnectionFactory connectionFactory2(@Value("${spring.activemq.broker-url}") String brokerUrl, @Value("${spring.activemq.user}") String userName, @Value("${spring.activemq.password}") String password) {
return new ActiveMQConnectionFactory(userName, password, brokerUrl);
}
/**
* 队列模式的监听容器
*
* @param connectionFactory
* @return
*/
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactoryQueue(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
bean.setConnectionFactory(connectionFactory);
return bean;
}
/**
* topic 监听
* @param connectionFactory
* @return
*/
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactoryTopic(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
bean.setConnectionFactory(connectionFactory);
bean.setPubSubDomain(true);
return bean;
}
/**
* 队列模板
*
* @param connectionFactory
* @return
*/
@Bean
public JmsTemplate jmsTemplateQueue(ConnectionFactory connectionFactory) {
return new JmsTemplate(connectionFactory);
}
/**
* 发布订阅模板
*
* @param connectionFactory
* @return
*/
@Bean
public JmsTemplate jmsTemplatePublish(ConnectionFactory connectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
jmsTemplate.setPubSubDomain(true);
return jmsTemplate;
}
}
- Producer代码演示
@SpringBootApplication
public class Producer {
@Autowired
private JmsTemplate jmsTemplatePublish;
@Autowired
private JmsTemplate jmsTemplateQueue;
@PostConstruct
public void send() {
// 队列模式发送
jmsTemplatePublish.convertAndSend("topic1", "Hello Spring topic 1");
// 发布订阅模式发送
jmsTemplateQueue.send("queue1", new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
MapMessage message = session.createMapMessage();
message.setString("msg", "Hello Spring xxxx");
return message;
}
});
}
public static void main(String[] args) {
SpringApplication.run(Producer.class, args);
}
}
- Consumer代码演示
@SpringBootApplication
public class Consumer {
@JmsListener(destination = "queue1", containerFactory = "jmsListenerContainerFactoryQueue")
public void receiveQueue(Message message) throws JMSException {
if (message instanceof TextMessage) {
System.out.println("收到文本消息:" + ((TextMessage) message).getText());
} else if (message instanceof ActiveMQMapMessage) {
System.out.println("收到Map消息:" + ((ActiveMQMapMessage) message).getContentMap());
} else {
System.out.println(message);
}
}
@JmsListener(destination = "topic1", containerFactory = "jmsListenerContainerFactoryTopic")
public void receiveTopic(String message) {
System.out.println("收到订阅消息:" + message);
}
public static void main(String[] args) {
SpringApplication.run(Consumer.class, args);
}
}