为何引入ActiveMQ、ActiveMQ的安装、ActiveMQ发送queue消息和接收Queue消息、ActiveMQ发送topic消息和接收topic消息、ActiveMQ持久化Topic消息

为何引入ActiveMQ

我们在学习Solr索引的时候,每当添加一个商品后,都要把数据库中的数据全部重新导入到索引库,特别消耗性能和时间,这显然是我们所不能忍受的,这就需要优化我们的方案。最好是在商品添加的时候就单独将该商品同步到索引库,这样便简单快捷地实现了数据库与索引库的同步。

摆在我们面前的方案有三个:
方案一:在taotao-manager中,添加商品的业务逻辑中,添加一段同步索引库的业务逻辑。
缺点:很明显,这样会导致业务逻辑耦合度很高,业务拆分不明确,这与我们当初拆分工程,职能单一、明确的原则相违背,故不可采用。

方案二:业务逻辑在taotao-search中实现,调用服务在taotao-manager实现,业务逻辑分开。
缺点:服务与服务之间耦合度变高,服务的启动有先后顺序。服务设计的原则便是各自干各自的活儿,启动要保证互不依赖,服务之间不应该有调用行为,一旦有调用行为,依赖的一方便会因被依赖一方出现故障而无法工作。

方案三:使用消息队列,MQ是一个消息中间件。如下图所示。
怎么理解消息中间件呢?我们可以把它理解为一个秘书,消息的发布者就是大老板,大老板下午三点要开个会,他只需跟秘书说一声,下午三点,我要开个会,就行了,老板不用管秘书是怎样通知各项目经理的,也不用管项目经理要带什么材料,他所做的只是告诉秘书一声而已。秘书负责与各个项目经理联系,告诉各个项目经理应该准备什么。MQ便相当于"秘书"这个角色。当添加一个商品时,商品服务只需要告诉消息中间件MQ,MQ便去通知其它服务做各自该做的事情,比如通知搜索服务去同步索引库,通知redis服务去同步缓存,通知生成静态页面等等。

添加商品发布消息Producer----MQ-----同步索引库Consumer、同步缓存Consumer、生成静态页面Consumer

