From 726991c14442c70b6eb44e6ce8c2233fc7a6e850 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 4 Jun 2014 20:15:35 +0200 Subject: [PATCH] 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 --- .../jms/hornetq/HornetQAutoConfiguration.java | 25 +++---- .../jms/hornetq/HornetQProperties.java | 2 +- .../HornetQAutoConfigurationTests.java | 66 ++++++++++++------- .../appendix-application-properties.adoc | 2 +- .../main/asciidoc/spring-boot-features.adoc | 15 +++-- 5 files changed, 68 insertions(+), 42 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQAutoConfiguration.java index e1e524dc3e..ce64f95cb4 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQAutoConfiguration.java @@ -42,8 +42,8 @@ import org.hornetq.jms.server.embedded.EmbeddedJMS; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureBefore; 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.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -53,12 +53,13 @@ import org.springframework.util.ClassUtils; /** * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration - * Auto-configuration} to integrate with an HornetQ broker. Connect by default to a broker - * available on the local machine with the default settings. If the necessary classes are - * present, the broker can also be embedded in the application itself. + * Auto-configuration} to integrate with an HornetQ broker. If the necessary + * classes are present, embed the broker in the application by default. Otherwise, + * connect to a broker available on the local machine with the default settings. * * @author Stephane Nicoll * @since 1.1.0 + * @see HornetQProperties */ @Configuration @AutoConfigureBefore(JmsAutoConfiguration.class) @@ -73,9 +74,9 @@ public class HornetQAutoConfiguration { /** * Create the {@link ConnectionFactory} to use if none is provided. If no - * {@linkplain HornetQProperties#getMode() mode} has been explicitly set, connect to - * the embedded server if it has been requested or to a broker available on the local - * machine with the default settings otherwise. + * {@linkplain HornetQProperties#getMode() mode} has been explicitly set, start an + * embedded server unless it has been explicitly disabled, connect to a broker + * available on the local machine with the default settings otherwise. */ @Bean @ConditionalOnMissingBean @@ -131,7 +132,7 @@ public class HornetQAutoConfiguration { */ @Configuration @ConditionalOnClass(name = EMBEDDED_JMS_CLASS) - @ConditionalOnProperty(prefix = "spring.hornetq.embedded", value = "enabled") + @ConditionalOnExpression("'${spring.hornetq.embedded.enabled:true}' == 'true'") static class EmbeddedServerConfiguration { @Autowired @@ -159,14 +160,14 @@ public class HornetQAutoConfiguration { org.hornetq.core.config.Configuration configuration, JMSConfiguration jmsConfiguration) { EmbeddedJMS server = new EmbeddedJMS(); - applyCustomizers(configuration); + customize(configuration); server.setConfiguration(configuration); server.setJmsConfiguration(jmsConfiguration); server.setRegistry(new HornetQNoOpBindingRegistry()); return server; } - private void applyCustomizers(org.hornetq.core.config.Configuration configuration) { + private void customize(org.hornetq.core.config.Configuration configuration) { if (this.configurationCustomizers != null) { AnnotationAwareOrderComparator.sort(this.configurationCustomizers); for (HornetQConfigurationCustomizer customizer : this.configurationCustomizers) { @@ -182,7 +183,7 @@ public class HornetQAutoConfiguration { addAll(configuration.getQueueConfigurations(), this.queuesConfiguration); addAll(configuration.getTopicConfigurations(), this.topicsConfiguration); addQueues(configuration, this.properties.getEmbedded().getQueues()); - addTopis(configuration, this.properties.getEmbedded().getTopics()); + addTopics(configuration, this.properties.getEmbedded().getTopics()); return configuration; } @@ -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) { configuration.getTopicConfigurations().add( new TopicConfigurationImpl(topic, "/topic/" + topic)); diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQProperties.java index f1dea8aa27..d13e9a201d 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQProperties.java @@ -70,7 +70,7 @@ public class HornetQProperties { */ public static class Embedded { - private boolean enabled; + private boolean enabled = true; private boolean persistent; diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQAutoConfigurationTests.java index 90d116abc9..cea134d494 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/hornetq/HornetQAutoConfigurationTests.java @@ -43,10 +43,6 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.springframework.beans.factory.annotation.Autowired; 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.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -93,7 +89,8 @@ public class HornetQAutoConfigurationTests { @Test 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"); HornetQConnectionFactory connectionFactory = this.context .getBean(HornetQConnectionFactory.class); @@ -102,8 +99,7 @@ public class HornetQAutoConfigurationTests { @Test public void embeddedConnectionFactory() { - load(EmptyConfiguration.class, "spring.hornetq.mode:embedded", - "spring.hornetq.embedded.enabled:true"); + load(EmptyConfiguration.class, "spring.hornetq.mode:embedded"); HornetQProperties properties = this.context.getBean(HornetQProperties.class); assertEquals(HornetQMode.EMBEDDED, properties.getMode()); @@ -121,26 +117,52 @@ public class HornetQAutoConfigurationTests { } @Test - public void nativeConnectionFactoryByDefault() { + public void embeddedConnectionFactoryByDefault() { // No mode is specified load(EmptyConfiguration.class); - HornetQConnectionFactory connectionFactory = this.context - .getBean(HornetQConnectionFactory.class); - assertNettyConnectionFactory(connectionFactory, "localhost", 5445); - } - @Test - public void embeddedConnectionFactoryIfEmbeddedServiceEnabled() { - // No mode enabled, embedded server required - load(EmptyConfiguration.class, "spring.hornetq.embedded.enabled:true"); + 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 + .getBean(HornetQConnectionFactory.class); + assertNettyConnectionFactory(connectionFactory, "localhost", 5445); + } + + @Test + public void embeddedConnectionFactorEvenIfEmbeddedServiceDisabled() { + // No mode is specified + load(EmptyConfiguration.class, + "spring.hornetq.mode:embedded", + "spring.hornetq.embedded.enabled:false"); + + assertEquals(0, this.context.getBeansOfType(EmbeddedJMS.class).size()); + + HornetQConnectionFactory connectionFactory = this.context + .getBean(HornetQConnectionFactory.class); + assertInVmConnectionFactory(connectionFactory); + } + + @Test public void embeddedServerWithDestinations() { - load(EmptyConfiguration.class, "spring.hornetq.embedded.enabled:true", + load(EmptyConfiguration.class, "spring.hornetq.embedded.queues=Queue1,Queue2", "spring.hornetq.embedded.topics=Topic1"); @@ -155,7 +177,7 @@ public class HornetQAutoConfigurationTests { @Test public void embeddedServerWithDestinationConfig() { - load(DestinationConfiguration.class, "spring.hornetq.embedded.enabled:true"); + load(DestinationConfiguration.class); DestinationChecker checker = new DestinationChecker(this.context); checker.checkQueue("sampleQueue", true); @@ -164,7 +186,7 @@ public class HornetQAutoConfigurationTests { @Test public void embeddedServiceWithCustomJmsConfiguration() { - load(CustomJmsConfiguration.class, "spring.hornetq.embedded.enabled:true", + load(CustomJmsConfiguration.class, "spring.hornetq.embedded.queues=Queue1,Queue2"); // Ignored with custom // config DestinationChecker checker = new DestinationChecker(this.context); @@ -176,7 +198,7 @@ public class HornetQAutoConfigurationTests { @Test public void embeddedServiceWithCustomHornetQConfiguration() { - load(CustomHornetQConfiguration.class, "spring.hornetq.embedded.enabled:true"); + load(CustomHornetQConfiguration.class); org.hornetq.core.config.Configuration configuration = this.context .getBean(org.hornetq.core.config.Configuration.class); assertEquals("customFooBar", configuration.getName()); @@ -187,7 +209,7 @@ public class HornetQAutoConfigurationTests { File dataFolder = this.folder.newFolder(); // 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.persistent:true", "spring.hornetq.embedded.dataDirectory:" + dataFolder.getAbsolutePath()); @@ -203,7 +225,7 @@ public class HornetQAutoConfigurationTests { this.context.close(); // Shutdown the broker // 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.persistent:true", "spring.hornetq.embedded.dataDirectory:" + dataFolder.getAbsolutePath()); diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 5c1c815a90..8905da74cb 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -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.queues= # comma separate queues 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]) spring.jms.pub-sub-domain= # false for queue (default), true for topic diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index e18733ccc3..7e6c575b6c 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -1702,11 +1702,14 @@ components require a `ConnectionFactory` to operate. ==== HornetQ support Spring Boot can auto-configure a `ConnectionFactory` when it detects that -HornetQ is available on the classpath. By default, a `ConnectionFactory` using -the `netty` transport protocol is configured, connecting to a broker running on -the local machine with the default settings. It is also possible to connect to -a running broker provided in the container or even embed the container in the -application if the necessary classes are present. +HornetQ is available on the classpath. If the broker is present, an embedded +broker is started and configured automatically unless the mode property has +been explicitly set. The supported modes are: `embedded` (to make explicit +that an embedded broker is required and should lead to an error if the broker +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 to connect to an existing HornetQ instance are provided, as well as the Spring @@ -1742,7 +1745,7 @@ names provided through configuration. ==== ActiveMQ support 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 is specified through configuration.