博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
消息队列—ActiveMQ
阅读量:4885 次
发布时间:2019-06-11

本文共 17278 字,大约阅读时间需要 57 分钟。

1.   学习计划

1、什么是MQ

2、MQ的应用场景

3、ActiveMQ的使用方法。

4、使用消息队列实现商品同步。

 

2.   同步索引库分析

方案一:在manager(后台)中,添加商品的业务逻辑中,添加一个同步索引库的业务逻辑。

  缺点:这样违背了服务单一职能的原则,业务逻辑耦合度高,业务拆分不明确。

方案二:业务逻辑在search中实现,调用服务在manager实现。业务逻辑分开。

  缺点:服务之间的耦合度变高,search服务依赖manager服务,服务的启动有先后顺序。

方案三:使用消息队列。MQ是一个消息中间件。

 

MQ是一个消息中间件,ActiveMQ、RabbitMQ、kafka(大数据)。

系统服务之间,非直接通信,而是通过MQ进行转发,这样既解决了系统之间的通信问题,同时也避免了系统之间的依赖和耦合。

消息队列的主要应用:

  解决系统之间的通信问题

  降低系统之间的耦合度

互联网项目中,为了用户的体验,必须遵守快速响应用户的原则,比如在电商项目中,当用户下单之后,其实还有很多的后续业务需要完成,用户根本不可能等你的流程全部处理完才得到下单反馈。这是后我们可以利用消息队列,在既能够快速响应用户的同时,有能后将业务消息压入MQ中,通过MQ的流转,通知后续业务的开展,达到数据最终一致

 

3.   ActiveMQ

3.1. 什么是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,进行测试

 

3.2. ActiveMQ的消息形式

对于消息的传递有两种类型

一种是点对点的,即一个生产者和一个消费者一一对应;(只能有一个消费者)

另一种是发布/订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收。(广播)

JMS定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。

  · StreamMessage -- Java原始值的数据流

  · MapMessage--一套名称-值对

  · TextMessage--一个字符串对象

  · ObjectMessage--一个序列化的 Java对象

  · BytesMessage--一个字节的数据流

4.   ActiveMQ的安装

进入http://activemq.apache.org/下载ActiveMQ

 

 

使用的版本是5.12.0

 

4.1. 安装环境:

1、需要jdk

2、安装Linux系统。生产环境都是Linux系统。

 

4.2. 安装步骤

第一步: 把ActiveMQ 的压缩包上传到Linux系统。

第二步:解压缩。

第三步:启动。

4.3.启动,查看,关闭

使用bin目录下的activemq命令启动:

[root@localhost bin]# ./activemq start

关闭:

[root@localhost bin]# ./activemq stop

查看状态:

[root@localhost bin]# ./activemq status

 4.4 细节

注意:如果ActiveMQ整合spring使用不要使用activemq-all-5.12.0.jar包。建议使用5.11.2

 

进入管理后台:

用户名:admin

密码:admin

  

   

503错误解决:

1、查看机器名

[root@arjenlee168 bin]# cat /etc/sysconfig/network

NETWORKING=yes

HOSTNAME=arjenlee168

 

2、修改host文件

[root@arjenlee168 bin]# cat /etc/hosts

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4 arjenlee168

::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

[root@arjenlee168 bin]#

 

3、重启Activemq服务

5.   ActiveMQ的使用方法

 

 

 下面是java代码依据JMS规范操作MQ。

5.1. Queue

  • Queue消息形式,服务端默认进行持久化。
  • Queue消息形式,只要被任意一个consumer消费后,服务端消除该消息,即一个消息只能被一个consumer消费。

如果消息没有被消费,则会一直被保存在服务端,直到被消费为止。

5.1.1.    Producer

生产者:生产消息,发送端。

把jar包添加到工程中。使用5.11.2版本的jar包。

 

 

5.1.1.1    创建步骤

第一步:创建ConnectionFactory对象,需要指定服务端ip及端口号。

