漫游MQ-socket 长连接

使用MQ发送或者接收消息,首先需要与broker 保持通信,是怎样工作的?

consumer绑定的listener是什么时机触发的?


Insight 过程使用的activemq,模板如下:

ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
connection.start();

Topic topic = session.createTopic("log-topic");
MessageConsumer consumer = session.createConsumer(topic);
consumer.setMessageListener(new LogListener());
创建connection,基于TansportFactory.createTransport() 会创建FailoverTransport,保障mq通信failover。

然后,创建session,也就是线程ActiveMQ Task-n 会创建关键的TcpTransport, 通过FailoverTransport.task 的iterate方法,开始建立连接。

TcpTransport 与broker建立了长连接,同时实现了Runnable接口,消息的传递以及listener的触发就看run() 的实现了。

过程如下:socket读取-listener消费链处理-对应的session分发message- message 入队列。

由上述的过程可以看到,consumer绑定的listener并没有直接通知消费,接着看代码。

session创建的taskRunner,调用wakeup()后,启动消费message队列的线程,如果有message 入队列,则分发至对应的consumer,具体的处理流程见源码:

public void dispatch(MessageDispatch md) {
    MessageListener listener = this.messageListener.get();
    try {
    	synchronized (unconsumedMessages.getMutex()) {
            if (!unconsumedMessages.isClosed()) {
                if (listener != null && unconsumedMessages.isRunning()) {
                	ActiveMQMessage message = createActiveMQMessage(md);
                	beforeMessageIsConsumed(md);
                	try {
                		boolean expired = message.isExpired();
                		if (!expired) {
                		    listener.onMessage(message);
                		}
                		afterMessageIsConsumed(md, expired);
                	} catch (RuntimeException e) {
                	    // ack rollback...
                	}
                } else {
                	unconsumedMessages.enqueue(md);
                	if (availableListener != null) {
                		availableListener.onMessageAvailable(this);
                	}
                }
            }
    	}
    } catch (Exception e) {
        session.connection.onClientInternalException(e);
    }
}
可以对比看 receive() 的处理。


结论:

mq 的通信默认使用tcp socket 长连接实现,支持failover。

consumer绑定的listener由session 级别的线程去触发,没有listener 则将message转入unconsume队列,待调用receive()再消费该message。


备注

mq封装实现的自己的Executor用于长连接任务的管理,TaskRunnerFactory name = "ActiveMQ Task",真正的提交runnable task其实还是ThreadPoolExecutor去完成。

生成全局唯一的Id,可以参考IdGenerator。

mq Command消费的listener传递链,可以参考TransportFilter 类。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值