AmqpAdmin
AmqpAdmin定义了一些exchange和queue的创建以及绑定操作,并提供了initialize()方法供子类去实现。
Spring提供了RabbitAdmin作为AmqpAdmin的实现类。在构造函数中,传入当前的connectionFactory,然后创建RabbitTemplate实例,赋值给当前类中的rabbitTemplate
public RabbitAdmin(ConnectionFactory connectionFactory) {
Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
this.connectionFactory = connectionFactory;
this.rabbitTemplate = new RabbitTemplate(connectionFactory);
}
RabbitAdmin实现了InitializingBean,在初始化的时候会调用afterPropertiesSet方法,其中addConnectionListener注册了ConnectionListener,ConnectionListener主要方法是initialize(),initialize()中过滤掉了一些不由此RabbitAdmin初始化的exchange,queue和binding。然后对剩下的exchange,queue和binding进行初始化。
public void afterPropertiesSet() {
synchronized (this.lifecycleMonitor) {
if (this.running || !this.autoStartup) {
return;
}
if (this.retryTemplate == null && !this.retryDisabled) {
this.retryTemplate = new RetryTemplate();
this.retryTemplate.setRetryPolicy(new SimpleRetryPolicy(DECLARE_MAX_ATTEMPTS));
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(DECLARE_INITIAL_RETRY_INTERVAL);
backOffPolicy.setMultiplier(DECLARE_RETRY_MULTIPLIER);
backOffPolicy.setMaxInterval(DECLARE_MAX_RETRY_INTERVAL);
this.retryTemplate.setBackOffPolicy(backOffPolicy);
}
if (this.connectionFactory instanceof CachingConnectionFactory &&
((CachingConnectionFactory) this.connectionFactory).getCacheMode() == CacheMode.CONNECTION) {
this.logger.warn("RabbitAdmin auto declaration is not supported with CacheMode.CONNECTION");
return;
}
// Prevent stack overflow...
final AtomicBoolean initializing = new AtomicBoolean(false);
this.connectionFactory.addConnectionListener(connection -> {
if (!initializing.compareAndSet(false, true)) {
// If we are already initializing, we don't need to do it again...
return;
}
try {
/*
* ...but it is possible for this to happen twice in the same ConnectionFactory (if more than
* one concurrent Connection is allowed). It's idempotent, so no big deal (a bit of network
* chatter). In fact it might even be a good thing: exclusive queues only make sense if they are
* declared for every connection. If anyone has a problem with it: use auto-startup="false".
*/
if (this.retryTemplate != null) {
this.retryTemplate.execute(c -> {
initialize();
return null;
});
}
else {
initialize();
}
}
finally {
initializing.compareAndSet(true, false);
}
});
this.running = true;
}
}
final Collection<Exchange> exchanges = filterDeclarables(contextExchanges);
final Collection<Queue> queues = filterDeclarables(contextQueues);
final Collection<Binding> bindings = filterDeclarables(contextBindings);
this.rabbitTemplate.execute(channel -> {
declareExchanges(channel, exchanges.toArray(new Exchange[exchanges.size()]));
declareQueues(channel, queues.toArray(new Queue[queues.size()]));
declareBindings(channel, bindings.toArray(new Binding[bindings.size()]));
return null;
});
AmqpTemplate
RabbitTemplate中定义了execute(ChannelCallback action) 来处理exchange,queue以及binding的创建。ChannelCallback定义了统一的回调方法。具体过程是通过com.rabbitmq.client.Channel将指令包装为rpc帧发送给rabbitmq server(amqp-client实现)。同样的,AmapTemplate中convertAndSend方法也是同样的回调逻辑。