Expose additional RabbitMQ settings

Allow SSL to be configured via standard configuration as well as the
requestedHeartbeat. Switch to RabbitConnectionFactoryBean.

Closes gh-2655, gh-2676
pull/2772/merge
Stephane Nicoll 10 years ago
parent ab55331863
commit e3a124d0f9

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2015 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.
@ -16,9 +16,13 @@
package org.springframework.boot.autoconfigure.amqp;
import java.io.ByteArrayOutputStream;
import java.util.Properties;
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;
@ -31,6 +35,7 @@ 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.core.io.ByteArrayResource;
import com.rabbitmq.client.Channel;
@ -72,6 +77,7 @@ import com.rabbitmq.client.Channel;
* </ul>
* @author Greg Turnquist
* @author Josh Long
* @author Stephane Nicoll
*/
@Configuration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@ -100,10 +106,8 @@ public class RabbitAutoConfiguration {
protected static class RabbitConnectionFactoryCreator {
@Bean
public ConnectionFactory rabbitConnectionFactory(RabbitProperties config) {
CachingConnectionFactory factory = new CachingConnectionFactory();
String addresses = config.getAddresses();
factory.setAddresses(addresses);
public ConnectionFactory rabbitConnectionFactory(RabbitProperties config) throws Exception {
RabbitConnectionFactoryBean factory = new RabbitConnectionFactoryBean();
if (config.getHost() != null) {
factory.setHost(config.getHost());
factory.setPort(config.getPort());
@ -117,7 +121,24 @@ public class RabbitAutoConfiguration {
if (config.getVirtualHost() != null) {
factory.setVirtualHost(config.getVirtualHost());
}
return factory;
if (config.getRequestedHeartbeat() != null) {
factory.setRequestedHeartbeat(config.getRequestedHeartbeat());
}
RabbitProperties.Ssl ssl = config.getSsl();
if (ssl.isEnabled()) {
factory.setUseSSL(true);
if (ssl.getKeyStore() != null || ssl.getTrustStore() != null) {
Properties properties = ssl.createSslProperties();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
properties.store(outputStream, "SSL config");
factory.setSslPropertiesLocation(
new ByteArrayResource(outputStream.toByteArray()));
}
}
factory.afterPropertiesSet();
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(factory.getObject());
connectionFactory.setAddresses(config.getAddresses());
return connectionFactory;
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2015 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.
@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.amqp;
import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.Set;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ -27,6 +28,7 @@ import org.springframework.util.StringUtils;
*
* @author Greg Turnquist
* @author Dave Syer
* @author Stephane Nicoll
*/
@ConfigurationProperties(prefix = "spring.rabbitmq")
public class RabbitProperties {
@ -51,6 +53,11 @@ public class RabbitProperties {
*/
private String password;
/**
* SSL configuration.
*/
private final Ssl ssl = new Ssl();
/**
* Virtual host to use when connecting to the broker.
*/
@ -61,6 +68,12 @@ public class RabbitProperties {
*/
private String addresses;
/**
* Requested heartbeat timeout, in seconds; zero for none.
*/
private Integer requestedHeartbeat;
public String getHost() {
if (this.addresses == null) {
return this.host;
@ -147,6 +160,10 @@ public class RabbitProperties {
this.password = password;
}
public Ssl getSsl() {
return ssl;
}
public String getVirtualHost() {
return this.virtualHost;
}
@ -155,4 +172,102 @@ public class RabbitProperties {
this.virtualHost = ("".equals(virtualHost) ? "/" : virtualHost);
}
public Integer getRequestedHeartbeat() {
return requestedHeartbeat;
}
public void setRequestedHeartbeat(Integer requestedHeartbeat) {
this.requestedHeartbeat = requestedHeartbeat;
}
public static class Ssl {
/**
* Enable SSL support.
*/
private boolean enabled;
/**
* Path to the key store that holds the SSL certificate.
*/
private String keyStore;
/**
* Password used to access the key store.
*/
private String keyStorePassword;
/**
* Trust store that holds SSL certificates.
*/
private String trustStore;
/**
* Password used to access the trust store.
*/
private String trustStorePassword;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getKeyStore() {
return keyStore;
}
public void setKeyStore(String keyStore) {
this.keyStore = keyStore;
}
public String getKeyStorePassword() {
return keyStorePassword;
}
public void setKeyStorePassword(String keyStorePassword) {
this.keyStorePassword = keyStorePassword;
}
public String getTrustStore() {
return trustStore;
}
public void setTrustStore(String trustStore) {
this.trustStore = trustStore;
}
public String getTrustStorePassword() {
return trustStorePassword;
}
public void setTrustStorePassword(String trustStorePassword) {
this.trustStorePassword = trustStorePassword;
}
/**
* Create the ssl configuration as expected by the
* {@link org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean RabbitConnectionFactoryBean}.
* @return the ssl configuration
*/
public Properties createSslProperties() {
Properties properties = new Properties();
if (getKeyStore() != null) {
properties.put("keyStore", getKeyStore());
}
if (getKeyStorePassword() != null) {
properties.put("keyStore.passPhrase", getKeyStorePassword());
}
if (getTrustStore() != null) {
properties.put("trustStore", getTrustStore());
}
if (getTrustStorePassword() != null) {
properties.put("trustStore.passPhrase", getTrustStorePassword());
}
return properties;
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2015 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.
@ -16,6 +16,9 @@
package org.springframework.boot.autoconfigure.amqp;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
@ -31,6 +34,7 @@ import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@ -47,6 +51,7 @@ import static org.mockito.Mockito.verify;
* Tests for {@link RabbitAutoConfiguration}.
*
* @author Greg Turnquist
* @author Stephane Nicoll
*/
public class RabbitAutoConfigurationTests {
@ -188,6 +193,46 @@ public class RabbitAutoConfigurationTests {
ctx.getBean(RabbitListenerConfigUtils.RABBIT_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME);
}
@Test
public void customizeRequestedHeartBeat() {
load(TestConfiguration.class, "spring.rabbitmq.requestedHeartbeat:20");
com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory();
assertEquals(20, rabbitConnectionFactory.getRequestedHeartbeat());
}
@Test
public void noSslByDefault() {
load(TestConfiguration.class);
com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory();
assertEquals("Must use default SocketFactory", SocketFactory.getDefault(),
rabbitConnectionFactory.getSocketFactory());
}
@Test
public void enableSsl() {
load(TestConfiguration.class, "spring.rabbitmq.ssl.enabled:true");
com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory();
assertTrue("SocketFactory must use SSL", rabbitConnectionFactory.getSocketFactory() instanceof SSLSocketFactory);
}
@Test // Make sure that we at least attempt to load the store
public void enableSslWithExtraConfig() {
thrown.expectMessage("foo");
thrown.expectMessage("does not exist");
load(TestConfiguration.class, "spring.rabbitmq.ssl.enabled:true",
"spring.rabbitmq.ssl.keyStore=foo",
"spring.rabbitmq.ssl.keyStorePassword=secret",
"spring.rabbitmq.ssl.trustStore=bar",
"spring.rabbitmq.ssl.trustStorePassword=secret");
}
private com.rabbitmq.client.ConnectionFactory getTargetConnectionFactory() {
CachingConnectionFactory connectionFactory = this.context
.getBean(CachingConnectionFactory.class);
return (com.rabbitmq.client.ConnectionFactory)
new DirectFieldAccessor(connectionFactory).getPropertyValue("rabbitConnectionFactory");
}
private void load(Class<?> config, String... environment) {
this.context = doLoad(new Class<?>[] { config }, environment);
}

@ -428,13 +428,19 @@ content into your application; rather pick only the properties that you need.
spring.jmx.enabled=true # Expose MBeans from Spring
# RABBIT ({sc-spring-boot-autoconfigure}/amqp/RabbitProperties.{sc-ext}[RabbitProperties])
spring.rabbitmq.addresses= # connection addresses (e.g. myhost:9999,otherhost:1111)
spring.rabbitmq.dynamic=true # create an AmqpAdmin bean
spring.rabbitmq.host= # connection host
spring.rabbitmq.port= # connection port
spring.rabbitmq.addresses= # connection addresses (e.g. myhost:9999,otherhost:1111)
spring.rabbitmq.username= # login user
spring.rabbitmq.password= # login password
spring.rabbitmq.virtual-host=
spring.rabbitmq.dynamic=
spring.rabbitmq.requested-heartbeat= # requested heartbeat timeout, in seconds; zero for none
spring.rabbitmq.ssl.enabled=false # enable SSL support
spring.rabbitmq.ssl.key-store= # path to the key store that holds the SSL certificate
spring.rabbitmq.ssl.key-store-password= # password used to access the key store
spring.rabbitmq.ssl.trust-store= # trust store that holds SSL certificates
spring.rabbitmq.ssl.trust-store-password= # password used to access the trust store
spring.rabbitmq.username= # login user
spring.rabbitmq.virtual-host= # virtual host to use when connecting to the broker
# REDIS ({sc-spring-boot-autoconfigure}/redis/RedisProperties.{sc-ext}[RedisProperties])
spring.redis.database= # database name

Loading…
Cancel
Save