/* * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.autoconfigure.amqp; import com.rabbitmq.client.Channel; import org.springframework.amqp.core.AmqpAdmin; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean; import org.springframework.amqp.rabbit.core.RabbitAdmin; import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.retry.backoff.ExponentialBackOffPolicy; import org.springframework.retry.policy.SimpleRetryPolicy; import org.springframework.retry.support.RetryTemplate; /** * {@link EnableAutoConfiguration Auto-configuration} for {@link RabbitTemplate}. * <p> * This configuration class is active only when the RabbitMQ and Spring AMQP client * libraries are on the classpath. * <P> * Registers the following beans: * <ul> * <li>{@link org.springframework.amqp.rabbit.core.RabbitTemplate RabbitTemplate} if there * is no other bean of the same type in the context.</li> * <li>{@link org.springframework.amqp.rabbit.connection.CachingConnectionFactory * CachingConnectionFactory} instance if there is no other bean of the same type in the * context.</li> * <li>{@link org.springframework.amqp.core.AmqpAdmin } instance as long as * {@literal spring.rabbitmq.dynamic=true}.</li> * </ul> * <p> * The {@link org.springframework.amqp.rabbit.connection.CachingConnectionFactory} honors * the following properties: * <ul> * <li>{@literal spring.rabbitmq.port} is used to specify the port to which the client * should connect, and defaults to 5672.</li> * <li>{@literal spring.rabbitmq.username} is used to specify the (optional) username. * </li> * <li>{@literal spring.rabbitmq.password} is used to specify the (optional) password. * </li> * <li>{@literal spring.rabbitmq.host} is used to specify the host, and defaults to * {@literal localhost}.</li> * <li>{@literal spring.rabbitmq.virtualHost} is used to specify the (optional) virtual * host to which the client should connect.</li> * </ul> * * @author Greg Turnquist * @author Josh Long * @author Stephane Nicoll * @author Gary Russell */ @Configuration @ConditionalOnClass({ RabbitTemplate.class, Channel.class }) @EnableConfigurationProperties(RabbitProperties.class) @Import(RabbitAnnotationDrivenConfiguration.class) public class RabbitAutoConfiguration { @Configuration @ConditionalOnMissingBean(ConnectionFactory.class) protected static class RabbitConnectionFactoryCreator { @Bean public CachingConnectionFactory rabbitConnectionFactory(RabbitProperties config) throws Exception { RabbitConnectionFactoryBean factory = new RabbitConnectionFactoryBean(); if (config.determineHost() != null) { factory.setHost(config.determineHost()); } factory.setPort(config.determinePort()); if (config.determineUsername() != null) { factory.setUsername(config.determineUsername()); } if (config.determinePassword() != null) { factory.setPassword(config.determinePassword()); } if (config.determineVirtualHost() != null) { factory.setVirtualHost(config.determineVirtualHost()); } if (config.getRequestedHeartbeat() != null) { factory.setRequestedHeartbeat(config.getRequestedHeartbeat()); } RabbitProperties.Ssl ssl = config.getSsl(); if (ssl.isEnabled()) { factory.setUseSSL(true); if (ssl.getAlgorithm() != null) { factory.setSslAlgorithm(ssl.getAlgorithm()); } factory.setKeyStore(ssl.getKeyStore()); factory.setKeyStorePassphrase(ssl.getKeyStorePassword()); factory.setTrustStore(ssl.getTrustStore()); factory.setTrustStorePassphrase(ssl.getTrustStorePassword()); } if (config.getConnectionTimeout() != null) { factory.setConnectionTimeout(config.getConnectionTimeout()); } factory.afterPropertiesSet(); CachingConnectionFactory connectionFactory = new CachingConnectionFactory( factory.getObject()); connectionFactory.setAddresses(config.determineAddresses()); connectionFactory.setPublisherConfirms(config.isPublisherConfirms()); connectionFactory.setPublisherReturns(config.isPublisherReturns()); if (config.getCache().getChannel().getSize() != null) { connectionFactory .setChannelCacheSize(config.getCache().getChannel().getSize()); } if (config.getCache().getConnection().getMode() != null) { connectionFactory .setCacheMode(config.getCache().getConnection().getMode()); } if (config.getCache().getConnection().getSize() != null) { connectionFactory.setConnectionCacheSize( config.getCache().getConnection().getSize()); } if (config.getCache().getChannel().getCheckoutTimeout() != null) { connectionFactory.setChannelCheckoutTimeout( config.getCache().getChannel().getCheckoutTimeout()); } return connectionFactory; } } @Configuration @Import(RabbitConnectionFactoryCreator.class) protected static class RabbitTemplateConfiguration { private final ObjectProvider<MessageConverter> messageConverter; private final RabbitProperties properties; public RabbitTemplateConfiguration( ObjectProvider<MessageConverter> messageConverter, RabbitProperties properties) { this.messageConverter = messageConverter; this.properties = properties; } @Bean @ConditionalOnSingleCandidate(ConnectionFactory.class) @ConditionalOnMissingBean(RabbitTemplate.class) public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); MessageConverter messageConverter = this.messageConverter.getIfUnique(); if (messageConverter != null) { rabbitTemplate.setMessageConverter(messageConverter); } rabbitTemplate.setMandatory(determineMandatoryFlag()); RabbitProperties.Template templateProperties = this.properties.getTemplate(); RabbitProperties.Retry retryProperties = templateProperties.getRetry(); if (retryProperties.isEnabled()) { rabbitTemplate.setRetryTemplate(createRetryTemplate(retryProperties)); } if (templateProperties.getReceiveTimeout() != null) { rabbitTemplate.setReceiveTimeout(templateProperties.getReceiveTimeout()); } if (templateProperties.getReplyTimeout() != null) { rabbitTemplate.setReplyTimeout(templateProperties.getReplyTimeout()); } return rabbitTemplate; } private boolean determineMandatoryFlag() { Boolean mandatory = this.properties.getTemplate().getMandatory(); return (mandatory != null ? mandatory : this.properties.isPublisherReturns()); } private RetryTemplate createRetryTemplate(RabbitProperties.Retry properties) { RetryTemplate template = new RetryTemplate(); SimpleRetryPolicy policy = new SimpleRetryPolicy(); policy.setMaxAttempts(properties.getMaxAttempts()); template.setRetryPolicy(policy); ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy(); backOffPolicy.setInitialInterval(properties.getInitialInterval()); backOffPolicy.setMultiplier(properties.getMultiplier()); backOffPolicy.setMaxInterval(properties.getMaxInterval()); template.setBackOffPolicy(backOffPolicy); return template; } @Bean @ConditionalOnSingleCandidate(ConnectionFactory.class) @ConditionalOnProperty(prefix = "spring.rabbitmq", name = "dynamic", matchIfMissing = true) @ConditionalOnMissingBean(AmqpAdmin.class) public AmqpAdmin amqpAdmin(ConnectionFactory connectionFactory) { return new RabbitAdmin(connectionFactory); } } @Configuration @ConditionalOnClass(RabbitMessagingTemplate.class) @ConditionalOnMissingBean(RabbitMessagingTemplate.class) @Import(RabbitTemplateConfiguration.class) protected static class MessagingTemplateConfiguration { @Bean @ConditionalOnSingleCandidate(RabbitTemplate.class) public RabbitMessagingTemplate rabbitMessagingTemplate( RabbitTemplate rabbitTemplate) { return new RabbitMessagingTemplate(rabbitTemplate); } } }