【深入理解RabbitMQ原理】Spring AMQP 声明队列和交换机的顺序问题

 

 

                                           AMQP 声明队列和交换机的顺序问题

 

消息发送方和接收方都可以去声明交换机或者队列, 但是这个顺序是咋样的?

一直认为只要启动了Sprig 容器,那么就自动声明了交换机和队列,其实不是这样的。

生产者是在发送的时候,消费者是在容器启动的时候初始化的

CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        this.rabbitTemplate.convertAndSend(this.routingKey, message, correlationData);

RabbitAdmin类

public void initialize() {

		if (this.applicationContext == null) {
			if (this.logger.isDebugEnabled()) {
				this.logger
						.debug("no ApplicationContext has been set, cannot auto-declare Exchanges, Queues, and Bindings");
			}
			return;
		}

		logger.debug("Initializing declarations");
		final Collection exchanges = filterDeclarables(applicationContext.getBeansOfType(Exchange.class).values());
		final Collection queues = filterDeclarables(applicationContext.getBeansOfType(Queue.class).values());
		final Collection bindings = filterDeclarables(applicationContext.getBeansOfType(Binding.class).values());

		for (Exchange exchange : exchanges) {
			if (!exchange.isDurable()) {
				logger.warn("Auto-declaring a non-durable Exchange ("
						+ exchange.getName()
						+ "). It will be deleted by the broker if it shuts down, and can be redeclared by closing and reopening the connection.");
			}
			if (exchange.isAutoDelete()) {
				logger.warn("Auto-declaring an auto-delete Exchange ("
						+ exchange.getName()
						+ "). It will be deleted by the broker if not in use (if all bindings are deleted), but will only be redeclared if the connection is closed and reopened.");
			}
		}

		for (Queue queue : queues) {
			if (!queue.isDurable()) {
				logger.warn("Auto-declaring a non-durable Queue ("
						+ queue.getName()
						+ "). It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.");
			}
			if (queue.isAutoDelete()) {
				logger.warn("Auto-declaring an auto-delete Queue ("
						+ queue.getName()
						+ "). It will be deleted by the broker if not in use, and all messages will be lost.  Redeclared when the connection is closed and reopened.");
			}
			if (queue.isExclusive()) {
				logger.warn("Auto-declaring an exclusive Queue ("
						+ queue.getName()
						+ "). It cannot be accessed by consumers on another connection, and will be redeclared if the connection is reopened.");
			}
		}

		rabbitTemplate.execute(new ChannelCallback() {
			@Override
			public Object doInRabbit(Channel channel) throws Exception {
				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;
			}
		});
		logger.debug("Declarations finished");

	} 
  
send 方法
public void send(final String exchange, final String routingKey,
			final Message message, final CorrelationData correlationData)
			throws AmqpException {
		execute(new ChannelCallback() {

			@Override
			public Object doInRabbit(Channel channel) throws Exception {
				doSend(channel, exchange, routingKey, message, correlationData);
				return null;
			}
		});
	}	

里面先执行execute 

	@Override
	public  T execute(final ChannelCallback action) {
		if (this.retryTemplate != null) {
			try {
				return this.retryTemplate.execute(new RetryCallback() {

					@Override
					public T doWithRetry(RetryContext context) throws Exception {
						return RabbitTemplate.this.doExecute(action);
					}

				});
			}
			catch (Exception e) {
				if (e instanceof RuntimeException) {
					throw (RuntimeException) e;
				}
				throw RabbitExceptionTranslator.convertRabbitAccessException(e);
			}
		}
		else {
			return this.doExecute(action);
		}
	}

然后执行下面的duExecute() 方法

private  T doExecute(ChannelCallback action) {
		Assert.notNull(action, "Callback object must not be null");
		RabbitResourceHolder resourceHolder = getTransactionalResourceHolder();
		Channel channel = resourceHolder.getChannel();
		if (this.confirmCallback != null || this.returnCallback != null) {
			addListener(channel);
		}
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("Executing callback on RabbitMQ Channel: " + channel);
			}
			return action.doInRabbit(channel);
		}
		catch (Exception ex) {
			if (isChannelLocallyTransacted(channel)) {
				resourceHolder.rollbackAll();
			}
			throw convertRabbitAccessException(ex);
		}
		finally {
			ConnectionFactoryUtils.releaseResources(resourceHolder);
		}
	}

