我们知道rabbitmq主要是用在分布式系统里面的对消息的转发,它在扩展性、扩展性、高可用性都表现得不错,所以得到了不错的反响,它也是社区活跃度较高的消息中间件之一。
Rabbitmq的核心组件
先来看看Rabbitmq的结构模型,由生产者给交换机发送消息,然后交换机根据所定制的路由规则,就把不同的消息路由到不一样的队列里。监听队列就当有消息过来的时候就开始消费。
vHost虚拟主机
在rabbitmq服务器上可以设置多个虚拟主机,也可以说一个broker里面可以开多个vhost。其实每一个vhost它都是一个迷你版的rabbitmq服务器,都拥有自己的交换机,binding、队列。更核心的就是每一个vhost它是独立的权限机制,这样的话就可以安全的使用rabbitmq来服务多个程序。
Exchange交换机
根据路由规则把消息转发到队列里。
Connection
生产/消费者都需要跟broker来进行连接,它是一条tcp连接。
什么是AMQP?
其实就是生产者发送消息,然后经过了交换机,交换机再根据路由规则来给队列,最后面AMQP代理就会把消息投递给订阅了这个队列的消费者。
ChannelManager解析
首先看看它的成员变量有哪些
变量名称 | 默认值 | 描述 |
---|---|---|
final Object monitor | new Object() | 加锁的对象 |
final Map<Integer, ChannelN> _channelMap | new HashMap | 通道map对象 |
final IntAllocator channelNumberAllocator | 通道编号分配器 | |
final ConsumerWorkService workService | 工作服务对象 | |
final Set shutdownSet | new HashSet() | 关闭线程等待 |
方法
方法名 | 描述 |
---|---|
ChannelManager( workService, channelMax,threadFactory,metricsCollector) | 构造方法 |
ChannelN getChannel(int channelNumber) | 获取通道对象,需要对于monitor加锁 |
void handleSignal(final ShutdownSignalException signal) | 处理关闭信号,也就关闭对应通道 |
ChannelN createChannel(AMQConnection connection) | 创建通道 |
void realeaseChannelNumber(ChannelN channel) | 释放通道 |
在生产/消费消息之前需要初始化Channel
Channel channel = connection.createChannel();
上面的createChannel它是AMQConnection里的一个方法
public Channel createChannel(int channelNumber) throws IOException {
ensureIsOpen();
ChannelManager cm = _channelManager;
if (cm == null) return null;
return cm.createChannel(this, channelNumber);
}
public Channel createChannel() throws IOException {
ensureIsOpen();
ChannelManager cm = _channelManager;
if (cm == null) return null;
return cm.createChannel(this);
}
这里调用了createChannel方法,接下来就是ChannelManager创建了Channel
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;
}
public ChannelN createChannel(AMQConnection connection, int channelNumber) throws IOException {
ChannelN ch;
synchronized (this.monitor) {
if (channelNumberAllocator.reserve(channelNumber)) {
ch = addNewChannel(connection, channelNumber);
} else {
return null;
}
}
ch.open(); // now that it's been safely added
return ch;
}
private ChannelN addNewChannel(AMQConnection connection, int channelNumber) throws IOException {
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);
}
其实addNewChannel它就是创建了ChannelN对象,然后就是在ChannelManager里的_channelMap当中,易于管理,而chanelNumberAllocator它其实是channelNumber的分配器,就是采用BitSet来实现分配的。
void handleSignal(final ShutdownSignalException signal)
(1)需要同步获取到所有的通道
(2)移除掉通道的编号
(3)创建channel关闭的Runnable接口
(4)shudownExecutor为空,那么就直接同步run方法
(5)shudownExecutor不为空,就异步的执行和确定关闭通道的超时时间
(6)把每一个channel关闭,再把countdownlatch对象给收集起来
(7)通知关闭监听器,执行关闭的操作
(8)在关闭consumerworkservice的时候需要等待所有的channel才执行。
ChannelN createChannel
(1)分配通道编号
(2)添加新通道(父级方法)
(3)判断通道编号是否存在,存在则抛出异常
(4)将通道加入到通道map中
(5)打开通道操作,连接