第二步:使用ConnectionFactory对象创建一个Connection对象。

第三步:开启连接,调用Connection对象的start方法。

第四步:使用Connection对象创建一个Session对象。

第五步:使用Session对象创建一个Destination对象(topic、queue),此处创建一个Queue对象。

第六步:使用Session对象创建一个Producer对象。

第七步:创建一个Message对象,创建一个TextMessage对象。

第八步:使用Producer对象发送消息。

第九步:关闭资源。

5.1.1.2  代码示例

@Test    public void testQueueProducer() throws Exception {        // 第一步:创建ConnectionFactory对象,需要指定服务端ip及端口号。        //brokerURL服务器的ip及端口号        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.168:61616");        // 第二步:使用ConnectionFactory对象创建一个Connection对象。        Connection connection = connectionFactory.createConnection();        // 第三步:开启连接,调用Connection对象的start方法。        connection.start();        // 第四步:使用Connection对象创建一个Session对象。        //第一个参数:是否开启事务。true:开启事务,第二个参数忽略。        //第二个参数:当第一个参数为false时,才有意义。消息的应答模式。1、自动应答2、手动应答。一般是自动应答。        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        // 第五步:使用Session对象创建一个Destination对象(topic、queue),此处创建一个Queue对象。        //参数:队列的名称。        Queue queue = session.createQueue("test-queue");        // 第六步:使用Session对象创建一个Producer对象。        MessageProducer producer = session.createProducer(queue);        // 第七步:创建一个Message对象,创建一个TextMessage对象。        /*TextMessage message = new ActiveMQTextMessage();        message.setText("hello activeMq,this is my first test.");*/        TextMessage textMessage = session.createTextMessage("hello activeMq,this is my first test.");        // 第八步:使用Producer对象发送消息。        producer.send(textMessage);        // 第九步:关闭资源。        producer.close();        session.close();        connection.close();    }

 

5.1.2.    Consumer

消费者:接收消息。

5.1.2.1    创建步骤

第一步:创建一个ConnectionFactory对象。

第二步:从ConnectionFactory对象中获得一个Connection对象。

第三步:开启连接。调用Connection对象的start方法。

第四步:使用Connection对象创建一个Session对象。

第五步:使用Session对象创建一个Destination对象。和发送端保持一致queue,并且队列的名称一致。

第六步:使用Session对象创建一个Consumer对象。

第七步:接收消息。

第八步:打印消息。

第九步:关闭资源

5.1.2.2    代码示例

@Test    public void testQueueConsumer() throws Exception {        // 第一步:创建一个ConnectionFactory对象。        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.168:61616");        // 第二步:从ConnectionFactory对象中获得一个Connection对象。        Connection connection = connectionFactory.createConnection();        // 第三步:开启连接。调用Connection对象的start方法。        connection.start();        // 第四步:使用Connection对象创建一个Session对象。        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        // 第五步:使用Session对象创建一个Destination对象。和发送端保持一致queue,并且队列的名称一致。        Queue queue = session.createQueue("test-queue");        // 第六步:使用Session对象创建一个Consumer对象。        MessageConsumer consumer = session.createConsumer(queue);        // 第七步:接收消息。        consumer.setMessageListener(new MessageListener() {                        @Override            public void onMessage(Message message) {                try {                    TextMessage textMessage = (TextMessage) message;                    String text = null;                    //取消息的内容                    text = textMessage.getText();                    // 第八步:打印消息。                    System.out.println(text);                } catch (JMSException e) {                    e.printStackTrace();                }            }        });        //等待键盘输入        System.in.read();        // 第九步:关闭资源        consumer.close();        session.close();        connection.close();    }

 

5.2. Topic

  • Topic消息形式,服务端默认不进行持久化存储。
  • Topic消息可以被多个consumer接收到,不会因为某一个consumer的消费行为,而是的消息被服务端删除。

5.2.1.    Producer

5.2.1.1.    创建步骤

第一步:创建ConnectionFactory对象,需要指定服务端ip及端口号。

第二步:使用ConnectionFactory对象创建一个Connection对象。

第三步:开启连接,调用Connection对象的start方法。

第四步:使用Connection对象创建一个Session对象。

第五步:使用Session对象创建一个Destination对象(topic、queue),此处创建一个Topic对象。

第六步:使用Session对象创建一个Producer对象。

第七步:创建一个Message对象,创建一个TextMessage对象。

第八步:使用Producer对象发送消息。

第九步:关闭资源。

5.2.1.2.  示例代码  

@Test    public void testTopicProducer() throws Exception {        // 第一步:创建ConnectionFactory对象,需要指定服务端ip及端口号。        // brokerURL服务器的ip及端口号        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.168:61616");        // 第二步:使用ConnectionFactory对象创建一个Connection对象。        Connection connection = connectionFactory.createConnection();        // 第三步:开启连接,调用Connection对象的start方法。        connection.start();        // 第四步:使用Connection对象创建一个Session对象。        // 第一个参数:是否开启事务。true:开启事务,第二个参数忽略。        // 第二个参数:当第一个参数为false时,才有意义。消息的应答模式。1、自动应答2、手动应答。一般是自动应答。        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        // 第五步:使用Session对象创建一个Destination对象(topic、queue),此处创建一个topic对象。        // 参数:话题的名称。        Topic topic = session.createTopic("test-topic");        // 第六步:使用Session对象创建一个Producer对象。        MessageProducer producer = session.createProducer(topic);        // 第七步:创建一个Message对象,创建一个TextMessage对象。        /*         * TextMessage message = new ActiveMQTextMessage(); message.setText(         * "hello activeMq,this is my first test.");         */        TextMessage textMessage = session.createTextMessage("hello activeMq,this is my topic test");        // 第八步:使用Producer对象发送消息。        producer.send(textMessage);        // 第九步:关闭资源。        producer.close();        session.close();        connection.close();    }

 

 

5.2.2.    Consumer

消费者:接收消息。

5.2.2.1.    创建步骤

第一步:创建一个ConnectionFactory对象。

第二步:从ConnectionFactory对象中获得一个Connection对象。

第三步:开启连接。调用Connection对象的start方法。

第四步:使用Connection对象创建一个Session对象。

第五步:使用Session对象创建一个Destination对象。和发送端保持一致topic,并且话题的名称一致。

第六步:使用Session对象创建一个Consumer对象。

第七步:接收消息。需要利用MessageListener。

第八步:打印消息。

第九步:关闭资源

5.2.2.2.    示例代码

@Test    public void testTopicConsumer() throws Exception {        // 第一步:创建一个ConnectionFactory对象。        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.168:61616");        // 第二步:从ConnectionFactory对象中获得一个Connection对象。        Connection connection = connectionFactory.createConnection();        // 第三步:开启连接。调用Connection对象的start方法。        connection.start();        // 第四步:使用Connection对象创建一个Session对象。        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        // 第五步:使用Session对象创建一个Destination对象。和发送端保持一致topic,并且话题的名称一致。        Topic topic = session.createTopic("test-topic");        // 第六步:使用Session对象创建一个Consumer对象。        MessageConsumer consumer = session.createConsumer(topic);        // 第七步:接收消息。        consumer.setMessageListener(new MessageListener() {            @Override            public void onMessage(Message message) {                try {                    TextMessage textMessage = (TextMessage) message;                    String text = null;                    // 取消息的内容                    text = textMessage.getText();                    // 第八步:打印消息。                    System.out.println(text);                } catch (JMSException e) {                    e.printStackTrace();                }            }        });        System.out.println("topic的消费端03。。。。。");        // 等待键盘输入        System.in.read();        // 第九步:关闭资源        consumer.close();        session.close();        connection.close();    }

 

6.   Activemq整合spring

使用spring提整合ActiveMQ,可以避免如上繁琐的使用步骤。

6.1. 配置producer

首先是spring和ActiveMQ整合中,如何配置producer

6.1.1.   导入整合包

第一步:引用spring和ActiveMQ整合的相关jar包。

org.springframework
spring-jms
org.springframework
spring-context-support

 

6.1.2.   配置ConnectionFactory

第二步:配置Activemq整合spring。配置ConnectionFactory

spring对ConnectionFactory进行了更上一层的包装(接口),真正的connectionFactory由JMS服务厂商提供,在这里是ActiveMQConnectionFactory,需要注入到spring中的connectionFactory。

6.1.2.   配置生产者

第三步:配置生产者:spring中提供了一个模板,JMSTemplate用来简化如上展示的发送消息的步骤。

使用JMSTemplate对象。发送消息,template中需要注入connectionFactory。

 

6.1.3.   配置Destination

第四步:在spring容器中配置Destination。可以是Queue,也可以是Topic

spring-queue

 

6.1.4.   完整的配置文件

spring-queue

 

下面看一下spring和ActiveMQ整合中,如何配置cousumer

6.2. 配置consumer

  • 导入jar包
  • 配置connectionFactory
  • 配置destination

以上同producer

 

6.2.1.   创建MessageListener

消息的接受需要用到,MessageListener,listener一旦监听到有消息传来,便会执行。

public class MyMessageListener implements MessageListener {    @Override    public void onMessage(Message message) {                try {            TextMessage textMessage = (TextMessage) message;            //取消息内容            String text = textMessage.getText();            System.out.println(text);        } catch (JMSException e) {            e.printStackTrace();        }    }}

 

6.2.2   配置消费者

 

与是手动创建consumer接受消息的代码相比,在spring中,我们只需要配置消息监听器消息监听器容器,然后启动spring容器就可以了。

 

6.2.3.   完整的配置文件

spring-queue

 

 

6.3. 代码测试

6.3.1.    发送消息

第一步:初始化一个spring容器

第二步:从容器中获得JMSTemplate对象。

第三步:从容器中获得一个Destination对象

第四步:使用JMSTemplate对象发送消息,需要知道Destination

@Test     public void testQueueProducer() throws Exception {         // 第一步:初始化一个spring容器         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-activemq.xml");         // 第二步:从容器中获得JMSTemplate对象。         JmsTemplate jmsTemplate = applicationContext.getBean(JmsTemplate.class);         // 第三步:从容器中获得一个Destination对象         Queue queue = (Queue) applicationContext.getBean("queueDestination");         // 第四步:使用JMSTemplate对象发送消息,需要知道Destination         jmsTemplate.send(queue, new MessageCreator() {                           @Override              public Message createMessage(Session session) throws JMSException {                   TextMessage textMessage = session.createTextMessage("spring activemq test");                   return textMessage;              }         });     }

6.3.2.    接收消息

Taotao-search-Service中接收消息。

第一步:把Activemq相关的jar包添加到工程中

第二步:创建一个MessageListener的实现类

第三步:配置spring和Activemq整合。

第四步:测试代码。

@Test     public void testQueueConsumer() throws Exception {         //初始化spring容器         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-activemq.xml");         //等待         System.in.read();     }

 

 

7.   添加商品同步索引库

7.1. Producer

manager-service工程中发送消息。

当商品添加完成后发送一个TextMessage,包含一个商品id。search-service从消息队列MQ中接受到推送过来的id值,根据id值去查询数据库,拿到对应的数据;利用查询得到的数据建立索引,添加到索引库中。

 

 

@Override    public TaotaoResult addItem(TbItem item, String desc) {        // 1、生成商品id        final long itemId = IDUtils.genItemId();        // 2、补全TbItem对象的属性        item.setId(itemId);        //商品状态,1-正常,2-下架,3-删除        item.setStatus((byte) 1);        Date date = new Date();        item.setCreated(date);        item.setUpdated(date);        // 3、向商品表插入数据        itemMapper.insert(item);        // 4、创建一个TbItemDesc对象        TbItemDesc itemDesc = new TbItemDesc();        // 5、补全TbItemDesc的属性        itemDesc.setItemId(itemId);        itemDesc.setItemDesc(desc);        itemDesc.setCreated(date);        itemDesc.setUpdated(date);        // 6、向商品描述表插入数据        itemDescMapper.insert(itemDesc);        //发送一个商品添加消息        jmsTemplate.send(topicDestination, new MessageCreator() {                        @Override            public Message createMessage(Session session) throws JMSException {                TextMessage textMessage = session.createTextMessage(itemId + "");                return textMessage;            }        });        // 7、TaotaoResult.ok()        return TaotaoResult.ok();    }

 

7.2. Consumer

7.2.1.    功能分析

1、接收消息。需要创建MessageListener接口的实现类。

2、取消息,取商品id。

3、根据商品id查询数据库。

4、创建一SolrInputDocument对象。

5、使用SolrServer对象写入索引库。

6、返回成功,返回TaotaoResult。

 

7.2.2.    Dao层

根据商品id查询商品信息。

 

 

映射文件:

7.2.3.    Service层

参数:商品ID

业务逻辑:

1、根据商品id查询商品信息。

2、创建一SolrInputDocument对象。

3、使用SolrServer对象写入索引库。

4、返回成功,返回TaotaoResult。

返回值:TaotaoResult

public TaotaoResult addDocument(long itemId) throws Exception {        // 1、根据商品id查询商品信息。        SearchItem searchItem = searchItemMapper.getItemById(itemId);        // 2、创建一SolrInputDocument对象。        SolrInputDocument document = new SolrInputDocument();        // 3、使用SolrServer对象写入索引库。        document.addField("id", searchItem.getId());        document.addField("item_title", searchItem.getTitle());        document.addField("item_sell_point", searchItem.getSell_point());        document.addField("item_price", searchItem.getPrice());        document.addField("item_image", searchItem.getImage());        document.addField("item_category_name", searchItem.getCategory_name());        document.addField("item_desc", searchItem.getItem_desc());        // 5、向索引库中添加文档。        solrServer.add(document);        solrServer.commit();        // 4、返回成功,返回TaotaoResult。        return TaotaoResult.ok();    }

7.2.4.    Listener

public class ItemChangeListener implements MessageListener {        @Autowired    private SearchItemServiceImpl searchItemServiceImpl;    @Override    public void onMessage(Message message) {        try {            TextMessage textMessage = null;            Long itemId = null;             //取商品id            if (message instanceof TextMessage) {                textMessage = (TextMessage) message;                itemId = Long.parseLong(textMessage.getText());            }            //向索引库添加文档            searchItemServiceImpl.addDocument(itemId);                    } catch (Exception e) {            e.printStackTrace();        }    }}

7.2.5.    Spring配置监听

 

 

转载于:https://www.cnblogs.com/arjenlee/p/9224615.html

你可能感兴趣的文章
14:Challenge 7(map大法好)
查看>>
1010. 邮寄包裹
查看>>
HDU 1394 (逆序数) Minimum Inversion Number
查看>>
UVa 12299 线段树 单点更新 RMQ with Shifts
查看>>
DSFORM
查看>>
IntelliJ+Maven+Spring+Tomcat项目搭建(MAC)
查看>>
关于time的使用
查看>>
String类
查看>>
laravel 框架memcache的配置
查看>>
【BZOJ1483】[HNOI2009]梦幻布丁 链表+启发式合并
查看>>
Python基础 ( 五 ) —— 文件处理
查看>>
leetcode-1 two sum(两数之和)
查看>>
poj1062(spfa)
查看>>
Python基础8(文件读写方法)
查看>>
Python基础36(网络编程UDP)
查看>>
把旧android手机变成跑python的服务器
查看>>
cocos2d-x -3.81+win7+vs2013开发环境创建新的项目
查看>>
第四周学习总结
查看>>
2018-05-07 html入门
查看>>
【Asp.net入门4-01】基本开发工具
查看>>