执行完之后,执行上面的initialize() 方法


之后执行 action.doInRabbit(channel); 声明队列交换机,通道,绑定
rabbitTemplate.execute(new ChannelCallback() {
			@Override
			public Object doInRabbit(Channel channel) throws Exception {
				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;
			}
		});

然后会释放掉资源
finally {
			ConnectionFactoryUtils.releaseResources(resourceHolder);
		}

public static void releaseResources(RabbitResourceHolder resourceHolder) {
		if (resourceHolder == null || resourceHolder.isSynchronizedWithTransaction()) {
			return;
		}
		RabbitUtils.closeChannel(resourceHolder.getChannel());
		RabbitUtils.closeConnection(resourceHolder.getConnection());
	}


inilization初始化之后创建连接
	public void onCreate(Connection connection) {
		for (ConnectionListener delegate : delegates) {
			delegate.onCreate(connection);
		}
	}
doExecute里面:
RabbitResourceHolder resourceHolder = getTransactionalResourceHolder();
		Channel channel = resourceHolder.getChannel();

看getTransactionalResourceHolder实现
protected RabbitResourceHolder getTransactionalResourceHolder() {
		RabbitResourceHolder holder = ConnectionFactoryUtils.getTransactionalResourceHolder(this.connectionFactory,
				isChannelTransacted());
		return holder;
	}
实现:
private static RabbitResourceHolder doGetTransactionalResourceHolder(ConnectionFactory connectionFactory,
			ResourceFactory resourceFactory) {

		Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
		Assert.notNull(resourceFactory, "ResourceFactory must not be null");

		RabbitResourceHolder resourceHolder = (RabbitResourceHolder) TransactionSynchronizationManager
				.getResource(connectionFactory);
		if (resourceHolder != null) {
			Channel channel = resourceFactory.getChannel(resourceHolder);
			if (channel != null) {
				return resourceHolder;
			}
		}
		RabbitResourceHolder resourceHolderToUse = resourceHolder;
		if (resourceHolderToUse == null) {
			resourceHolderToUse = new RabbitResourceHolder();
		}
		Connection connection = resourceFactory.getConnection(resourceHolderToUse);
		Channel channel = null;
		try {
			/*
			 * If we are in a listener container, first see if there's a channel registered
			 * for this consumer and the consumer is using the same connection factory.
			 */
			channel = ConsumerChannelRegistry.getConsumerChannel(connectionFactory);
			if (channel == null && connection == null) {
				connection = resourceFactory.createConnection();
				resourceHolderToUse.addConnection(connection);
			}
			if (channel == null) {
				channel = resourceFactory.createChannel(connection);
			}
			resourceHolderToUse.addChannel(channel, connection);

			if (resourceHolderToUse != resourceHolder) {
				bindResourceToTransaction(resourceHolderToUse, connectionFactory,
						resourceFactory.isSynchedLocalTransactionAllowed());
			}

			return resourceHolderToUse;

		} catch (IOException ex) {
			RabbitUtils.closeChannel(channel);
			RabbitUtils.closeConnection(connection);
			throw new AmqpIOException(ex);
		}
	}

主要代码:
if (channel == null && connection == null) {
				connection = resourceFactory.createConnection();
				resourceHolderToUse.addConnection(connection);
			}
			if (channel == null) {
				channel = resourceFactory.createChannel(connection);
			}
			resourceHolderToUse.addChannel(channel, connection);



