ActiveMQ源码架构解析第二节

2024-05-07 09:18

本文主要是介绍ActiveMQ源码架构解析第二节,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ActiveMQ源码架构解析第二节

  • 博客分类:
  • ActiveMQ

 

    本节主要内容就是讲解消息的传递方式,上一节已经讲解完客户端和broker端连接的建立方式,在Connection、Session、Producer类对象建立的同时,客户端和broker端会进行一些消息交互,ActiveMQ中把所有的消息交互的内容都叫做Command,每条消息对应一个Command,例如客户端刚连接到broker,broker会发送一个BrokerInfo信息到客户端,接着客户端会发送ConnectionInfo连接信息、ProducerInfo生产者信息等等到服务端,如下图所示:

 



 

 

 

 

这些命令都继承于BaseCommand抽象类并实现于Command接口,类图如下,这里使用了访问者设计模式以及适配器设计模式。



 

适配器模式分为三种实现,第一种是通过继承实现,第二种是通过组合实现,第三种也就是类图中画的叫做默认适配器,CommandVisiter接口中定义了处理所有消息的方法,是broker和客户端api公用的一个接口,但是客户端用不到全部接口,如果实现这个接口那又必须实现全部的方法,所以此处在接口和具体类中间新增了一个CommandVisiterAdapter抽象类实现了全部的处理消息的方法并且全部都是空实现,这样在新建DefaultVisiter的时候就可以根据自己的需要来选择相应的方法进行实现了,访问者设计模式的体现请看下面的代码:

 

/**

 

     * reads packets from a Socket

 

     */

 

    publicvoid run() {

 

        LOG.trace("TCP consumer thread for " + this + " starting");

 

        this.runnerThread=Thread.currentThread();

 

        try {

 

            while (!isStopped()) {

 

                doRun();

 

            }

 

        } catch (IOException e) {

 

            stoppedLatch.get().countDown();

 

            onException(e);

 

        } catch (Throwable e){

 

            stoppedLatch.get().countDown();

 

            IOException ioe=new IOException("Unexpected error occured: " + e);

 

            ioe.initCause(e);

 

            onException(ioe);

 

        }finally {

 

            stoppedLatch.get().countDown();

 

        }

 

    }

 

 

 

    protectedvoid doRun() throws IOException {

 

        try {

 

            Object command = readCommand();

 

            doConsume(command);

 

        } catch (SocketTimeoutException e) {

 

        } catch (InterruptedIOException e) {

 

        }

 

    }

 

 

 

    protected Object readCommand() throws IOException {

 

        return wireFormat.unmarshal(dataIn);

 

}

 

 

 

这段代码是来自TcpTransport.java中,上一节已经讲解完TcpTransport的建立所以此处不在熬述,可以看到线程启动后一直在调用doRun方法,doRun方法则调用readCommand来读取客户端发送过来的信息,读到之后就会调用ActiveMQConnection.javaonCommand方法,如下代码:

 

 

 

@Override

 

    publicvoid onCommand(final Object o) {

 

        final Command command = (Command)o;

 

        if (!closed.get() && command != null) {

 

            try {

 

                command.visit(new CommandVisitorAdapter() {

 

                    @Override

 

                    public Response processMessageDispatch(MessageDispatch md) throws Exception {

 

                        waitForTransportInterruptionProcessingToComplete();

 

                        ActiveMQDispatcher dispatcher = dispatchers.get(md.getConsumerId());

 

                        if (dispatcher != null) {

 

                            // Copy in case a embedded broker is dispatching via

 

                            // vm://

 

                            // md.getMessage() == null to signal end of queue

 

                            // browse.

 

                            Message msg = md.getMessage();

 

                            if (msg != null) {

 

                                msg = msg.copy();

 

                                msg.setReadOnlyBody(true);

 

                                msg.setReadOnlyProperties(true);

 

                                msg.setRedeliveryCounter(md.getRedeliveryCounter());

 

                                msg.setConnection(ActiveMQConnection.this);

 

                                msg.setMemoryUsage(null);

 

                                md.setMessage(msg);

 

                            }

 

                            dispatcher.dispatch(md);

 

                        }

 

                        returnnull;

 

                    }

 

 

 

                    @Override

 

                    public Response processProducerAck(ProducerAck pa) throws Exception {

 

                        if (pa != null && pa.getProducerId() != null) {

 

                            ActiveMQMessageProducer producer = producers.get(pa.getProducerId());

 

                            if (producer != null) {

 

                                producer.onProducerAck(pa);

 

                            }

 

                        }

 

                        returnnull;

 

                    }

 

 

 

                    @Override

 

                    public Response processBrokerInfo(BrokerInfo info) throws Exception {

 

                        brokerInfo = info;

 

                        brokerInfoReceived.countDown();

 

                        optimizeAcknowledge &= !brokerInfo.isFaultTolerantConfiguration();

 

                        getBlobTransferPolicy().setBrokerUploadUrl(info.getBrokerUploadUrl());

 

                        returnnull;

 

                    }

 

 

 

                    @Override

 

                    public Response processConnectionError(final ConnectionError error) throws Exception {

 

                        executor.execute(new Runnable() {

 

                            @Override

 

                            publicvoid run() {

 

                                onAsyncException(error.getException());

 

                            }

 

                        });

 

                        returnnull;

 

                    }

 

 

 

                    @Override

 

                    public Response processControlCommand(ControlCommand command) throws Exception {

 

                        onControlCommand(command);

 

                        returnnull;

 

                    }

 

 

 

                    @Override

 

                    public Response processConnectionControl(ConnectionControl control) throws Exception {

 

                        onConnectionControl((ConnectionControl)command);

 

                        returnnull;

 

                    }

 

 

 

                    @Override

 

                    public Response processConsumerControl(ConsumerControl control) throws Exception {

 

                        onConsumerControl((ConsumerControl)command);

 

                        returnnull;

 

                    }

 

 

 

                    @Override

 

                    public Response processWireFormat(WireFormatInfo info) throws Exception {

 

                        onWireFormatInfo((WireFormatInfo)command);

 

                        returnnull;

 

                    }

 

                });

 

            } catch (Exception e) {

 

                onClientInternalException(e);

 

            }

 

        }

 

 

 

        for (Iterator<TransportListener> iter = transportListeners.iterator(); iter.hasNext();) {

 

            TransportListener listener = iter.next();

 

            listener.onCommand(command);

 

        }

 

}

 

 

 

