Commit 726991c1 authored by Stephane Nicoll's avatar Stephane Nicoll

Use an embed HornetQ broker by default

This commit changes the default behavior of the HornetQ auto
configuration. Prior to this commit, an embedded broker was only
started when it was requested explicitly by a configuration option.

This is inconsistent with the ActiveMQ support and boot favors the
easiest route. If the necessary classes are available, HornetQ is
embedded in the application by default.

Fixes gh-1029
parent d6718025
...@@ -42,8 +42,8 @@ import org.hornetq.jms.server.embedded.EmbeddedJMS; ...@@ -42,8 +42,8 @@ import org.hornetq.jms.server.embedded.EmbeddedJMS;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -53,12 +53,13 @@ import org.springframework.util.ClassUtils; ...@@ -53,12 +53,13 @@ import org.springframework.util.ClassUtils;
/** /**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} to integrate with an HornetQ broker. Connect by default to a broker * Auto-configuration} to integrate with an HornetQ broker. If the necessary
* available on the local machine with the default settings. If the necessary classes are * classes are present, embed the broker in the application by default. Otherwise,
* present, the broker can also be embedded in the application itself. * connect to a broker available on the local machine with the default settings.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.1.0 * @since 1.1.0
* @see HornetQProperties
*/ */
@Configuration @Configuration
@AutoConfigureBefore(JmsAutoConfiguration.class) @AutoConfigureBefore(JmsAutoConfiguration.class)
...@@ -73,9 +74,9 @@ public class HornetQAutoConfiguration { ...@@ -73,9 +74,9 @@ public class HornetQAutoConfiguration {
/** /**
* Create the {@link ConnectionFactory} to use if none is provided. If no * Create the {@link ConnectionFactory} to use if none is provided. If no
* {@linkplain HornetQProperties#getMode() mode} has been explicitly set, connect to * {@linkplain HornetQProperties#getMode() mode} has been explicitly set, start an
* the embedded server if it has been requested or to a broker available on the local * embedded server unless it has been explicitly disabled, connect to a broker
* machine with the default settings otherwise. * available on the local machine with the default settings otherwise.
*/ */
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
...@@ -131,7 +132,7 @@ public class HornetQAutoConfiguration { ...@@ -131,7 +132,7 @@ public class HornetQAutoConfiguration {
*/ */
@Configuration @Configuration
@ConditionalOnClass(name = EMBEDDED_JMS_CLASS) @ConditionalOnClass(name = EMBEDDED_JMS_CLASS)
@ConditionalOnProperty(prefix = "spring.hornetq.embedded", value = "enabled") @ConditionalOnExpression("'${spring.hornetq.embedded.enabled:true}' == 'true'")
static class EmbeddedServerConfiguration { static class EmbeddedServerConfiguration {
@Autowired @Autowired
...@@ -159,14 +160,14 @@ public class HornetQAutoConfiguration { ...@@ -159,14 +160,14 @@ public class HornetQAutoConfiguration {
org.hornetq.core.config.Configuration configuration, org.hornetq.core.config.Configuration configuration,
JMSConfiguration jmsConfiguration) { JMSConfiguration jmsConfiguration) {
EmbeddedJMS server = new EmbeddedJMS(); EmbeddedJMS server = new EmbeddedJMS();
applyCustomizers(configuration); customize(configuration);
server.setConfiguration(configuration); server.setConfiguration(configuration);
server.setJmsConfiguration(jmsConfiguration); server.setJmsConfiguration(jmsConfiguration);
server.setRegistry(new HornetQNoOpBindingRegistry()); server.setRegistry(new HornetQNoOpBindingRegistry());
return server; return server;
} }
private void applyCustomizers(org.hornetq.core.config.Configuration configuration) { private void customize(org.hornetq.core.config.Configuration configuration) {
if (this.configurationCustomizers != null) { if (this.configurationCustomizers != null) {
AnnotationAwareOrderComparator.sort(this.configurationCustomizers); AnnotationAwareOrderComparator.sort(this.configurationCustomizers);
for (HornetQConfigurationCustomizer customizer : this.configurationCustomizers) { for (HornetQConfigurationCustomizer customizer : this.configurationCustomizers) {
...@@ -182,7 +183,7 @@ public class HornetQAutoConfiguration { ...@@ -182,7 +183,7 @@ public class HornetQAutoConfiguration {
addAll(configuration.getQueueConfigurations(), this.queuesConfiguration); addAll(configuration.getQueueConfigurations(), this.queuesConfiguration);
addAll(configuration.getTopicConfigurations(), this.topicsConfiguration); addAll(configuration.getTopicConfigurations(), this.topicsConfiguration);
addQueues(configuration, this.properties.getEmbedded().getQueues()); addQueues(configuration, this.properties.getEmbedded().getQueues());
addTopis(configuration, this.properties.getEmbedded().getTopics()); addTopics(configuration, this.properties.getEmbedded().getTopics());
return configuration; return configuration;
} }
...@@ -201,7 +202,7 @@ public class HornetQAutoConfiguration { ...@@ -201,7 +202,7 @@ public class HornetQAutoConfiguration {
} }
} }
private void addTopis(JMSConfiguration configuration, String[] topics) { private void addTopics(JMSConfiguration configuration, String[] topics) {
for (String topic : topics) { for (String topic : topics) {
configuration.getTopicConfigurations().add( configuration.getTopicConfigurations().add(
new TopicConfigurationImpl(topic, "/topic/" + topic)); new TopicConfigurationImpl(topic, "/topic/" + topic));
......
...@@ -70,7 +70,7 @@ public class HornetQProperties { ...@@ -70,7 +70,7 @@ public class HornetQProperties {
*/ */
public static class Embedded { public static class Embedded {
private boolean enabled; private boolean enabled = true;
private boolean persistent; private boolean persistent;
......
...@@ -43,10 +43,6 @@ import org.junit.Test; ...@@ -43,10 +43,6 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.hornetq.HornetQAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.hornetq.HornetQConfigurationCustomizer;
import org.springframework.boot.autoconfigure.jms.hornetq.HornetQMode;
import org.springframework.boot.autoconfigure.jms.hornetq.HornetQProperties;
import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
...@@ -93,7 +89,8 @@ public class HornetQAutoConfigurationTests { ...@@ -93,7 +89,8 @@ public class HornetQAutoConfigurationTests {
@Test @Test
public void nativeConnectionFactoryCustomHost() { public void nativeConnectionFactoryCustomHost() {
load(EmptyConfiguration.class, "spring.hornetq.host:192.168.1.144", load(EmptyConfiguration.class, "spring.hornetq.mode:native",
"spring.hornetq.host:192.168.1.144",
"spring.hornetq.port:9876"); "spring.hornetq.port:9876");
HornetQConnectionFactory connectionFactory = this.context HornetQConnectionFactory connectionFactory = this.context
.getBean(HornetQConnectionFactory.class); .getBean(HornetQConnectionFactory.class);
...@@ -102,8 +99,7 @@ public class HornetQAutoConfigurationTests { ...@@ -102,8 +99,7 @@ public class HornetQAutoConfigurationTests {
@Test @Test
public void embeddedConnectionFactory() { public void embeddedConnectionFactory() {
load(EmptyConfiguration.class, "spring.hornetq.mode:embedded", load(EmptyConfiguration.class, "spring.hornetq.mode:embedded");
"spring.hornetq.embedded.enabled:true");
HornetQProperties properties = this.context.getBean(HornetQProperties.class); HornetQProperties properties = this.context.getBean(HornetQProperties.class);
assertEquals(HornetQMode.EMBEDDED, properties.getMode()); assertEquals(HornetQMode.EMBEDDED, properties.getMode());
...@@ -121,26 +117,52 @@ public class HornetQAutoConfigurationTests { ...@@ -121,26 +117,52 @@ public class HornetQAutoConfigurationTests {
} }
@Test @Test
public void nativeConnectionFactoryByDefault() { public void embeddedConnectionFactoryByDefault() {
// No mode is specified // No mode is specified
load(EmptyConfiguration.class); load(EmptyConfiguration.class);
assertEquals(1, this.context.getBeansOfType(EmbeddedJMS.class).size());
org.hornetq.core.config.Configuration configuration = this.context
.getBean(org.hornetq.core.config.Configuration.class);
assertFalse("Persistence disabled by default",
configuration.isPersistenceEnabled());
assertFalse("Security disabled by default", configuration.isSecurityEnabled());
HornetQConnectionFactory connectionFactory = this.context
.getBean(HornetQConnectionFactory.class);
assertInVmConnectionFactory(connectionFactory);
}
@Test
public void nativeConnectionFactoryIfEmbeddedServiceDisabledExplicitly() {
// No mode is specified
load(EmptyConfiguration.class, "spring.hornetq.embedded.enabled:false");
assertEquals(0, this.context.getBeansOfType(EmbeddedJMS.class).size());
HornetQConnectionFactory connectionFactory = this.context HornetQConnectionFactory connectionFactory = this.context
.getBean(HornetQConnectionFactory.class); .getBean(HornetQConnectionFactory.class);
assertNettyConnectionFactory(connectionFactory, "localhost", 5445); assertNettyConnectionFactory(connectionFactory, "localhost", 5445);
} }
@Test @Test
public void embeddedConnectionFactoryIfEmbeddedServiceEnabled() { public void embeddedConnectionFactorEvenIfEmbeddedServiceDisabled() {
// No mode enabled, embedded server required // No mode is specified
load(EmptyConfiguration.class, "spring.hornetq.embedded.enabled:true"); load(EmptyConfiguration.class,
"spring.hornetq.mode:embedded",
"spring.hornetq.embedded.enabled:false");
assertEquals(0, this.context.getBeansOfType(EmbeddedJMS.class).size());
HornetQConnectionFactory connectionFactory = this.context HornetQConnectionFactory connectionFactory = this.context
.getBean(HornetQConnectionFactory.class); .getBean(HornetQConnectionFactory.class);
assertInVmConnectionFactory(connectionFactory); assertInVmConnectionFactory(connectionFactory);
} }
@Test @Test
public void embeddedServerWithDestinations() { public void embeddedServerWithDestinations() {
load(EmptyConfiguration.class, "spring.hornetq.embedded.enabled:true", load(EmptyConfiguration.class,
"spring.hornetq.embedded.queues=Queue1,Queue2", "spring.hornetq.embedded.queues=Queue1,Queue2",
"spring.hornetq.embedded.topics=Topic1"); "spring.hornetq.embedded.topics=Topic1");
...@@ -155,7 +177,7 @@ public class HornetQAutoConfigurationTests { ...@@ -155,7 +177,7 @@ public class HornetQAutoConfigurationTests {
@Test @Test
public void embeddedServerWithDestinationConfig() { public void embeddedServerWithDestinationConfig() {
load(DestinationConfiguration.class, "spring.hornetq.embedded.enabled:true"); load(DestinationConfiguration.class);
DestinationChecker checker = new DestinationChecker(this.context); DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("sampleQueue", true); checker.checkQueue("sampleQueue", true);
...@@ -164,7 +186,7 @@ public class HornetQAutoConfigurationTests { ...@@ -164,7 +186,7 @@ public class HornetQAutoConfigurationTests {
@Test @Test
public void embeddedServiceWithCustomJmsConfiguration() { public void embeddedServiceWithCustomJmsConfiguration() {
load(CustomJmsConfiguration.class, "spring.hornetq.embedded.enabled:true", load(CustomJmsConfiguration.class,
"spring.hornetq.embedded.queues=Queue1,Queue2"); // Ignored with custom "spring.hornetq.embedded.queues=Queue1,Queue2"); // Ignored with custom
// config // config
DestinationChecker checker = new DestinationChecker(this.context); DestinationChecker checker = new DestinationChecker(this.context);
...@@ -176,7 +198,7 @@ public class HornetQAutoConfigurationTests { ...@@ -176,7 +198,7 @@ public class HornetQAutoConfigurationTests {
@Test @Test
public void embeddedServiceWithCustomHornetQConfiguration() { public void embeddedServiceWithCustomHornetQConfiguration() {
load(CustomHornetQConfiguration.class, "spring.hornetq.embedded.enabled:true"); load(CustomHornetQConfiguration.class);
org.hornetq.core.config.Configuration configuration = this.context org.hornetq.core.config.Configuration configuration = this.context
.getBean(org.hornetq.core.config.Configuration.class); .getBean(org.hornetq.core.config.Configuration.class);
assertEquals("customFooBar", configuration.getName()); assertEquals("customFooBar", configuration.getName());
...@@ -187,7 +209,7 @@ public class HornetQAutoConfigurationTests { ...@@ -187,7 +209,7 @@ public class HornetQAutoConfigurationTests {
File dataFolder = this.folder.newFolder(); File dataFolder = this.folder.newFolder();
// Start the server and post a message to some queue // Start the server and post a message to some queue
load(EmptyConfiguration.class, "spring.hornetq.embedded.enabled:true", load(EmptyConfiguration.class,
"spring.hornetq.embedded.queues=TestQueue", "spring.hornetq.embedded.queues=TestQueue",
"spring.hornetq.embedded.persistent:true", "spring.hornetq.embedded.persistent:true",
"spring.hornetq.embedded.dataDirectory:" + dataFolder.getAbsolutePath()); "spring.hornetq.embedded.dataDirectory:" + dataFolder.getAbsolutePath());
...@@ -203,7 +225,7 @@ public class HornetQAutoConfigurationTests { ...@@ -203,7 +225,7 @@ public class HornetQAutoConfigurationTests {
this.context.close(); // Shutdown the broker this.context.close(); // Shutdown the broker
// Start the server again and check if our message is still here // Start the server again and check if our message is still here
load(EmptyConfiguration.class, "spring.hornetq.embedded.enabled:true", load(EmptyConfiguration.class,
"spring.hornetq.embedded.queues=TestQueue", "spring.hornetq.embedded.queues=TestQueue",
"spring.hornetq.embedded.persistent:true", "spring.hornetq.embedded.persistent:true",
"spring.hornetq.embedded.dataDirectory:" + dataFolder.getAbsolutePath()); "spring.hornetq.embedded.dataDirectory:" + dataFolder.getAbsolutePath());
......
...@@ -256,7 +256,7 @@ content into your application; rather pick only the properties that you need. ...@@ -256,7 +256,7 @@ content into your application; rather pick only the properties that you need.
spring.hornetq.embedded.data-directory= # location of data content (when persistence is enabled) spring.hornetq.embedded.data-directory= # location of data content (when persistence is enabled)
spring.hornetq.embedded.queues= # comma separate queues to create on startup spring.hornetq.embedded.queues= # comma separate queues to create on startup
spring.hornetq.embedded.topics= # comma separate topics to create on startup spring.hornetq.embedded.topics= # comma separate topics to create on startup
spring.hornetq.embedded.cluster-password = # customer password (randomly generated by default) spring.hornetq.embedded.cluster-password= # customer password (randomly generated by default)
# JMS ({sc-spring-boot-autoconfigure}/jms/JmsTemplateProperties.{sc-ext}[JmsTemplateProperties]) # JMS ({sc-spring-boot-autoconfigure}/jms/JmsTemplateProperties.{sc-ext}[JmsTemplateProperties])
spring.jms.pub-sub-domain= # false for queue (default), true for topic spring.jms.pub-sub-domain= # false for queue (default), true for topic
......
...@@ -1702,11 +1702,14 @@ components require a `ConnectionFactory` to operate. ...@@ -1702,11 +1702,14 @@ components require a `ConnectionFactory` to operate.
==== HornetQ support ==== HornetQ support
Spring Boot can auto-configure a `ConnectionFactory` when it detects that Spring Boot can auto-configure a `ConnectionFactory` when it detects that
HornetQ is available on the classpath. By default, a `ConnectionFactory` using HornetQ is available on the classpath. If the broker is present, an embedded
the `netty` transport protocol is configured, connecting to a broker running on broker is started and configured automatically unless the mode property has
the local machine with the default settings. It is also possible to connect to been explicitly set. The supported modes are: `embedded` (to make explicit
a running broker provided in the container or even embed the container in the that an embedded broker is required and should lead to an error if the broker
application if the necessary classes are present. is not available in the classpath), and `native` to connect to a broker
using the the `netty` transport protocol. When the latter is configured, boot
configures a `ConnectionFactory` connecting to a broker running on the local
machine with the default settings.
NOTE: if you are using `spring-boot-starter-hornetq` the necessary dependencies NOTE: if you are using `spring-boot-starter-hornetq` the necessary dependencies
to connect to an existing HornetQ instance are provided, as well as the Spring to connect to an existing HornetQ instance are provided, as well as the Spring
...@@ -1742,7 +1745,7 @@ names provided through configuration. ...@@ -1742,7 +1745,7 @@ names provided through configuration.
==== ActiveMQ support ==== ActiveMQ support
Spring Boot can also configure a `ConnectionFactory` when it detects that Spring Boot can also configure a `ConnectionFactory` when it detects that
ActiveMQ is available on the classpath. If the complete broker is available, ActiveMQ is available on the classpath. If the broker is present,
an embedded broker is started and configured automatically if no broker URL an embedded broker is started and configured automatically if no broker URL
is specified through configuration. is specified through configuration.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment