### 消息中间件 ###

----------

**消息中间件**

1. 消息中间件的概述
2. 消息中间件的应用场景
  * 异步处理
  * 应用解耦
  * 流量削峰
  * 消息通信
 
----------

### JMS消息服务 ###

----------

**JMS的概述**

1. JMS消息服务的概述
2. JMS消息模型
  * P2P模式
  * Pub/Sub模式
 
3. 消息消费的方式
  * 同步的方式---手动
  * 异步的方式---listener监听
 
4. JMS编程模型
----------

### 消息中间件:ActiveMQ ###

----------

**ActiveMQ的下载与安装**

1. ActiveMQ的下载与安装
  * 下载ActiveMQ的压缩文件,解压apache-activemq-5.14.5-bin.zip文件
  * 双击运行:activemq.bat文件,启动服务
 
2. 测试ActiveMQ是否安装成功
  * 打开浏览器,输入:http://localhost:8161
 
3. 点击Manage ActiveMQ broker连接,可以查看ActiveMQ中已经发布的消息等
  * 用户名密码都是:admin
----------

**ActiveMQ的消息队列方式入门**(P2P模式)

1. 在父工程的pom.xml文件中引入ActiveMQ和Spring整合JMS的坐标依赖
<!-- activemq start -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.2.0</version>
</dependency>
<!-- activemq end -->
<!-- spring 与 mq整合 start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>3.7</version>
</dependency>
<!-- spring 与 mq整合 end -->
 
2. ActiveMQ的向消息队列中发送消息的入门程序(没有使用Spring整合JMS的方式)
@Test
public void sendQueueMessage() throws JMSException {
// 1 创建连接工厂
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(); // 2 使用工厂,创建连接
Connection connection = factory.createConnection(); // 3 启动连接
connection.start(); // 4 使用连接,创建会话,true表示开始事务,代码执行后需要提供事务
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); // 5 创建队列队形(myQueue--队列的名字)/topic-----------session创建
Queue queue = session.createQueue("myQueue");
// 6 创建生产者-----------session创建
MessageProducer producer = session.createProducer(queue);
// 7 创建消息----文本消息-------session创建
TextMessage message = session.createTextMessage();
message.setText("helloworld!!!"); // 8 发送消息
producer.send(message); // 9 提交事务
session.commit();
session.close();
connection.close();
}
3. ActiveMQ从消息队列中获取消息
@Test
public void receiverQueueMessage() throws JMSException {
// 1 创建连接工厂
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
// 2 使用工厂,创建连接
Connection connection = factory.createConnection();
// 3 启动连接
connection.start();
// 4 使用连接,创建会话,true表示开始事务,代码执行后需要提供事务
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
// 5 创建队列队形(hello--队列的名字)/topic-----------session创建
Queue queue = session.createQueue("myQueue");
// 6 创建消费者-----------session创建
MessageConsumer consumer = session.createConsumer(queue); // 7 接收消息----text格式
TextMessage receive = (TextMessage) consumer.receive();
String text = receive.getText();
System.out.println("接收到的消息====" + text); // 8 提交事务
session.commit();
session.close();
connection.close(); }
4. 使用监听器的方式,从队列中消费消息
/**
*异步方式
Queue接受用Listener方式接受,多用
如果有多个监听listener,则交替执行
* @throws Exception
*/
@Test
public void receiverQueueListener() throws Exception{
// 1 创建连接工厂
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
// 2 使用工厂,创建连接
Connection connection = factory.createConnection();
// 3 启动连接
connection.start();
// 4 使用连接,创建会话,true表示开始事务,代码执行后需要提供事务//死循环的不能用事物
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 5 创建队列队形(hello--队列的名字)/topic-----------session创建
Queue queue = session.createQueue("myQueue");
// 6 创建消费者-----------session创建
MessageConsumer consumer = session.createConsumer(queue); //7 // 给消费者添加监听器
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message msg) {
TextMessage message = (TextMessage) msg;
try {
System.out.println("Listener1111111111接收到的消息是=="+message.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}); while(true){}
// 使用监听器的方式不能关闭,需要监听器一直工作
// session.commit();
// session.close();
// connection.close();
}

**ActiveMQ的消息订阅方式入门**(Pub/Sub模式)

