RabbitMQ客户端源码分析(七)之Channel与ChannelManager

RabbitMQ-java-client版本

  1. com.rabbitmq:amqp-client:4.3.0
  2. RabbitMQ版本声明: 3.6.15

Channel

  1. uml图

  2. transmit(AMQCommand c):传输方法,委托AMQCommand进行传输

        public void transmit(AMQCommand c) throws IOException {
            synchronized (_channelMutex) {
                ensureIsOpen();
                quiescingTransmit(c);
            }
        }
        public void quiescingTransmit(AMQCommand c) throws IOException {
            synchronized (_channelMutex) {
                if (c.getMethod().hasContent()) {
                    while (_blockContent) {
                        try {
                            _channelMutex.wait();
                        } catch (InterruptedException ignored) {}
    
                        // 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();
                    }
                }
                //调用AMQCommand的传输方法
                c.transmit(this);
            }
        }
    
    
    

ChannelManager

  1. ChannelManager:负责Channel的管理,创建Channel、添加新的Channel、获取Channel、Channel关闭等

  2. 构造方法

        public ChannelManager(ConsumerWorkService workService, int channelMax, ThreadFactory threadFactory, MetricsCollector metricsCollector) {
            if (channelMax == 0) {
                // The framing encoding only allows for unsigned 16-bit integers
                // for the channel number
                channelMax = (1 << 16) - 1;
            }
            _channelMax = channelMax;
            channelNumberAllocator = new IntAllocator(1, channelMax);
    
            this.workService = workService;
            this.threadFactory = threadFactory;
            this.metricsCollector = metricsCollector;
        }
            
    
  3. 创建Channel,通过IntAllocator分配一个Channel编号(channelNumber),使用Map维护ChannelNumber与Channel的映射关系。

        //维护ChannelNumber与Channel的映射
        private final Map<Integer, ChannelN> _channelMap = new HashMap<Integer, ChannelN>();
        
        public ChannelN createChannel(AMQConnection connection) throws IOException {
            ChannelN ch;
            synchronized (this.monitor) {
                int channelNumber = channelNumberAllocator.allocate();
                if (channelNumber == -1) {
                    return null;
                } else {
                    ch = addNewChannel(connection, channelNumber);
                }
            }
            ch.open(); // now that it's been safely added
            return ch;
        }    
    
        private ChannelN addNewChannel(AMQConnection connection, int channelNumber) {
                if (_channelMap.containsKey(channelNumber)) {
                    // That number's already allocated! Can't do it
                    // This should never happen unless something has gone
                    // badly wrong with our implementation.
                    throw new IllegalStateException("We have attempted to "
                            + "create a channel with a number that is already in "
                            + "use. This should never happen. "
                            + "Please report this as a bug.");
                }
                ChannelN ch = instantiateChannel(connection, channelNumber, this.workService);
                _channelMap.put(ch.getChannelNumber(), ch);
                return ch;
            }
        protected ChannelN instantiateChannel(AMQConnection connection, int channelNumber, ConsumerWorkService workService) {
            return new ChannelN(connection, channelNumber, workService, this.metricsCollector);
        }
         
    
    
  4. handleSignal:关闭所有被管理的Channel,在关闭Connection时需要关闭所有Channel,就是调用此方法。从源码可以看出,使用异步关闭,主要是为了避免JDK socket wirte死锁,BIO下socket write没有写超时。详细参考http://rabbitmq.1065348.n5.nabble.com/Long-timeout-if-server-host-becomes-unreachable-td30275.html

        public void handleSignal(final ShutdownSignalException signal) {
            Set<ChannelN> channels;
            synchronized(this.monitor) {
                channels = new HashSet<ChannelN>(_channelMap.values());
            }
    
            for (final ChannelN channel : channels) {
                releaseChannelNumber(channel);
                // async shutdown if possible
                // see https://github.com/rabbitmq/rabbitmq-java-client/issues/194
                Runnable channelShutdownRunnable = new Runnable() {
                    @Override
                    public void run() {
                        channel.processShutdownSignal(signal, true, true);
                    }
                };
                if(this.shutdownExecutor == null) {
                    channelShutdownRunnable.run();
                } else {
                    Future<?> channelShutdownTask = this.shutdownExecutor.submit(channelShutdownRunnable);
                    try {
                        channelShutdownTask.get(channelShutdownTimeout, TimeUnit.MILLISECONDS);
                    } catch (Exception e) {
                        LOGGER.warn("Couldn't properly close channel {} on shutdown after waiting for {} ms", channel.getChannelNumber(), channelShutdownTimeout);
                        channelShutdownTask.cancel(true);
                    }
                }
                shutdownSet.add(channel.getShutdownLatch());
                channel.notifyListeners();
            }
            scheduleShutdownProcessing();
        }
    
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值