常见的作为MQ的消息中间件有:ActiveMQ、RabbitMQ、Kafka。我们要学习的是ActiveMQ,其它的都大同小异。
在这里插入图片描述
在这里插入图片描述
那么,什么是ActiveMQ?
ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。
主要特点:

  1. 多种语言和协议编写客户端。语言: Java, C, C++, C#, Ruby, Perl, Python, PHP。应用协议: OpenWire,Stomp REST,WS Notification,XMPP,AMQP
  2. 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)
  3. 对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性
  4. 通过了常见J2EE服务器(如 Geronimo,JBoss 4, GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上
  5. 支持多种传送协议:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA
  6. 支持通过JDBC和journal提供高速的消息持久化
  7. 从设计上保证了高性能的集群,客户端-服务器,点对点
  8. 支持Ajax
  9. 支持与Axis的整合
  10. 可以很容易得调用内嵌JMS provider,进行测试

ActiveMQ的消息形式
对于消息的传递有两种类型:
一种是点对点的,即一个生产者和一个消费者一一对应;
另一种是发布/订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收。
JMS定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。我们用的最多的也就是TextMessage而已。
  · StreamMessage – Java原始值的数据流
  · MapMessage–一套名称-值对
  · TextMessage–一个字符串对象
  · ObjectMessage–一个序列化的 Java对象
  · BytesMessage–一个字节的数据流

我们可以通过下面一张图来加深理解,图上半部分是"发布/订阅者"模式,两个发布者各自发布了一条消息,每条消息都可以被多个Consumer接收到。图下半部分是"面对面"模式,两个发布者各自发布了一条消息,压入队列当中,队列的特点是先进先出,一旦有某个消费者拿走了一条消息,队列中就少了一条消息,剩下的消费者就不可能再消费那条消息了,因此也就做到了一对一。

ActiveMQ的安装

https://archive.apache.org/dist/activemq/

先查看下/usr/local/software目录下是否有我们刚才上传的文件,发现已经有了,然后解压它到/usr/local目录下,如下所示。(注:个人习惯把安装包放到自己建的/usr/local/software目录下,习惯把安装包解压到/usr/local目录下)

解压完后,我们到/usr/local目录下,查看目录列表可以看到有我们刚才解压好的apache-activemq-5.12.0,我们进入到该目录下,查看文件列表,如下图所示。我们可以看到有一个名为activemq-all-5.12.0.jar的jar包,这个jar包,如果不与spring结合,只是简单用来当做activemq客户端的话,可以使用。

如果要将activemq与spring整合的话,不要使用这个jar包,因为这个jar包当中包含了spring的包结构,而且里面的类与spring里面的类名称是一样的,但是方法不全,当我们将spring和activemq结合的时候,如果系统使用的是activemq的jar包当中的spring的类的话就会报错,启动都启动不了,而且错误还隐藏的特别深,难以捉摸其原因。因此整合的话,不要用这个jar包!!!activemq有一个版本5.11.2,里面没有spring的包结构,我们可以使用。----我使用了5-15-9
是在清华大学开源镜像站上下载的

我们看下bin目录下的文件列表,如下图所示,其中activemq文件是用来启动activemq的。

conf目录存放的是一些配置文件,我们不用动,data目录存放的是服务端的缓存数据,webapps提供了管理的后台,

我们不用做任何修改便可以启动activemq,如下所示,我们先到bin目录下,然后使用命令./activemq start来启动。
我们在地址栏输入http://192.168.156.30:8161/admin/,其中8161是activemq默认的访问端口,admin是指定要访问后台系统,回车后会弹出对话框,用户名和密码都是默认的"admin",然后点击"确定"。
在这里插入图片描述

总结:
第一步: 把ActiveMQ 的压缩包上传到Linux系统。
第二步:解压缩。
第三步:启动。
使用bin目录下的activemq命令
启动:
[root@localhost bin]# ./activemq start
关闭:
[root@localhost bin]# ./activemq stop
查看状态:
[root@localhost bin]# ./activemq status

进入管理后台:
http://192.168.173.148:8161/admin
用户名:admin
密码:admin

在这里插入图片描述
我们点击管理界面的"Queues",可以看到如下图所示界面,这是点对点消息发送界面。
在这里插入图片描述
我们再点击"Topics",可以看到如下图所示界面,这是发布/订阅模式界面
在这里插入图片描述

在Send中可以测试发送点对点或发布/订阅两种消
在这里插入图片描述

ActiveMQ发送queue消息和接收Queue消息

错误:
[ERROR] Failed to execute goal on project taotao-manager-service: Could not resolve dependencies for project com.taotao:taotao-manager-service:war:0.0.1-SNAPSHOT: Could not transfer artifact org.apache.activemq:activemq-all:jar:5.15.9 from/to alimaven (http://maven.aliyun.com/nexus/content/repositories/central/): GET request of: org/apache/activemq/activemq-all/5.15.9/activemq-all-5.15.9.jar from alimaven failed: Premature end of Content-Length delimited message body (expected: 18,162,140; received: 719,117) -> [Help 1]

我们在taotao-manager和taotao-search工程都会用到消息服务,因此我们可以选择其中任何一个工程来进行测试,这里我们使用taotao-manager-service工程(taotao-manager的子工程)来测试一下面对面发送消息和接收消息。

首先,我们需要在taotao-manager-service工程添加对activemq的maven依赖,如下图所示。activemq的版本号在taotao-parent工程已经统一定义好了,我们使用的是5.11.2版本的Jar包,之所以选择这个版本的Jar包,是因为这个版本的Jar包还没有spring相关的包结构,与spring结合不会有问题,我们安装的activemq服务是5.12.0版本的,它里面的Jar包是有spring相关的Jar包的,这样会引起Jar包冲突,出现各种各样的问题,因此我们虽然安装的是5.12.0版本的activemq,但是我们使用的Jar包却是5.11.2版本。
在taotao-manager-service的pom.xml中引入activemq组件

下面我们在taotao-manager-service工程新建一个测试包和测试类com.taotao.test.activemq.TestActiveMq.java

我们运行上面的测试方法,执行成功后,我们到activemq的后台管理系统,点击"Queues",可以看到我们刚才发送的那条消息"test-queue"。我们点击"test-queue"
在这里插入图片描述
我们会看到如下图所示界面,可以看到刚才发送的那条消息的ID信息,Persistence(持久化)为永久保存,Priorty(优先级)为4,Redelivered(是否重复投递消息)为false,即不重复投递消息。我们点击ID那一长串字符串。
在这里插入图片描述
正常访问,我们在"Message Details"一栏,可以看到我们发送的消息信息。“hello activemq”
在这里插入图片描述

上节课我们一起学习了使用ActiveMQ来发送面对面消息,这节课我们一起学习下如何接收消息。
我们在测试类中添加一个测试方法testQueueConsumer()

执行上面的测试方法,如下图所示,可以看到正确输出了我们上节课发送的消息。这时程序并没有结束(下图中红色运行标志)
在这里插入图片描述

我们再发送两条不同的消息,看看是不是能马上接收到新的消息,如下图所示,发现只要一发送消息,接收端便立刻会显示出发送的消息。
在这里插入图片描述

如果我们想结束接收消息,可以在Console控制台直接敲回车即可
我们再来看下activemq的管理后台,点击"Queues",可以看到如下图所示界面。说明我们面对面发送消息是没问题的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ActiveMQ发送topic消息和接收topic消息

前两节我们一起学习了发送队列消息及消费队列消息,这节我们一起学习下如何发送topic消息。

我们在测试类中添加一个测试方法,用来测试发送topic消息,如下图所示,其实这个方法与发送队列消息几乎一样,只是创建Destination对象的时候不一样而已。

运行上面的测试方法,运行成功后,我们访问activemq的管理后台页面,点击"Topics",可以看到有"test-topic"这一行,压入消息队列一条消息,但由于没有消费者,因此没有消费掉该消息。
在这里插入图片描述
我们点击上图的"test-topic",会看到如下图所示界面。我们发现刚才我们发送的消息并没有被保存。
在这里插入图片描述
而我们发送的queue消息在未被消费前会被保存

这样的话,就会有个问题,那就是如果发送topic消息时没有消费者,那么这条消息便不存在了,不会再被消费了。因此我们要想消息不会被遗失掉,我们要先打开消费者,然后再发送topic消息。

我们来写消费topic消息的方法,如下图所示,该方法与我们上节课学习的消费队列消息的方法不同的是创建Destination的时候不一样,同时为了模拟多个消费者,在该方法中添加一条输出信息,标明该方法是第几个消费者。

我们运行上面的方法,会看到控制台输出"topic消费者1111。。。。。",为了模仿多个消费者,我们修改输出信息为"22222。。。。。",然后再运行该方法,从而增加一个消费者,然后再修改输出信息为"3333。。。。。",再运行该方法,就会再增加一个消费者,从而现在有三个消费者。

启动了三个消费者后,我们再发送一次topic消息,发完之后,我们看各个控制台的信息。如下图所示。可以看到都打印出了我们发送的topic信息。

我们再看下activemq的管理后台页面,发现消费者现在有3个,压入队列的消息有两条(第一条发送时没有消费者),消费的消息有3条(这是因为有三个消费者 ,对于第二次发送的topic消息,这三个消费者各自消费了一次,因此显示的数量是3)

在这里插入图片描述

在这里插入图片描述

ActiveMQ持久化Topic消息

我们上节课一起学习了产生和消费topic消息,但是有个问题就是topic消息没有持久化,也就意味着,如果消息发送者发送消息的时候,如果消费者没有运行的话,它将无法消费这个消息了(即使它启动也无法再接收到那条topic消息了),这样问题就来了,如果那条消息非常重要呢?我们不能容忍接收不到消息的情况。

下面来实现topic消息的持久化,分以下四步来进行

第一步:写生产者方法
我们新建一个生产topic消息的生产者方法,这个方法与我们上节课生产topic消息的方法略有不同(不同之处我已在下图标出),如下图所示。

第二步:写消费者方法
配好了生产者,我们再来配置下消费者,在创建ConnectionFactory时便与上节课学习的创建方式有所不同(不同之处我已经标出来了)

第三步:配置activemq.xml文件
我们还需要配置下activemq的activemq.xml文件,只需要添加一句配置,就是在<broker的末尾添加一句关于持久化的配置persistent="true"即可。

添加持久化后的代码如下:

第四步:测试
为了测试topic消息的持久化,我们需要先启动消费者,因为只有消费者先在服务端做下登记后,才能保证发送的topic消息被消费者所消费。我们先启动clientId为"consumer1"的消费者,如下图所示。

为了测试多消费者的情况,我们再启动一个消费者,做法很简单,就是修改下消费者的clientId,然后把标志信息"topic消费者1111。。。。。"改为"topic消费者2222。。。。。"即可(如下图红色方框框住的部分就是要修改的地方),然后保存并重新运行testTopicPersistenceConsumer这个方法。

创建了两个消费者后,我们再来创建两个生产者,先执行一遍testTopicPersistenceProducer方法,这样便创建了一个clientId为"producer1"的生产者。之后我们修改下clientId的值,改为"producer2",然后把发送的消息也改一下,以示区分,如下图所示(红色方框框住的内容是修改的内容),修改后保存,然后再运行一下该方法,这样我们便有两个生产者了。

既然消息发送者发送了消息,我们看下当前两个消费者有没有接收到消息,如下图所示,发现两个消费者都接收到两个生产者发来的消息了。
在这里插入图片描述
在这里插入图片描述
我们再来看下activemq的后台管理系统,先看下"Topics",可以看到名称为"test-topic"的消息队列,该队列有两个消费者,刚才一共压入队列两条消息,与我们刚才的操作完全相符。

在这里插入图片描述
我们再点击"Subscribers"进行查看,可以看到有两个消费者,当前两个消费者接收到2条消息,并且已消费2条消息,当前待接收的消息数为0。
在这里插入图片描述

当然,上面只是测试的生产者和消费者都在线的情况,我们现在要测试消费者不在线的时候,生产者发送消息,等消费者启动后还能不能接收到消息。做法也很简单,我们先把两个消费者的进程关掉。然后修改生产者方法中的消息信息,比如我们把"producer1"的消息信息改为"hello,activemq topic333",运行生产者方法,然后再修改clientId为"producer2",消息信息修改为"hello,activemq topic444",再运行生产者方法。
在这里插入图片描述
在这里插入图片描述
这时我们再来看下activemq的后台管理系统界面,还是先看"Topics",消息队列的消费者还是显示的是2个(这时消费者处于关闭状态),这说明一旦消费者在服务端登记后,服务端便一直记着这两个消费者,当前压入消息队列的消息是4条(原来的两条再加上刚添加的两条,共四条)

再看下"Subscribers"一栏,可以看到当前两个消费者处于离线状态,两个消费者都有两个待接收的消息(Pending Queue Size),这说明,虽然消费者当前不在线,但是服务端依然为它们保留着信息,并未丢失。当前进入消息队列共4条消息(Enqueue Counter ) ,消费的消息还是两条(Dequeue Counter),这是因为新发送的两条消息消费者还没有消费掉。

这时我们启动两个消费者(记得做下区分,在上面已经说过了,就不再啰嗦了),启动完后,我们查看下两个消费者的控制台信息,如下图所示。可以看到两个消费者都正常消费了刚才它们不在线时消息生产者发送的消息,没有造成消息丢失。

我们再看下activemq的后台管理系统界面,“Topics"一栏没有变化,我就不贴图了,我们看下"Subscribers”,可以看到,消息队列中待发送的消息数变成0了,这是因为所有消息都已经被消费完了。两个消费者都显示消息入队4条,出队4条,消费完毕。

那么,有的同学会疑问,那重启activemq服务呢?消息还能不丢失吗?那我们做下实验便知道了,我们还是先把两个消费者关掉,修改消息生产者方法的消息内容,重新发送两条消息。然后,我们关掉activemq并重新启动activemq,如下所示。

重启activemq后,我们查看activemq的后台管理系统界面,在"Topics"一栏,我们可以看到消息队列有两个消费者(与重启之前一样),入队的消息数量显示为0(这是表示 重启后压入消息队列的消息,重启后没有发送任何消息,因此该数量为0)

我们再看"Subscribers"一栏,显示两个消费者的消息队列中有两条消息没有消费。

我们现在启动两个消费者,启动完后,我们观察两个消费者的控制台信息,如下图所示,发现正常接收到了activemq服务重启之前的消息!!!

我们最后再看一眼activemq的后台,可以看到消息都被消费完了。至于没有保留重启前消息的数量,这个没有问题,因为消息都已经被消费完了,保不保存曾经被消费的消息数量没有什么意义,只要保证消息未被消费的消息不丢失就可以了!!

Activemq整合spring

Spring与Activemq的整合及用JmsTemplate发送消息

前几节我们一起学习了用Junit测试ActiveMQ的发送接收消息。这节我们一起学习下ActiveMQ如何与Spring进行整合。

首先,要在taotao-manager-service工程的pom.xml文件中添加以下两个依赖(由于我们搭建这个工程的时候就已经添加了对这两个jar的依赖,因此我们不用做这步了)

spring-jms
spring-context-support

接着,我们需要在taotao-manager-service工程下新建一个关于activemq的配置文件applicationContext-activemq.xml

这样我们就把Spring与ActiveMQ结合完毕了,下面我们便一起来测试使用Jmsemplate来发送消息。SpringActivemq.java

运行上面的代码,我们可以看到我们刚才发送的消息在activemq的后台管理系统可以看到。
在这里插入图片描述

Activemq与Spring整合接收消息

我们测试接收消息换个工程来测试,就用taotao-search-service工程,要用这个工程来接收ActiveMQ消息就要先添加对activemq-all的依赖。如下图所示。

下面我们新建一个监听器类,该类继承自MessageListener. MyMessageListener.java

下面我们需要新建一个activemq的配置文件applicationContext-activemq.xml

最后新建一个包和一个测试类TestSpringActiveMQ.java

下面我们便来运行上面的测试方法,在控制台会看到接收到了一条activemq消息,这是上节课我们发送的activemq消息,由于当时没有消费者,所以这条消息一直留到现在。现在我们有了消费者,自然就消费了那条没有被消费的消息。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我们还可以再发送几条activemq消息看看这个控制台是否都能接收的了。

我们再用JmsTemplate来发送一条消息试试,结果如下图所示,可以正常接收到。如果不想让测试类继续接收消息的话,可以在控制台直接敲回车即可。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值