/**
* Topic发送
* @throws JMSException
*/
@Test
public void sendTopicMessage() throws JMSException {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); // 创建消息订阅
Topic topic = session.createTopic("myTopic");
// 创建生产者
MessageProducer producer = session.createProducer(topic);
// 创建消息,一组可以存储key value的消息
MapMessage message = session.createMapMessage();
message.setString("username", "cgx");
message.setString("password", "123456");
// 发送消息
producer.send(message);
// 提交事务
session.commit();
session.close();
connection.close();
}
/**
* Topic接受
*
* @throws JMSException
*/
@Test
public void testReceiverMessage() throws JMSException {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); // 创建消息订阅
Topic topic = session.createTopic("myTopic");
// 创建消费者
MessageConsumer consumer = session.createConsumer(topic);
// 接收消息
MapMessage message = (MapMessage) consumer.receive();
System.out.println(message.getString("username"));
System.out.println(message.getString("password")); session.commit();
session.close();
connection.close();
}
/**
* Topic接受Listener监听方式
*
* @throws Exception
*/
@Test
public void receiverQueueListener() throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 创建消息订阅
Topic topic = session.createTopic("myTopic");
// 创建消费者
MessageConsumer consumer = session.createConsumer(topic); // 给消费者添加监听器consumer添加监听
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message msg) {
MapMessage message = (MapMessage) msg;
try {
System.out.println(message.getString("username"));
System.out.println(message.getString("password"));
} catch (JMSException e) {
e.printStackTrace();
}
}
}); while (true) { } }

### Spring整合ActiveMQ ###★★★★★

----------
 
**Spring整合ActiveMQ**★★★★★
 
1. 创建applicationContext-mq.xml的配置文件,导入约束★★★★★
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd"> </beans>
2. 具体的配置如下★★★★★
applicationContext-mq.xml===================mq的消息发送(消息生产者)
<!-- 配置连接工厂 -->
<!-- ActiveMQ 连接工厂 -->
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
<!-- 如果连接网络:tcp://ip:61616;未连接网络:tcp://localhost:61616 以及用户名,密码-->
<amq:connectionFactory id="amqConnectionFactory"
brokerURL="tcp://localhost:61616" userName="admin" password="admin" /> <!-- Spring Caching连接工厂 -->
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
<property name="targetConnectionFactory" ref="amqConnectionFactory"></property>
<!-- Session缓存数量和链接数有关 -->
<property name="sessionCacheSize" value="100" />
</bean> <!-- 定义JmsTemplate的Queue类型★★★★★ -->
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
<constructor-arg ref="connectionFactory" />
<!-- 非pub/sub模型(发布/订阅),即队列模式 -->
<property name="pubSubDomain" value="false" />
</bean> <!-- 定义JmsTemplate的Topic类型★★★★★ -->
<bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate" >
<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
<constructor-arg ref="connectionFactory" />
<!-- pub/sub模型(发布/订阅) -->
<property name="pubSubDomain" value="true" />
</bean>
 
3. 发送消息的代码如下★★★★★
  3.1.Queue方式:★★★★★
@Autowired
@Qualifier(value="jmsQueueTemplate")
private JmsTemplate queueTemplate;//Queue /**
* Queue发送消息---spring框架
*/
@Test
public void sendQueueMessage() {
// 发送消息 构造参数指定目标,因为配置文件中的队列和订阅模式是通过id与false和true进行区分
queueTemplate.send("myQueue", new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
// 使用session创建消息,发送
TextMessage textMessage = session.createTextMessage("测试结合spring框架发送queue消息");
return textMessage;
}
});
}
  3.2.Topic方式:★★★★★