走完了execute ,然后走doSend方法
protected void doSend(Channel channel, String exchange, String routingKey, Message message,
			CorrelationData correlationData) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("Publishing message on exchange [" + exchange + "], routingKey = [" + routingKey + "]");
		}

		if (exchange == null) {
			// try to send to configured exchange
			exchange = this.exchange;
		}

		if (routingKey == null) {
			// try to send to configured routing key
			routingKey = this.routingKey;
		}
		if (this.confirmCallback != null && channel instanceof PublisherCallbackChannel) {
			PublisherCallbackChannel publisherCallbackChannel = (PublisherCallbackChannel) channel;
			publisherCallbackChannel.addPendingConfirm(this, channel.getNextPublishSeqNo(),
					new PendingConfirm(correlationData, System.currentTimeMillis()));
		}
		boolean mandatory = this.returnCallback != null && this.mandatory;
		MessageProperties messageProperties = message.getMessageProperties();
		if (mandatory) {
			messageProperties.getHeaders().put(PublisherCallbackChannel.RETURN_CORRELATION, this.uuid);
		}
		BasicProperties convertedMessageProperties = this.messagePropertiesConverter
				.fromMessageProperties(messageProperties, encoding);
		channel.basicPublish(exchange, routingKey, mandatory, convertedMessageProperties, message.getBody());
		// Check if commit needed
		if (isChannelLocallyTransacted(channel)) {
			// Transacted channel created by this template -> commit.
			RabbitUtils.commitIfNecessary(channel);
		}
	}
 
  