可以看到Command作为入参传进onCommand方法,然后方法中调用command.visit(new CommandVisitorAdapter() {…}),new CommandVisitorAdapter就是上面介绍过的适配器设计模式,这里可以看到这个匿名类只需实现可以用到的方法,而不是实现所有的接口方法。这里command.visit的好处是传入进来的command程序不需要判断他是什么类型的command然后在决定调用这个command的某个方法,而是直接调用visit方法即可,而所有的业务逻辑也是统一的在CommandVisitorAdaptor中实现,这也算是java中动态多分派的实现。

 

知道了消息接收处理以及broker和客户端的信息交互之后,我们在来看下消息是如何从Command类序列化到字节写入以及字节如何反序列化转成Command类的,在ActiveMQ中,每一个Command消息都对应一个CommandMarshal类,例如ConnectionInfo使用ConnectionInfoMarshal来序列化和反序列化,BrokerInfo使用BrokerInfoMarshal来序列化和反序列化,ConnectionInfoMarshalmarshal的实现就是把字符串或者字节等信息写入到socket的输出流中没有什么可说的,序列化和反序列化又分为两种,一种是tight一种是loosetight会针对cpu来进行优化,先写入大小,在写入具体数据,而loose方式则直接写入数据,两种方式都会使用缓存功能,客户端和服务端都分别存在marshal[]unMarshal[]数组,例如客户端给服务端发送ProducerInfo信息,第一次发送后会把ProducerInfo存放在marshal的第0位,然后服务端接收后会把这个producerInfo放在unMarshal[0]中,如果客户端在次发送ProducerInfo则从缓存中取,找到ProducerInfomarshal[]的第0个,则直接发送0,服务端则从unMarshal[]0个取出使用,这节就到这里吧,想到什么我在补充,欢迎跟帖讨论。

这篇关于ActiveMQ源码架构解析第二节的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/966940

相关文章

使用Python实现批量访问URL并解析XML响应功能

《使用Python实现批量访问URL并解析XML响应功能》在现代Web开发和数据抓取中,批量访问URL并解析响应内容是一个常见的需求,本文将详细介绍如何使用Python实现批量访问URL并解析XML响... 目录引言1. 背景与需求2. 工具方法实现2.1 单URL访问与解析代码实现代码说明2.2 示例调用

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

在C#中合并和解析相对路径方式

《在C#中合并和解析相对路径方式》Path类提供了几个用于操作文件路径的静态方法,其中包括Combine方法和GetFullPath方法,Combine方法将两个路径合并在一起,但不会解析包含相对元素... 目录C#合并和解析相对路径System.IO.Path类幸运的是总结C#合并和解析相对路径对于 C

Java解析JSON的六种方案

《Java解析JSON的六种方案》这篇文章介绍了6种JSON解析方案,包括Jackson、Gson、FastJSON、JsonPath、、手动解析,分别阐述了它们的功能特点、代码示例、高级功能、优缺点... 目录前言1. 使用 Jackson:业界标配功能特点代码示例高级功能优缺点2. 使用 Gson:轻量

Java如何接收并解析HL7协议数据

《Java如何接收并解析HL7协议数据》文章主要介绍了HL7协议及其在医疗行业中的应用,详细描述了如何配置环境、接收和解析数据,以及与前端进行交互的实现方法,文章还分享了使用7Edit工具进行调试的经... 目录一、前言二、正文1、环境配置2、数据接收:HL7Monitor3、数据解析:HL7Busines

python解析HTML并提取span标签中的文本

《python解析HTML并提取span标签中的文本》在网页开发和数据抓取过程中,我们经常需要从HTML页面中提取信息,尤其是span元素中的文本,span标签是一个行内元素,通常用于包装一小段文本或... 目录一、安装相关依赖二、html 页面结构三、使用 BeautifulSoup javascript

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库