AmqpTemplate

652 阅读1分钟

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方法也是同样的回调逻辑。