protected  T doExecute(RetryCallback retryCallback, RecoveryCallback recoveryCallback, RetryState state)
			throws Exception, ExhaustedRetryException {

		RetryPolicy retryPolicy = this.retryPolicy;
		BackOffPolicy backOffPolicy = this.backOffPolicy;

		// Allow the retry policy to initialise itself...
		RetryContext context = open(retryPolicy, state);
		if (logger.isTraceEnabled()) {
			logger.trace("RetryContext retrieved: " + context);
		}

		// Make sure the context is available globally for clients who need
		// it...
		RetrySynchronizationManager.register(context);

		Throwable lastException = null;

		try {

			// Give clients a chance to enhance the context...
			boolean running = doOpenInterceptors(retryCallback, context);

			if (!running) {
				throw new TerminatedRetryException("Retry terminated abnormally by interceptor before first attempt");
			}

			// Get or Start the backoff context...
			BackOffContext backOffContext = null;
			AttributeAccessor attributeAccessor = null;
			if (context instanceof AttributeAccessor) {
				attributeAccessor = (AttributeAccessor) context;
				Object resource = attributeAccessor.getAttribute("backOffContext");
				if (resource instanceof BackOffContext) {
					backOffContext = (BackOffContext) resource;
				}
			}
			if (backOffContext == null) {
				backOffContext = backOffPolicy.start(context);
				if (attributeAccessor != null && backOffContext != null) {
					attributeAccessor.setAttribute("backOffContext", backOffContext);
				}
			}

			/*
			 * We allow the whole loop to be skipped if the policy or context
			 * already forbid the first try. This is used in the case of
			 * external retry to allow a recovery in handleRetryExhausted
			 * without the callback processing (which would throw an exception).
			 */
			while (canRetry(retryPolicy, context) && !context.isExhaustedOnly()) {

				try {
					logger.debug("Retry: count=" + context.getRetryCount());
					// Reset the last exception, so if we are successful
					// the close interceptors will not think we failed...
					lastException = null;
					return retryCallback.doWithRetry(context);
				}
				catch (Throwable e) {

					lastException = e;

					doOnErrorInterceptors(retryCallback, context, e);

					try {
						registerThrowable(retryPolicy, state, context, e);
					} catch (Exception ex) {
						throw new TerminatedRetryException("Could not register throwable", ex);
					}

					if (canRetry(retryPolicy, context) && !context.isExhaustedOnly()) {
						try {
							backOffPolicy.backOff(backOffContext);
						}
						catch (BackOffInterruptedException ex) {
							lastException = e;
							// back off was prevented by another thread - fail
							// the retry
							logger.debug("Abort retry because interrupted: count=" + context.getRetryCount());
							throw ex;
						}
					}

					logger.debug("Checking for rethrow: count=" + context.getRetryCount());
					if (shouldRethrow(retryPolicy, context, state)) {
						logger.debug("Rethrow in retry for policy: count=" + context.getRetryCount());
						throw wrapIfNecessary(e);
					}

				}

				/*
				 * A stateful attempt that can retry should have rethrown the
				 * exception by now - i.e. we shouldn't get this far for a
				 * stateful attempt if it can retry.
				 */
			}

			logger.debug("Retry failed last attempt: count=" + context.getRetryCount());

			if (context.isExhaustedOnly()) {
				throw new ExhaustedRetryException("Retry exhausted after last attempt with no recovery path.", context
						.getLastThrowable());
			}

			return handleRetryExhausted(recoveryCallback, context, state);

		}
		finally {
			close(retryPolicy, context, state, lastException == null);
			doCloseInterceptors(retryCallback, context, lastException);
			RetrySynchronizationManager.clear();
		}

【深入理解RabbitMQ原理】Spring AMQP 声明队列和交换机的顺序问题_第1张图片

debug 了amqp源码之后有所发送

调用了rabbitmqtemplate去发送消息时;发送码有这么个办法

并且消费消息的时候也会进入这个方法

	rabbitTemplate.execute(new ChannelCallback() {
			@Override
			public Object doInRabbit(Channel channel) throws Exception {
				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;
			}
		}); 
  

先声明交换机,再声明队列,最后绑定

private void declareExchanges(final Channel channel, final Exchange... exchanges) throws IOException {
		for (final Exchange exchange : exchanges) {
			if (logger.isDebugEnabled()) {
				logger.debug("declaring Exchange '" + exchange.getName() + "'");
			}

			if (!isDeclaringDefaultExchange(exchange)) {
				try {
					channel.exchangeDeclare(exchange.getName(), exchange.getType(), exchange.isDurable(),
						exchange.isAutoDelete(), exchange.getArguments());
				}
				catch (IOException e) {
					if (this.ignoreDeclarationExceptions) {
						if (logger.isWarnEnabled()) {
							logger.warn("Failed to declare exchange:" + exchange + ", continuing...", e);
						}
					}
					else {
						throw e;
					}
				}
			}
		}
	}

 

声明队列的一些参数:

autoDelete:自动删除,如果该队列没有任何订阅的消费者的话,该队列会被自动删除。这种队列适用于临时队列。

queue:queue的名称

exclusive:排他队列,如果一个队列被声明为排他队列,该队列仅对首次申明它的连接可见,并在连接断开时自动删除。这里需要注意三点:1. 排他队列是基于连接可见的,同一连接的不同信道是可以同时访问同一连接创建的排他队列;2.“首次”,如果一个连接已经声明了一个排他队列,其他连接是不允许建立同名的排他队列的,这个与普通队列不同;3.即使该队列是持久化的,一旦连接关闭或者客户端退出,该排他队列都会被自动删除的,这种队列适用于一个客户端发送读取消息的应用场景。

autoDelete:自动删除,如果该队列没有任何订阅的消费者的话,该队列会被自动删除。这种队列适用于临时队列。

 

插个题外话,channel源码中有

   Queue.DeclareOk queueDeclarePassive(String queue) throws IOException;

这个方法的意思是:一个queue是否已经存在。如果该队列存在,则会返回true;如果不存在,就会返回异常,但是不会创建新的队列

但不不一样的是消费方

进入了方法 attemptPassiveDeclarations()

public void start() throws AmqpException {
		if (logger.isDebugEnabled()) {
			logger.debug("Starting consumer " + this);
		}
		try {
			this.resourceHolder = ConnectionFactoryUtils.getTransactionalResourceHolder(connectionFactory, transactional);
			this.channel = resourceHolder.getChannel();
		}
		catch (AmqpAuthenticationException e) {
			throw new FatalListenerStartupException("Authentication failure", e);
		}
		this.consumer = new InternalConsumer(channel);
		this.deliveryTags.clear();
		this.activeObjectCounter.add(this);

		// mirrored queue might be being moved
		int passiveDeclareTries = 3;
		do {
			try {
				attemptPassiveDeclarations();
				if (passiveDeclareTries < 3 && logger.isInfoEnabled()) {
					logger.info("Queue declaration succeeded after retrying");
				}
				passiveDeclareTries = 0;
			}
			catch (DeclarationException e) {
				if (passiveDeclareTries > 0 && channel.isOpen()) {
					if (logger.isWarnEnabled()) {
						logger.warn("Queue declaration failed; retries left=" + (passiveDeclareTries-1), e);
						try {
							Thread.sleep(5000);
						}
						catch (InterruptedException e1) {
							Thread.currentThread().interrupt();
						}
					}
				}
				else if (e.getFailedQueues().size() < this.queues.length) {
					if (logger.isWarnEnabled()) {
						logger.warn("Not all queues are available; only listening on those that are - configured: "
								+ Arrays.asList(this.queues) + "; not available: " + e.getFailedQueues());
					}
					this.missingQueues.addAll(e.getFailedQueues());
					this.lastRetryDeclaration = System.currentTimeMillis();
				}
				else {
					this.activeObjectCounter.release(this);
					throw new QueuesNotAvailableException("Cannot prepare queue for listener. "
							+ "Either the queue doesn't exist or the broker will not allow us to use it.", e);
				}
			}
		}
		while (passiveDeclareTries-- > 0);

		if (!acknowledgeMode.isAutoAck()) {
			// Set basicQos before calling basicConsume (otherwise if we are not acking the broker
			// will send blocks of 100 messages)
			try {
				channel.basicQos(prefetchCount);
			}
			catch (IOException e) {
				this.activeObjectCounter.release(this);
				throw new FatalListenerStartupException("Cannot set basicQos.", e);
			}
		}


		try {
			for (String queueName : queues) {
				if (!this.missingQueues.contains(queueName)) {
					consumeFromQueue(queueName);
				}
			}
		}
		catch (IOException e) {
			throw RabbitExceptionTranslator.convertRabbitAccessException(e);
		}
	}
private void attemptPassiveDeclarations() {
		DeclarationException failures = null;
		for (String queueName : this.queues) {
			try {
				this.channel.queueDeclarePassive(queueName);
			}
			catch (IOException e) {
				if (logger.isWarnEnabled()) {
					logger.warn("Failed to declare queue:" + queueName);
				}
				if (failures == null) {
					failures = new DeclarationException();
				}
				failures.addFailedQueue(queueName);
			}
		}
		if (failures != null) {
			throw failures;
		}
	}

这个是QueyeDeclarePassive  是去检查,这个队列有没有声明成功,没有声明成功是会报错的。

 

消费者容器启动为什么会创建声明

看线程的run 方法

@Override
		public void run() {

			boolean aborted = false;

			int consecutiveIdles = 0;

			int consecutiveMessages = 0;

			try {

				try {
					SimpleMessageListenerContainer.this.redeclareElementsIfNecessary();
					this.consumer.start();
					this.start.countDown();
				}
				catch (QueuesNotAvailableException e) {
					if (SimpleMessageListenerContainer.this.missingQueuesFatal) {
						throw e;
					}
					else {
						this.start.countDown();
						handleStartupFailure(e);
						throw e;
					}
				}
				catch (FatalListenerStartupException ex) {
					throw ex;
				}
				catch (Throwable t) {
					this.start.countDown();
					handleStartupFailure(t);
					throw t;
				}

				if (SimpleMessageListenerContainer.this.transactionManager != null) {
					/*
					 * Register the consumer's channel so it will be used by the transaction manager
					 * if it's an instance of RabbitTransactionManager.
					 */
					ConsumerChannelRegistry.registerConsumerChannel(consumer.getChannel(), getConnectionFactory());
				}

				// Always better to stop receiving as soon as possible if
				// transactional
				boolean continuable = false;
				while (isActive(this.consumer) || continuable) {
					try {
						// Will come back false when the queue is drained
						continuable = receiveAndExecute(this.consumer) && !isChannelTransacted();
						if (SimpleMessageListenerContainer.this.maxConcurrentConsumers != null) {
							if (continuable) {
								consecutiveIdles = 0;
								if (consecutiveMessages++ > SimpleMessageListenerContainer.this.consecutiveActiveTrigger) {
									considerAddingAConsumer();
									consecutiveMessages = 0;
								}
							}
							else {
								consecutiveMessages = 0;
								if (consecutiveIdles++ > SimpleMessageListenerContainer.this.consecutiveIdleTrigger) {
									considerStoppingAConsumer(this.consumer);
									consecutiveIdles = 0;
								}
							}
						}
					}
					catch (ListenerExecutionFailedException ex) {
						// Continue to process, otherwise re-throw
					}
					catch (AmqpRejectAndDontRequeueException rejectEx) {
						/*
						 *  These will normally be wrapped by an LEFE if thrown by the
						 *  listener, but we will also honor it if thrown by an
						 *  error handler.
						 */
					}
				}

			}
			catch (InterruptedException e) {
				logger.debug("Consumer thread interrupted, processing stopped.");
				Thread.currentThread().interrupt();
				aborted = true;
			}
			catch (QueuesNotAvailableException ex) {
				if (SimpleMessageListenerContainer.this.missingQueuesFatal) {
					logger.error("Consumer received fatal exception on startup", ex);
					this.startupException = ex;
					// Fatal, but no point re-throwing, so just abort.
					aborted = true;
				}
			}
			catch (FatalListenerStartupException ex) {
				logger.error("Consumer received fatal exception on startup", ex);
				this.startupException = ex;
				// Fatal, but no point re-throwing, so just abort.
				aborted = true;
			}
			catch (FatalListenerExecutionException ex) {
				logger.error("Consumer received fatal exception during processing", ex);
				// Fatal, but no point re-throwing, so just abort.
				aborted = true;
			}
			catch (ShutdownSignalException e) {
				if (RabbitUtils.isNormalShutdown(e)) {
					if (logger.isDebugEnabled()) {
						logger.debug("Consumer received Shutdown Signal, processing stopped: " + e.getMessage());
					}
				}
				else {
					this.logConsumerException(e);
				}
			}
			catch (AmqpIOException e) {
				if (e.getCause() instanceof IOException && e.getCause().getCause() instanceof ShutdownSignalException
						&& e.getCause().getCause().getMessage().contains("in exclusive use")) {
					logger.warn(e.getCause().getCause().toString());
				}
				else {
					this.logConsumerException(e);
				}
			}
			catch (Error e) {
				logger.error("Consumer thread error, thread abort.", e);
				aborted = true;
			}
			catch (Throwable t) {
				this.logConsumerException(t);
			}
			finally {
				if (SimpleMessageListenerContainer.this.transactionManager != null) {
					ConsumerChannelRegistry.unRegisterConsumerChannel();
				}
			}

			// In all cases count down to allow container to progress beyond startup
			start.countDown();

			if (!isActive(consumer) || aborted) {
				logger.debug("Cancelling " + this.consumer);
				try {
					this.consumer.stop();
					synchronized (consumersMonitor) {
						if (SimpleMessageListenerContainer.this.consumers != null) {
							SimpleMessageListenerContainer.this.consumers.remove(this.consumer);
						}
					}
				}
				catch (AmqpException e) {
					logger.info("Could not cancel message consumer", e);
				}
				if (aborted) {
					logger.error("Stopping container from aborted consumer");
					stop();
				}
			}
			else {
				logger.info("Restarting " + this.consumer);
				restart(this.consumer);
			}

		}

关键的一行在这里

SimpleMessageListenerContainer.this.redeclareElementsIfNecessary();

 

万一实在是想创建怎么办

RabbitAdmin  RabbitAdmin =(RabbitAdmin) APPLICATION_CONTEXT.getBean("RabbitAdmin");
            RabbitAdmin.initialize();

 

生产者还是消费者启动,创建连接时,会走 RabbitAdmin.initialize() 方法

	try {
			this.resourceHolder = ConnectionFactoryUtils.getTransactionalResourceHolder(connectionFactory, transactional);
			this.channel = resourceHolder.getChannel();
		}
	public final Connection createConnection() throws AmqpException {
		synchronized (this.connectionMonitor) {
			if (this.cacheMode == CacheMode.CHANNEL) {
				if (this.connection == null) {
					this.connection = new ChannelCachingConnectionProxy(super.createBareConnection());
					// invoke the listener *after* this.connection is assigned
//创建连接的时候 connection
					getConnectionListener().onCreate(connection);
				}
				return this.connection;
			}
this.connectionFactory.addConnectionListener(new ConnectionListener() {

				// Prevent stack overflow...
				private final AtomicBoolean initializing = new AtomicBoolean(false);

				@Override
				public void onCreate(Connection 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".
						 */
						initialize();
					}
					finally {
						initializing.compareAndSet(true, false);
					}
				}

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(【深入理解RabbitMQ原理】Spring AMQP 声明队列和交换机的顺序问题)