@Autowired
@Qualifier(value = "jmsTopicTemplate")
private JmsTemplate topicTemplate;//Topic /**
* Topic发送消息---spring框架
*/
@Test
public void sendTopicMessage() {
topicTemplate.send("spring_topic", new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
MapMessage mapMessage = session.createMapMessage();
mapMessage.setString("username", "mdzz");
return mapMessage;
}
});
}
4. 接收消息的代码如下==========不提倡手动,要用监听器异步获取
/**
* Queue接收消息---spring框架
* 同步手动:不提倡
* receive("myQueue")要写目标,不写目标的话会报找不到目标的错误NO defaultDestination
*/
@Test
public void receiverMessage() {
//接收消息textMessage类型
TextMessage textMessage = (TextMessage) queueTemplate.receive("myQueue"); try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
 
**Spring配置监听器**★★★★★★★★★★★★★★★
 
1. 自定义监听器代码的编写----接收消息---spring框架---实现MessageListener接口★★★★★
  1.1.Queue:★★★★★
@Component(value="queueConsumer1")
public class QueueListener implements MessageListener { @Override
public void onMessage(Message arg0) {
// 把arg0强转
TextMessage textMessage = (TextMessage) arg0;
try {
// 输出消息
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
} }
 
  1.2.Topic:发送一个,两个都会接受★★★★★topic特点:有几个监听几个都会同时收到
@Component
public class TopicConsumer1 implements MessageListener { @Override
public void onMessage(Message arg0) {
MapMessage mapMessage = (MapMessage) arg0;
try {
System.out.println("TopicConsumer1===="+mapMessage.getString("username"));
} catch (JMSException e) {
e.printStackTrace();
}
} } @Component
public class TopicConsumer2 implements MessageListener {
//...
}
 
2. 编写配置文件
applicationContext-mq-consumer.xml=============mq的消息接受(负责监听接受消息)
<!-- 扫描包 -->
<context:component-scan base-package="com.my.jms.consumer" /> <!-- ActiveMQ 连接工厂 -->
<amq:connectionFactory id="amqConnectionFactory"
brokerURL="tcp://localhost:61616" userName="admin" password="admin" /> <!-- Spring Caching连接工厂 -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="amqConnectionFactory"></property>
<property name="sessionCacheSize" value="100" />
</bean> <!-- Spring JmsTemplate 的消息生产者 start-->
<jms:listener-container destination-type="queue" container-type="default" connection-factory="connectionFactory">
<jms:listener destination="myQueue" ref="queueConsumer1"/>
</jms:listener-container> <jms:listener-container destination-type="topic" container-type="default" connection-factory="connectionFactory">
<jms:listener destination="spring_topic" ref="topicConsumer1"/>
<jms:listener destination="spring_topic" ref="topicConsumer2" />
</jms:listener-container>
 
3.不用启动项目,把spring配置文件applicationContext-mq-consumer.xml启动起来,可以用采用下面方法
新建一个test类,让他一直启动着,这样就一直加载spring的配置文件
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-mq-consumer.xml")
public class SpringQueueListenerTest { @Test
public void test(){
while(true);
}
}
4.只要发送端(发送消息---spring框架)一启动,监听器就会监听到,就会输出:测试结合spring框架发送queue消息★★★★★

spring整合总结:

消息发送
  1. 创建spring容器
  2. 从容器中获取JMSTemplate对象,发送消息
  3. 定义Destination
  4. 使用JMSTemplate对象发送消息
消息接受
  1. 创建一个类实现MessageListener 接口。业务处理在此类中实现。
  2.在spring容器中配置DefaultMessageListenerContainer对象,引用MessageListener 实现类对象接收消息。

项目整合ActiveMQ:

1. 消息生产者整合ActiveMQ
  消息生产者只需要发送消息
  需要把JMSTemplate和Destination交给spring进行管理

 部分代码:

/**===========================activeMQ消息发送========================================*/
// 发送消息!!!
this.send("save", item.getId());
} @Autowired
private JmsTemplate jmsTemplate; @Autowired
private Destination destination; /**
* 此方法就是用来发送消息的
* 考虑:1、发送什么数据?2、我需要什么数据?
* 在消息中需要:1、消息的标识:save,delete,update;2、商品的ID
*/
private void send(final String type, final Long itemId) {
// TODO Auto-generated method stub
jmsTemplate.send(destination, new MessageCreator() { @Override
public Message createMessage(Session session) throws JMSException {
//创建消息体
TextMessage textMessage = new ActiveMQTextMessage();
//设置消息内容
Map<String, Object> map = new HashMap<>();
map.put("type", type);
map.put("itemId", itemId);
try {
ObjectMapper mapper = new ObjectMapper();
textMessage.setText(mapper.writeValueAsString(map));
} catch (Exception e) {
e.printStackTrace();
}
return textMessage;
}
});
}

2. 消息消费改造
  在search-service添加
  ItemMessageListener:

/**===========================activeMQ消息发送========================================*/
@Autowired
private SearchService searchService; @Override
public void onMessage(Message message) {
//先判断此消息类型是否是TextMessage
if(message instanceof TextMessage){
//如果是,强转
TextMessage textMessage = (TextMessage)message;
try {
//获取消息:json
String json = textMessage.getText();
//杰克逊第三作用:直接解析json数据
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(json);
String type = jsonNode.get("type").asText();
Long itemId = jsonNode.get("itemId").asLong();
//根据解析出来的type,判断此type=save的时候我应该调用indexSearch方法
if("save".equals(type)){
searchService.indexItem(itemId);
} } catch (Exception e) {
e.printStackTrace();
}
} }

索引库增加商品会触发mq:

SearchServiceImpl:

@Override
public void indexItem(Long itemId) throws Exception {
Item item = this.itemMapper.selectByPrimaryKey(itemId); SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", item.getId());
doc.addField("item_title", item.getTitle());
doc.addField("item_image", item.getImage());
doc.addField("item_cid", item.getCid());
doc.addField("item_price", item.getPrice());
doc.addField("item_status", item.getStatus()); this.cloudSolrServer.add(doc); this.cloudSolrServer.commit(); }
 

消息中间件--ActiveMQ&JMS消息服务的更多相关文章

  1. 三:JMS消息服务规范

    一:JMS是什么?--->JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API--->用于在两个应用程 ...

  2. Java JMS——消息服务

    转载请注明原文地址: https://www.cnblogs.com/ygj0930/p/10921569.html 一:什么是Java消息服务—— 消息通信接口规范 Java消息服务指的:两个应用程 ...

  3. JBoss EAP应用服务器部署方法和JBoss 开发JMS消息服务小例子

    一.download JBoss-EAP-6.2.0GA: http://jbossas.jboss.org/downloads JBoss Enterprise Application Platfo ...

  4. Intellij IDEA 创建消息驱动Bean - 接收JMS消息

    除了同步方式的调用之外,有时还需要异步调用,用来处理不需要即时处理的信息,例如短信.邮件等,这需要使用EJB中的独特组件——消息驱动Bean(Message-Driven Bean,MDB),它提供了 ...

  5. JMS(Java消息服务)与消息队列ActiveMQ基本使用(一)

    最近的项目中用到了mq,之前自己一直在码农一样的照葫芦画瓢.最近几天研究了下,把自己所有看下来的文档和了解总结一下. 一. 认识JMS 1.概述 对于JMS,百度百科,是这样介绍的:JMS即Java消 ...

  6. (十七)SpringBoot之使用异步消息服务jms之ActiveMQ

    一.引入maven依赖 <dependencies> <dependency> <groupId>org.springframework.boot</grou ...

  7. ActiveMQ学习总结(5)——Java消息服务JMS详解

    JMS: Java消息服务(Java Message Service) JMS是用于访问企业消息系统的开发商中立的API.企业消息系统可以协助应用软件通过网络进行消息交互. JMS的编程过程很简单,概 ...

  8. 使用ActiveMQ实现JMS消息通信服务

    PTP(点对点的消息模型) 在点对点模型中,相当于两个人打电话,两个人独享一条通信线路.一方发送消息,一方接收消息. 在p2p的模型中,双方通过队列交流,一个队列只有一个生产者和一个消费者. 1.建立 ...

  9. 【转载】JAVA消息服务JMS规范及原理详解

    转载:https://www.cnblogs.com/molao-doing/articles/6557305.html 作者: moyun- 一.简介 JMS即Java消息服务(Java Messa ...

随机推荐

  1. Python内置函数(34)——filter

    英文文档: filter(function, iterable) Construct an iterator from those elements of iterable for which fun ...

  2. emqtt 试用(九)ssl认证 - 客户端 mqttfx 验证

    一.代码生成证书 1.安装openssl,配置path变量 安装文件:Win64OpenSSL-1_1_0f.exe 安装openssl:C:\OpenSSL-Win64 配置path变量:C:\Op ...

  3. Eclipse在线更新慢

    一.去掉不必要的更新 打开Windows-Preferences -> Install/Update –> Available Software Sites,将不需要的更新停用 二.关闭自 ...

  4. mysql的账户管理

    mysql中账户管理:1 查看所有用户: 所有用户及权限信息都存储在mysql数据库中的user表中 查看user表的结构 desc user\G; 主要字段: host: 表示允许访问的主机 use ...

  5. [BZOJ4011][HNOI2015] 落忆枫音(学习笔记) - 拓扑+DP

    其实就是贴一下防止自己忘了,毕竟看了题解才做出来 Orz PoPoQQQ 原文链接 Description 背景太长了 给定一个DAG,和一对点(x, y), 在DAG中由x到y连一条有向边,求生成树 ...

  6. HTML初识

    HTML初识 web服务本质 import socket def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) so ...

  7. Java基础语法<六> 数组 Arrays

    笔记整理 来源于<Java核心技术卷 I > <Java编程思想>   允许数组长度为0 new element[0] 数组长度为0与null不同   1. 数组拷贝 允许将一 ...

  8. java中String类学习笔记

    1.String的两种实例化方式 String str="hello";//直接赋值的方式: String str=new String("hello");// ...

  9. [LeetCode] The Maze 迷宫

    There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolli ...

  10. python AES加密解密 pycryptodome

    环境 pyhton3.6 博主为了解码 AES 用了1天的时间,安了各种包,然而走了很多坑,在这里给大家提供一个简便的方法 首先在命令行(推荐)  pip install Crypto 你会发现安装下 ...