一、JMS(Java Message Service)
它是一种与厂商无关的API,用来访问消息收发系统消息。它类似于JDBC,JDBC是可以用来访问不同关系数据库的API,而JMS则提供同样与厂商无关的访问消息收发服务的方法,这样就可以通过消息收发服务实现从一个JMS客户机向另一个JMS客户机发送消息,所需要的是厂商支持JMS。换句话说,JMS是Java平台上有关面向消息中间件的技术规范。
二、简单了解JMS
1. JMS包括以下基本构件:
1)连接工厂,是客户用来创建连接的对象,ActiveMQ提供的是ActiveMQConnectionFactory;
2)连接connection;
3)会话session,是发送和接收消息的上下文,用于创建消息生产者,消息消费者,相比rocketMQ会话session是提供事务性的;
4)目的地destination,指定生产消息的目的地和消费消息的来源对象;
生产者、消费者,由会话创建的对象,顾名思义。
2. 消息通信机制:
(1)点对点模式(p2p),每个消息只有1个消费者,它的目的地称为queue队列;
(2) 发布/订阅模式,每个消息可以有多个消费者,而且订阅一个主题的消费者,只能消费自它订阅之后发布的消息。
(3)消息确认机制
Session.AUTO_ACKNOWLEDGE,直接使用receive方法。
Session.CLIENT_ACKNOWLEDGE,通过消息的acknowledge 方法确认消息。
Session.DUPS_ACKNOWLEDGE,该选择只是会话迟钝第确认消息的提交。如果JMS provider 失败,那么可能会导致一些重复的消息。如果是重复的消息,那么JMS provider 必须把消息头的JMSRedelivered 字段设置为true。
三、ActiveMQ的引言
ActiveMQ是由Apache出品的,一款最流行的,能力强劲的消息中间件(MOM:Message Orient middleware)。并且是对消息通信规范JMS的一种具体实现
四、ActiveMQ的特点
1. 将数据从一个应用程序传送到另一个应用程序,或者从软件的一个模块传送到另外一个模块;
2. 负责建立网络通信的通道,进行数据的可靠传送。
3. 保证数据不重发,不丢失
4. 能够实现跨平台操作,能够为不同操作系统上的软件集成技工数据传送服务
五、ActiveMQ的使用场景
1.应用解耦
2.异步消息
3.流量削锋
4.消息通讯
更详细的使用场景参考这篇博客 消息中间件(二)MQ使用场景
六、ActiveMQ在linux中的安装
1. 安装JDK
1.导入JDK压缩包
2.解压 tar -zxvf ....
3.vi /etc/profile
4.添加
export JAVA_HOME=JDK安装的路径
export PATH=$PATH:$JAVA_HOME/bin
5.source /etc/profile
6.java -version
2. 安装ActiveMQ
1.导入ActiveMQ的压缩包
2.解压
3.启动
./activeMq start
4.开启日志
tail -f activeMq.log 开启实时的日志
5.通过客户端工具连接
ip:8161/admin
用户名:admin
密码:admin
用户名,密码在哪看
vi /conf/users.properties
admin=admin
3. 浏览器访问 192.168.174.888:8161
七、ActiveMQ与java集成
1.引入依赖
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.7.0</version>
</dependency>
2. P2P(queue、点对点 )测试代码 (一个生产者,两个消费者)
public class TestP2PProduct {
@Test
//生产者
public void testProduct() throws JMSException {
//1、创建连接工厂
String brokerURL = "tcp://192.168.174.139:61616";
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerURL);
//2、创建连接
Connection connection = connectionFactory.createConnection();
//3、创建回话 是否开启事务 开启自动回执
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
//4、创建生产者
Destination destination = new ActiveMQQueue("QUEUE-1");
MessageProducer producer = session.createProducer(destination);
//5、创建消息
for (int i=1;i<=100;i++){
TextMessage textMessage = session.createTextMessage("生产的Message"+i);
//6、生产者发布消息
producer.send(textMessage);
}
//7、提交
session.commit();
//8、释放资源
connection.close();
producer.close();
session.close();
}
//消费者1
@Test
public void testConsumer() throws JMSException {
String brokerURL = "tcp://192.168.174.139:61616";
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerURL);
Connection connection = connectionFactory.createConnection();
//注意:
connection.start();
Session session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);
Destination destination = new ActiveMQQueue("QUEUE-1");
MessageConsumer consumer = session.createConsumer(destination);
//消费
for (int i=1;i<=100;i++){
TextMessage textMessage = (TextMessage) consumer.receive();
System.out.println("消费者1"+textMessage.getText());
}
session.commit();
connection.close();
consumer.close();
session.close();
}
//消费者2
@Test
public void testConsumer2() throws JMSException {
String brokerURL = "tcp://192.168.174.139:61616";
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerURL);
Connection connection = connectionFactory.createConnection();
//注意:
connection.start();
Session session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);
Destination destination = new ActiveMQQueue("QUEUE-1");
MessageConsumer consumer = session.createConsumer(destination);
//消费
for (int i=1;i<=100;i++){
TextMessage textMessage = (TextMessage) consumer.receive();
System.out.println("消费者2"+textMessage.getText());
}
session.commit();
connection.close();
consumer.close();
session.close();
}
}
先启动两个消费者,消费者会一直处于等待状态,再启动生产者,结果如下:
队列(p2p)模式的消息,是只会被一个消费者所使用的,而不会被共享,这也就是和发布/订阅模式的差别
3. 发布/订阅模式 测试代码(一个发布者,两个订阅者)
//发布订阅
public class TestTopicProduct {
public static void main(String[] args) throws JMSException {
//创建发布的连接工厂
String brokerURL = "tcp://192.168.174.139:61616";
TopicConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerURL);
//创建连接
TopicConnection topicConnection = connectionFactory.createTopicConnection();
//创建回话
TopicSession topicSession = topicConnection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE);
//创建发布
ActiveMQTopic topic = new ActiveMQTopic("TOPIC-1");
TopicPublisher publisher = topicSession.createPublisher(topic);
//创建主题
for (int i=1;i<=100;i++){
TextMessage textMessage = topicSession.createTextMessage("Hello-TestTopic "+i);
//发布
publisher.send(textMessage);
}
//提交
topicSession.commit();
//释放
topicConnection.close();
topicSession.close();
publisher.close();
}
}
public class TestTopicConsumer {
//订阅者1
@Test
public void testConsumer1() throws JMSException {
String brokerURL = "tcp://192.168.174.139:61616";
TopicConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerURL);
//2.创建连接
TopicConnection topicConnection = connectionFactory.createTopicConnection();
topicConnection.start();
//3.创建回话
TopicSession topicSession = topicConnection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE);
Topic topic = new ActiveMQTopic("TOPIC-1");
MessageConsumer consumer = topicSession.createConsumer(topic);
while (true) {
Message receive = consumer.receive();
TextMessage textMessage = (TextMessage) receive;
if (textMessage != null) {
System.out.println("1 号"+textMessage.getText());
}else{
break;
}
}
}
//订阅者2
@Test
public void testConsumer2() throws JMSException {
String brokerURL = "tcp://192.168.174.139:61616";
TopicConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerURL);
//2.创建连接
TopicConnection topicConnection = connectionFactory.createTopicConnection();
topicConnection.start();
//3.创建回话
TopicSession topicSession = topicConnection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE);
Topic topic = new ActiveMQTopic("TOPIC-1");
MessageConsumer consumer = topicSession.createConsumer(topic);
while (true) {
Message receive = consumer.receive();
TextMessage textMessage = (TextMessage) receive;
if (textMessage != null) {
System.out.println("2 号"+textMessage.getText());
}else{
break;
}
}
}
}
先启动两个消费者,再启动生产者,结果如下:
从结果可以看出,这种模式消费者都各自消费了所有生产者的消息,这就是共享性消息的发布/订阅模式,这就是和队列(p2p)模型的区别。
注意:发布/订阅模式中,如果消费者是在生产者产生消息之启动的,那么是不会对之前的消息进行消费的,这一点和队列模式是有区别的
ActiveMQ 与 Springboot 的集成