Commit 5a69bb92 authored by Stephane Nicoll's avatar Stephane Nicoll Committed by Phillip Webb

Add HornetQ JMS support

Provide auto-configuration support for HornetQ JMS broker, along with
an additional starter POM.

The connection factory connects to a broker available on the local
machine by default. A configuration switch allows to enable an embedded
mode that starts HornetQ as part of the application.

In such a mode, the spring.hornetq.embedded.* properties provide
additional options to configure the embedded broker. In particular,
message persistence and data directory locations can be specified. It is
also possible to define the queue(s) and topic(s) to create on startup.

Fixes: gh-765
parent 67beba94
......@@ -111,6 +111,16 @@
<artifactId>hibernate-jpa-2.0-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms-client</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms-server</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
......
/*
* Copyright 2012-2014 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.jms;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.jms.ConnectionFactory;
import org.hornetq.api.core.TransportConfiguration;
import org.hornetq.api.core.client.HornetQClient;
import org.hornetq.api.core.client.ServerLocator;
import org.hornetq.api.jms.HornetQJMSClient;
import org.hornetq.api.jms.JMSFactoryType;
import org.hornetq.core.remoting.impl.invm.InVMConnectorFactory;
import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
import org.hornetq.core.remoting.impl.netty.TransportConstants;
import org.hornetq.jms.client.HornetQConnectionFactory;
import org.hornetq.jms.server.config.JMSConfiguration;
import org.hornetq.jms.server.config.JMSQueueConfiguration;
import org.hornetq.jms.server.config.TopicConfiguration;
import org.hornetq.jms.server.config.impl.JMSConfigurationImpl;
import org.hornetq.jms.server.config.impl.JMSQueueConfigurationImpl;
import org.hornetq.jms.server.config.impl.TopicConfigurationImpl;
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.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
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.
*
* @author Stephane Nicoll
* @since 1.1.0
*/
@Configuration
@AutoConfigureBefore(JmsAutoConfiguration.class)
@ConditionalOnClass({ ConnectionFactory.class, HornetQJMSClient.class })
@EnableConfigurationProperties(HornetQProperties.class)
public class HornetQAutoConfiguration {
private static final String EMBEDDED_JMS_CLASS = "org.hornetq.jms.server.embedded.EmbeddedJMS";
@Autowired
private HornetQProperties properties;
/**
* 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.
*/
@Bean
@ConditionalOnMissingBean
public ConnectionFactory jmsConnectionFactory() {
HornetQMode mode = this.properties.getMode();
if (mode == null) {
mode = deduceMode();
}
if (mode == HornetQMode.EMBEDDED) {
return createEmbeddedConnectionFactory();
}
return createNativeConnectionFactory();
}
/**
* Deduce the {@link HornetQMode} to use if none has been set.
*/
private HornetQMode deduceMode() {
if (this.properties.getEmbedded().isEnabled()
&& ClassUtils.isPresent(EMBEDDED_JMS_CLASS, null)) {
return HornetQMode.EMBEDDED;
}
return HornetQMode.NATIVE;
}
private ConnectionFactory createEmbeddedConnectionFactory() {
try {
TransportConfiguration transportConfiguration = new TransportConfiguration(
InVMConnectorFactory.class.getName());
ServerLocator serviceLocator = HornetQClient
.createServerLocatorWithoutHA(transportConfiguration);
return new HornetQConnectionFactory(serviceLocator);
}
catch (NoClassDefFoundError ex) {
throw new IllegalStateException("Unable to create InVM "
+ "HornetQ connection, ensure that hornet-jms-server.jar "
+ "is in the classpath", ex);
}
}
private ConnectionFactory createNativeConnectionFactory() {
Map<String, Object> params = new HashMap<String, Object>();
params.put(TransportConstants.HOST_PROP_NAME, this.properties.getHost());
params.put(TransportConstants.PORT_PROP_NAME, this.properties.getPort());
TransportConfiguration transportConfiguration = new TransportConfiguration(
NettyConnectorFactory.class.getName(), params);
return HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF,
transportConfiguration);
}
/**
* Configuration used to create the embedded HornetQ server.
*/
@Configuration
@ConditionalOnClass(name = EMBEDDED_JMS_CLASS)
@ConditionalOnProperty(prefix = "spring.hornetq.embedded", value = "enabled")
static class EmbeddedServerConfiguration {
@Autowired
private HornetQProperties properties;
@Autowired(required = false)
private List<HornetQConfigurationCustomizer> configurationCustomizers;
@Autowired(required = false)
private List<JMSQueueConfiguration> queuesConfiguration;
@Autowired(required = false)
private List<TopicConfiguration> topicsConfiguration;
@Bean
@ConditionalOnMissingBean
public org.hornetq.core.config.Configuration hornetQConfiguration() {
return new HornetQEmbeddedConfigurationFactory(this.properties)
.createConfiguration();
}
@Bean(initMethod = "start", destroyMethod = "stop")
@ConditionalOnMissingBean
public EmbeddedJMS hornetQServer(
org.hornetq.core.config.Configuration configuration,
JMSConfiguration jmsConfiguration) {
EmbeddedJMS server = new EmbeddedJMS();
applyCustomizers(configuration);
server.setConfiguration(configuration);
server.setJmsConfiguration(jmsConfiguration);
server.setRegistry(new HornetQNoOpBindingRegistry());
return server;
}
private void applyCustomizers(org.hornetq.core.config.Configuration configuration) {
if (this.configurationCustomizers != null) {
AnnotationAwareOrderComparator.sort(this.configurationCustomizers);
for (HornetQConfigurationCustomizer customizer : this.configurationCustomizers) {
customizer.customize(configuration);
}
}
}
@Bean
@ConditionalOnMissingBean
public JMSConfiguration hornetQJmsConfiguration() {
JMSConfiguration configuration = new JMSConfigurationImpl();
addAll(configuration.getQueueConfigurations(), this.queuesConfiguration);
addAll(configuration.getTopicConfigurations(), this.topicsConfiguration);
addQueues(configuration, this.properties.getEmbedded().getQueues());
addTopis(configuration, this.properties.getEmbedded().getTopics());
return configuration;
}
private <T> void addAll(List<T> list, Collection<? extends T> items) {
if (items != null) {
list.addAll(items);
}
}
private void addQueues(JMSConfiguration configuration, String[] queues) {
boolean persistent = this.properties.getEmbedded().isPersistent();
for (String queue : queues) {
configuration.getQueueConfigurations().add(
new JMSQueueConfigurationImpl(queue, null, persistent, "/queue/"
+ queue));
}
}
private void addTopis(JMSConfiguration configuration, String[] topics) {
for (String topic : topics) {
configuration.getTopicConfigurations().add(
new TopicConfigurationImpl(topic, "/topic/" + topic));
}
}
}
}
/*
* Copyright 2012-2014 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.jms;
import org.hornetq.core.config.Configuration;
import org.hornetq.jms.server.embedded.EmbeddedJMS;
/**
* Callback interface that can be implemented by beans wishing to customize the HornetQ
* JMS server {@link Configuration} before it is used by an auto-configured
* {@link EmbeddedJMS} instance.
*
* @author Phillip Webb
* @since 1.1.0
* @see HornetQAutoConfiguration
*/
public interface HornetQConfigurationCustomizer {
/**
* Customize the configuration.
* @param configuration the configuration to customize
*/
void customize(Configuration configuration);
}
/*
* Copyright 2012-2014 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.jms;
import java.io.File;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hornetq.api.core.TransportConfiguration;
import org.hornetq.core.config.Configuration;
import org.hornetq.core.config.impl.ConfigurationImpl;
import org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory;
import org.hornetq.core.server.JournalType;
import org.springframework.boot.autoconfigure.jms.HornetQProperties.Embedded;
/**
* Factory class to create a HornetQ {@link Configuration} from {@link HornetQProperties}.
*
* @author Stephane Nicol
* @author Phillip Webb
* @since 1.1.0
*/
class HornetQEmbeddedConfigurationFactory {
private Log logger = LogFactory.getLog(HornetQAutoConfiguration.class);
private final Embedded properties;
public HornetQEmbeddedConfigurationFactory(HornetQProperties properties) {
this.properties = properties.getEmbedded();
}
public Configuration createConfiguration() {
ConfigurationImpl configuration = new ConfigurationImpl();
configuration.setSecurityEnabled(false);
configuration.setPersistenceEnabled(this.properties.isPersistent());
String dataDir = getDataDir();
// HORNETQ-1302
configuration.setJournalDirectory(dataDir + "/journal");
if (this.properties.isPersistent()) {
configuration.setJournalType(JournalType.NIO);
configuration.setLargeMessagesDirectory(dataDir + "/largemessages");
configuration.setBindingsDirectory(dataDir + "/bindings");
configuration.setPagingDirectory(dataDir + "/paging");
}
TransportConfiguration transportConfiguration = new TransportConfiguration(
InVMAcceptorFactory.class.getName());
configuration.getAcceptorConfigurations().add(transportConfiguration);
// HORNETQ-1143
if (this.properties.isDefaultClusterPassword()) {
this.logger.debug("Using default HornetQ cluster password: "
+ this.properties.getClusterPassword());
}
configuration.setClusterPassword(this.properties.getClusterPassword());
return configuration;
}
private String getDataDir() {
if (this.properties.getDataDirectory() != null) {
return this.properties.getDataDirectory();
}
String tempDirectory = System.getProperty("java.io.tmpdir");
return new File(tempDirectory, "hornetq-data").getAbsolutePath();
}
}
/*
* Copyright 2012-2014 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.jms;
/**
* Define the mode in which HornetQ can operate.
*
* @author Stephane Nicoll
* @since 1.1.0
*/
public enum HornetQMode {
/**
* Connect to a broker using the native HornetQ protocol (i.e. netty).
*/
NATIVE,
/**
* Embed (i.e. start) the broker in the application.
*/
EMBEDDED
}
/*
* Copyright 2012-2014 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.jms;
import org.hornetq.spi.core.naming.BindingRegistry;
/**
* A no-op implementation of the {@link org.hornetq.spi.core.naming.BindingRegistry}.
*
* @author Stephane Nicoll
* @since 1.1.0
*/
public class HornetQNoOpBindingRegistry implements BindingRegistry {
@Override
public Object lookup(String name) {
// This callback is used to check if an entry is present in the context before
// creating a queue on the fly. This is actually never used to try to fetch a
// destination that is unknown.
return null;
}
@Override
public boolean bind(String name, Object obj) {
// This callback is used bind a Destination created on the fly by the embedded
// broker using the JNDI name that was specified in the configuration. This does
// not look very useful since it's used nowhere. It could be interesting to
// autowire a destination to use it but the wiring is a bit "asynchronous" so
// better not provide that feature at all.
return false;
}
@Override
public void unbind(String name) {
}
@Override
public void close() {
}
@Override
public Object getContext() {
return this;
}
@Override
public void setContext(Object ctx) {
}
}
/*
* Copyright 2012-2014 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.jms;
import java.util.UUID;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for HornetQ
*
* @author Stephane Nicoll
* @since 1.1.0
*/
@ConfigurationProperties(prefix = "spring.hornetq")
public class HornetQProperties {
private HornetQMode mode;
private String host = "localhost";
private int port = 5445;
private final Embedded embedded = new Embedded();
public HornetQMode getMode() {
return this.mode;
}
public void setMode(HornetQMode mode) {
this.mode = mode;
}
public String getHost() {
return this.host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return this.port;
}
public void setPort(int port) {
this.port = port;
}
public Embedded getEmbedded() {
return this.embedded;
}
/**
* Configuration for an embedded HornetQ server.
*/
public static class Embedded {
private boolean enabled;
private boolean persistent;
private String dataDirectory;
private String[] queues = new String[0];
private String[] topics = new String[0];
private String clusterPassword = UUID.randomUUID().toString();
private boolean defaultClusterPassword = true;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isPersistent() {
return this.persistent;
}
public void setPersistent(boolean persistent) {
this.persistent = persistent;
}
public String getDataDirectory() {
return this.dataDirectory;
}
public void setDataDirectory(String dataDirectory) {
this.dataDirectory = dataDirectory;
}
public String[] getQueues() {
return this.queues;
}
public void setQueues(String[] queues) {
this.queues = queues;
}
public String[] getTopics() {
return this.topics;
}
public void setTopics(String[] topics) {
this.topics = topics;
}
public String getClusterPassword() {
return this.clusterPassword;
}
public void setClusterPassword(String clusterPassword) {
this.clusterPassword = clusterPassword;
this.defaultClusterPassword = false;
}
public boolean isDefaultClusterPassword() {
return this.defaultClusterPassword;
}
}
}
......@@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jms;
import javax.jms.ConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
......@@ -37,6 +38,7 @@ import org.springframework.jms.core.JmsTemplate;
@ConditionalOnClass(JmsTemplate.class)
@ConditionalOnBean(ConnectionFactory.class)
@EnableConfigurationProperties(JmsProperties.class)
@AutoConfigureAfter({ HornetQAutoConfiguration.class, ActiveMQAutoConfiguration.class })
public class JmsAutoConfiguration {
@Autowired
......
......@@ -19,6 +19,7 @@ org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.HornetQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
......
......@@ -30,6 +30,7 @@ import static org.junit.Assert.assertEquals;
public class ActiveMQPropertiesTests {
private final ActiveMQProperties properties = new ActiveMQProperties();
private final StandardEnvironment environment = new StandardEnvironment();
@Test
......
/*
* Copyright 2012-2014 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.jms;
import org.hornetq.core.config.Configuration;
import org.hornetq.core.server.JournalType;
import org.junit.Test;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link HornetQEmbeddedConfigurationFactory}.
*
* @author Stephane Nicol
* @author Phillip Webb
*/
public class HornetQEmbeddedConfigurationFactoryTests {
@Test
public void defaultDataDir() {
HornetQProperties properties = new HornetQProperties();
properties.getEmbedded().setPersistent(true);
Configuration configuration = new HornetQEmbeddedConfigurationFactory(properties)
.createConfiguration();
assertThat(configuration.getJournalDirectory(),
startsWith(System.getProperty("java.io.tmpdir")));
assertThat(configuration.getJournalDirectory(), endsWith("/journal"));
}
@Test
public void persistenceSetup() {
HornetQProperties properties = new HornetQProperties();
properties.getEmbedded().setPersistent(true);
Configuration configuration = new HornetQEmbeddedConfigurationFactory(properties)
.createConfiguration();
assertThat(configuration.isPersistenceEnabled(), equalTo(true));
assertThat(configuration.getJournalType(), equalTo(JournalType.NIO));
}
@Test
public void generatedClusterPassoword() throws Exception {
HornetQProperties properties = new HornetQProperties();
Configuration configuration = new HornetQEmbeddedConfigurationFactory(properties)
.createConfiguration();
assertThat(configuration.getClusterPassword().length(), equalTo(36));
}
@Test
public void specificClusterPassoword() throws Exception {
HornetQProperties properties = new HornetQProperties();
properties.getEmbedded().setClusterPassword("password");
Configuration configuration = new HornetQEmbeddedConfigurationFactory(properties)
.createConfiguration();
assertThat(configuration.getClusterPassword(), equalTo("password"));
}
}
......@@ -68,6 +68,7 @@
<hikaricp.version>1.3.8</hikaricp.version>
<httpclient.version>4.3.3</httpclient.version>
<httpasyncclient.version>4.0.1</httpasyncclient.version>
<hornetq.version>2.4.1.Final</hornetq.version>
<hsqldb.version>2.3.2</hsqldb.version>
<jackson.version>2.3.3</jackson.version>
<javassist.version>3.18.1-GA</javassist.version> <!-- Same as Hibernate -->
......@@ -212,6 +213,11 @@
<artifactId>spring-boot-starter-groovy-templates</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hornetq</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
......@@ -714,6 +720,16 @@
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>${hibernate-jpa-api.version}</version>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms-server</artifactId>
<version>${hornetq.version}</version>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms-client</artifactId>
<version>${hornetq.version}</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
......
......@@ -242,6 +242,17 @@ content into your application; rather pick only the properties that you need.
spring.activemq.in-memory=true # broker kind to create if no broker-url is specified
spring.activemq.pooled=false
# HornetQ ({sc-spring-boot-autoconfigure}/jms/HornetQProperties.{sc-ext}[HornetQProperties])
spring.hornetq.mode= # connection mode (native, embedded)
spring.hornetq.host=localhost # hornetQ host (native mode)
spring.hornetq.port=5445 # hornetQ port (native mode)
spring.hornetq.embedded.enabled=true # if the embedded server is enabled (needs hornetq-jms-server.jar)
spring.hornetq.embedded.persistent=false # message persistence
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)
# JMS ({sc-spring-boot-autoconfigure}/jms/JmsTemplateProperties.{sc-ext}[JmsTemplateProperties])
spring.jms.pub-sub-domain= # false for queue (default), true for topic
......
......@@ -53,6 +53,12 @@ The following auto-configuration classes are from the `spring-boot-autoconfigure
|{sc-spring-boot-autoconfigure}/web/HttpMessageConvertersAutoConfiguration.{sc-ext}[HttpMessageConvertersAutoConfiguration]
|{dc-spring-boot-autoconfigure}/web/HttpMessageConvertersAutoConfiguration.{dc-ext}[javadoc]
|{sc-spring-boot-autoconfigure}/jms/ActiveMQAutoConfiguration.{sc-ext}[ActiveMQAutoConfiguration]
|{dc-spring-boot-autoconfigure}/jms/ActiveMQAutoConfiguration.{dc-ext}[javadoc]
|{sc-spring-boot-autoconfigure}/jms/HornetQAutoConfiguration.{sc-ext}[HornetQAutoConfiguration]
|{dc-spring-boot-autoconfigure}/jms/HornetQAutoConfiguration.{dc-ext}[javadoc]
|{sc-spring-boot-autoconfigure}/jms/JmsTemplateAutoConfiguration.{sc-ext}[JmsTemplateAutoConfiguration]
|{dc-spring-boot-autoconfigure}/jms/JmsTemplateAutoConfiguration.{dc-ext}[javadoc]
......
......@@ -245,6 +245,9 @@ and Hibernate.
|`spring-boot-starter-groovy-templates`
|Support for the Groovy templating engine
|`spring-boot-starter-hornetq`
|Support for ``Java Message Service API'' via HornetQ.
|`spring-boot-starter-integration`
|Support for common `spring-integration` modules.
......
......@@ -34,6 +34,7 @@
<module>spring-boot-sample-data-rest</module>
<module>spring-boot-sample-data-solr</module>
<module>spring-boot-sample-flyway</module>
<module>spring-boot-sample-hornetq</module>
<module>spring-boot-sample-integration</module>
<module>spring-boot-sample-jetty</module>
<module>spring-boot-sample-liquibase</module>
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-samples</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-hornetq</artifactId>
<name>Spring Boot HornetQ Sample</name>
<description>Spring Boot HornetQ Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hornetq</artifactId>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
/*
* Copyright 2012-2013 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 sample.hornetq;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class SampleHornetQApplication {
@Autowired
private ConnectionFactory connectionFactory;
@Bean
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationBeanPostProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
@Bean
public DefaultMessageListenerContainer messageListener() {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(this.connectionFactory);
container.setDestinationName("testQueue");
container.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
System.out.println(message.getBody(Object.class));
}
catch (JMSException ex) {
ex.printStackTrace();
}
}
});
return container;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleHornetQApplication.class, args);
}
}
/*
* Copyright 2012-2013 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 sample.hornetq;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class Sender {
@Autowired
private JmsTemplate jmsTemplate;
@Scheduled(fixedDelay = 1000L)
public void send() {
this.jmsTemplate.convertAndSend("testQueue", "Hello");
}
}
spring.hornetq.mode=embedded
spring.hornetq.embedded.enabled=true
spring.hornetq.embedded.queues=testQueue,anotherQueue
......@@ -31,6 +31,7 @@
<module>spring-boot-starter-data-solr</module>
<module>spring-boot-starter-freemarker</module>
<module>spring-boot-starter-groovy-templates</module>
<module>spring-boot-starter-hornetq</module>
<module>spring-boot-starter-integration</module>
<module>spring-boot-starter-jdbc</module>
<module>spring-boot-starter-jetty</module>
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-starter-hornetq</artifactId>
<name>Spring Boot HornetQ Starter</name>
<description>Spring Boot HornetQ Starter</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms-client</artifactId>
</dependency>
</dependencies>
</project>
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