消息中间件
消息中间件是基于生产者和消费者的,生产者将数据存放到消息中间件服务器的队列中,如果消费者运行正常,可以随即获取数据,如果消费者异常,可以在恢复正常之后继续获取消息,消息中间件是异步通讯的。
消息中间件中的消息模型
点对点
消息存放到队列中,只能让一个消费者消费,不能重复消费,即便是多个消费者,同一个消息只能执行一次。
发布与订阅
消息存放到Topic(主题)中,可以让多个消费者消费
这两个消息模型之间有什么区别?
- 点对点模型中消费者在运行的时候,可以获取在该运行时间之前和该运行时间之后生产者发送的所有未消费的消息
- 发布与订阅中消费者在运行的时候,只可以获取在该运行时间之后,生产者发送的未消费的消息。
消息中间件结构图
消费者消费消息的三个阶段
- 通过receive方法获取消息
- 获取消息中内容
- 确认消息
Web项目整合ActiveMQ
首先启动ActiveMQ,默认8161端口
执行activemq.bat文件
注:执行ActiveMQ后访问http://localhost:8161/admin/
初始密码:admin admin
新建maven项目,引入依赖
<!--ActiveMQ-->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.7.0</version>
</dependency>
点对点模型
Producer生产者
package com.neusoft.mq.producer;
import lombok.extern.slf4j.Slf4j;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
@Slf4j
public class ProducerTest {
private static final String USERNAME = "admin";
private static final String PASSWORD = "admin";
// 用于接收消息、发消息的端口号,不同于工作平台的端口号
private static final String BROKERURL = "tcp://127.0.0.1:61616";
private static final String QUENENAME = "myQuene";
public static void main(String[] args) throws Exception{
start();
}
public static void start() throws Exception{
// 获取ActiveMQ会话工厂
ActiveMQConnectionFactory activeFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKERURL);
// 获取连接
Connection connection = activeFactory.createConnection();
// 启动连接
connection.start();
// jms 关闭事务,设置消息可靠性,自动签收
// session可以携带事务,设置为true,但是需要在producer.send(message)之后加上session.commit
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 创建消息队列
Queue queue = session.createQueue(QUENENAME);
// 创建生产者
MessageProducer producer = session.createProducer(queue);
// 设置存放到消息队列中的内容
for(int i = 0 ; i < 10; i++){
TextMessage textMessage = session.createTextMessage("Hello world, I am wn,"+i);
// 发送消息
producer.send(textMessage);
}
log.info("消息队列存放成功...");
// 关闭连接
session.close();
connection.close();
}
}
Consumer消费者
package com.neusoft.mq.receiver;
import lombok.extern.slf4j.Slf4j;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
@Slf4j
public class ReceiverTest1 {
private static final String USERNAME = "admin";
private static final String PASSWORD = "admin";
private static final String BROKERURL = "tcp://127.0.0.1:61616";
private static final String QUENENAME = "myQuene";
public static void main(String[] args) throws Exception{
start();
}
public static void start() throws Exception{
// 获取ActiveMQ会话工厂
ActiveMQConnectionFactory activeFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKERURL);
// 获取连接
Connection connection = activeFactory.createConnection();
// 启动连接
connection.start();
// jms 关闭事务,设置消息可靠性,自动签收
Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
// 创建消息队列
Queue queue = session.createQueue(QUENENAME);
// 创建消费者
MessageConsumer consumer = session.createConsumer(queue);
while (true){
// 接收消息
TextMessage textMessage = (TextMessage)consumer.receive();
if(textMessage != null){
System.out.println("我是消费者,内容:"+textMessage.getText());
// 手动应答
textMessage.acknowledge();
}
else
break;
}
// 关闭连接
session.close();
connection.close();
}
}
发布与订阅模型
Producer生产者
package com.neusoft.mq.producer;
import lombok.extern.slf4j.Slf4j;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
@Slf4j
public class TopicProducerTest {
private static final String USERNAME = "admin";
private static final String PASSWORD = "admin";
// 用于接收消息、发消息的端口号,不同于工作平台的端口号
private static final String BROKERURL = "tcp://127.0.0.1:61616";
private static final String TOPICNAME = "myTopic";
public static void main(String[] args) throws Exception{
start();
}
public static void start() throws Exception{
// 获取ActiveMQ会话工厂
ActiveMQConnectionFactory activeFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKERURL);
// 获取连接
Connection connection = activeFactory.createConnection();
// 启动连接
connection.start();
// jms 关闭事务,设置消息可靠性,自动签收
// session可以携带事务,设置为true,但是需要在producer.send(message)之后加上session.commit
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 创建消息队列
Topic topic = session.createTopic(TOPICNAME);
// 创建生产者
MessageProducer producer = session.createProducer(topic);
// 设置存放到消息队列中的内容
for(int i = 0 ; i < 5; i++){
TextMessage textMessage = session.createTextMessage("Hello world, I am wn,"+i);
// 发送消息
producer.send(textMessage);
}
log.info("消息队列存放成功...");
// 关闭连接
session.close();
connection.close();
}
}
Consumer消费者
package com.neusoft.mq.receiver;
import lombok.extern.slf4j.Slf4j;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
@Slf4j
public class TopicReceiverTest1 {
private static final String USERNAME = "admin";
private static final String PASSWORD = "admin";
private static final String BROKERURL = "tcp://127.0.0.1:61616";
private static final String TOPICNAME = "myTopic";
public static void main(String[] args) throws Exception{
start();
}
public static void start() throws Exception{
// 获取ActiveMQ会话工厂
ActiveMQConnectionFactory activeFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKERURL);
// 获取连接
Connection connection = activeFactory.createConnection();
// 启动连接
connection.start();
// jms 关闭事务,设置消息可靠性,自动签收
Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
// 创建消息队列
Topic topic = session.createTopic(TOPICNAME);
// 创建消费者
MessageConsumer consumer = session.createConsumer(topic);
while (true){
// 接收消息
TextMessage textMessage = (TextMessage)consumer.receive();
if(textMessage != null){
System.out.println("我是消费者1,内容:"+textMessage.getText());
// 手动应答
textMessage.acknowledge();
}
else
break;
}
// 关闭连接
session.close();
connection.close();
}
}