RabbitMQ-客户端源码之AMQChannel

本文详细探讨了RabbitMQ客户端AMQChannel中的RPC机制,特别是AMQCommand的transmit方法如何将内容发送给broker并处理响应。通过分析AMQConnection的start()方法和AMQChannel的rpc()方法,揭示了如何等待broker返回并使用ActiveRpc处理帧。重点介绍了BlockingRpcContinuation和BlockingCell,它们作为内部实现的关键组件,实现了基于BlockingQueue的RPC通信。
ublic void quiescingTransmit(Method m) throws IOException {
    synchronized (_channelMutex) {
        quiescingTransmit(new AMQCommand(m));
    }
}
public void quiescingTransmit(AMQCommand c) throws IOException {
    synchronized (_channelMutex) {
        if (c.getMethod().hasContent()) {
            while (_blockContent) {
                try {
                    _channelMutex.wait();
                } catch (InterruptedException e) {}

                // This is to catch a situation when the thread wakes up during
                // shutdown. Currently, no command that has content is allowed
                // to send anything in a closing state.
                ensureIsOpen();
            }
        }
        c.transmit(this);
    }
}

上面代码只需要看: c.transmit(this);这一句,其余的都是摆设。看到这里,就调用了AMQCommand的transmit方法,这个transmit方法就是讲AMQChannel中封装的内容发给broker,然后等待broker返回,进而通过之前附值的_activeRpc来处理回传的帧。

虽然之前在AMQConnection([[二]RabbitMQ-客户端源码之AMQConnection][RabbitMQ-_AMQConnection])中详细讲述了start()方法,但是这里还是要来拿这个来举例这个AMQChannel中的rpc怎么使用
在AMQConnection中有这么一段代码:

Method method = (challenge == null)
                        ? new AMQP.Connection.StartOk.Builder()
                                  .clientProperties(_clientProperties)
                                  .mechanism(sm.getName())
                                  .response(response)
                                  .build()
                        : new AMQP.Connection.SecureOk.Builder().response(response).build();

try {
    Method serverResponse = _channel0.rpc(method, HANDSHAKE_TIMEOUT/2).getMethod();
    if (serverResponse instanceof AMQP.Connection.Tune) {
        connTune = (AMQP.Connection.Tune) serverResponse;
    } else {
        challenge = ((AMQP.Connection.Secure) serverResponse).getChallenge();
        response = sm.handleChallenge(challenge, this.username, this.password);
    }

客户端将Method封装成Connection.StartOk帧之后等待broker返回Connection.Tune帧。
此时调用了AMQChannel的rpc(Method m, int timeout)方法,其间接调用了AMQChannel的privateRpc(Method, int timeout)方法。代码详情上面已经罗列出来。

注意privateRpc(Method, int timeout)方法的最有一句返回:return k.getReply(timeout);这句代码的意思是SimpleBlockingRpcContinuation对象在等待broker的返回,确切的来说是MainLoop线程处理之后返回,即AMQChannel类中handleCompleteInboundCommand方法的nextOutstandingRpc().handleCommand(command)这行代码。


AQMChannel还有些其他的内容,都是边缘性的东西,这里还剩下个RpcContinuation要着重阐述下的:

public interface RpcContinuation {
    void handleCommand(AMQCommand command);
    void handleShutdownSignal(ShutdownSignalException signal);
}

public static abstract class BlockingRpcContinuation implements RpcContinuation {
    public final BlockingValueOrException _blocker =
        new BlockingValueOrException();

    public void handleCommand(AMQCommand command) {
        _blocker.setValue(transformReply(command));
    }

    public void handleShutdownSignal(ShutdownSignalException signal) {
        _blocker.setException(signal);
    }

    public T getReply() throws ShutdownSignalException
    {
        return _blocker.uninterruptibleGetValue();
    }

    public T getReply(int timeout)
        throws ShutdownSignalException, TimeoutException
    {
        return _blocker.uninterruptibleGetValue(timeout);
    }

    public abstract T transformReply(AMQCommand command);
}

public static class SimpleBlockingRpcContinuation
    extends BlockingRpcContinuation
{
    public AMQCommand transformReply(AMQCommand command) {
        return command;
    }
}

RPCContinuation只是一个接口,而BlockingRpcContinuation这个抽象类缺似乎略有门道。而SimpleBlockingRpcContinuation只是将BlockingRpcContinuation中的handleCommand方法便成为:

_blocker.setValue(command);

BlockingRpcContinuation类主要操纵了BlockingValueOrException _blocker这个成员变量。再接下深究BlockingValueOrException其实是继承了BlockingCell,对其做了一下简单的封装。最后来看下BlockingCell是个什么鬼, 截取部分代码如下:

public class BlockingCell {
    private boolean _filled = false;
    private T _value;

    public synchronized T get() throws InterruptedException {
        while (!_filled) {
            wait();
        }
        return _value;
    }

其实这个就是capacity为1的BlockingQueue,顾美其名曰BlockingCell,绕了大半圈,原来AMQChannel中的_activeRpc就是个这么玩意儿~

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值