Merge pull request #3246 from eddumelendez/gh-3154

* gh-3154:
  Document Apache Artemis support
  Add Apache Artemis Starter POM
  Add Apache Artemis support
pull/3243/merge
Phillip Webb 10 years ago
commit a0dde9f17d

@ -130,6 +130,16 @@
<artifactId>activemq-pool</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-jms-client</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-jms-server</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>

@ -0,0 +1,53 @@
/*
* 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.
* 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.artemis;
import javax.jms.ConnectionFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
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.jms.JmsAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* {@link EnableAutoConfiguration Auto-configuration} to integrate with an Artemis 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 Eddú Meléndez
* @since 1.3.0
* @see ArtemisProperties
*/
@Configuration
@AutoConfigureBefore(JmsAutoConfiguration.class)
@AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class })
@ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class })
@ConditionalOnMissingBean(ConnectionFactory.class)
@EnableConfigurationProperties(ArtemisProperties.class)
@Import({ ArtemisXAConnectionFactoryConfiguration.class,
ArtemisConnectionFactoryConfiguration.class })
public class ArtemisAutoConfiguration {
}

@ -0,0 +1,40 @@
/*
* 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.
* 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.artemis;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
/**
* Callback interface that can be implemented by beans wishing to customize the Artemis
* JMS server {@link Configuration} before it is used by an auto-configured
* {@link EmbeddedJMS} instance.
*
* @author Eddú Meléndez
* @author Phillip Webb
* @since 1.3.0
* @see ArtemisAutoConfiguration
*/
public interface ArtemisConfigurationCustomizer {
/**
* Customize the configuration.
* @param configuration the configuration to customize
*/
void customize(Configuration configuration);
}

@ -0,0 +1,44 @@
/*
* 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.
* 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.artemis;
import javax.jms.ConnectionFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration for Artemis {@link ConnectionFactory}.
*
* @author Eddú Meléndez
* @author Phillip Webb
*/
@Configuration
@ConditionalOnMissingBean(ConnectionFactory.class)
class ArtemisConnectionFactoryConfiguration {
@Bean
public ConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory,
ArtemisProperties properties) {
return new ArtemisConnectionFactoryFactory(beanFactory, properties)
.createConnectionFactory(ActiveMQConnectionFactory.class);
}
}

@ -0,0 +1,135 @@
/*
* 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.
* 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.artemis;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
import org.apache.activemq.artemis.api.core.client.ServerLocator;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Factory to create a Artemis {@link ActiveMQConnectionFactory} instance from properties
* defined in {@link ArtemisProperties}.
*
* @author Eddú Meléndez
* @author Phillip Webb
* @author Stephane Nicoll
*/
class ArtemisConnectionFactoryFactory {
static final String EMBEDDED_JMS_CLASS = "org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ";
private final ArtemisProperties properties;
private final ListableBeanFactory beanFactory;
public ArtemisConnectionFactoryFactory(ListableBeanFactory beanFactory,
ArtemisProperties properties) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
Assert.notNull(properties, "Properties must not be null");
this.beanFactory = beanFactory;
this.properties = properties;
}
public <T extends ActiveMQConnectionFactory> T createConnectionFactory(
Class<T> factoryClass) {
try {
startEmbeddedJms();
return doCreateConnectionFactory(factoryClass);
}
catch (Exception ex) {
throw new IllegalStateException("Unable to create "
+ "ActiveMQConnectionFactory", ex);
}
}
private void startEmbeddedJms() {
if (ClassUtils.isPresent(EMBEDDED_JMS_CLASS, null)) {
try {
this.beanFactory.getBeansOfType(Class.forName(EMBEDDED_JMS_CLASS));
}
catch (Exception ex) {
// Ignore
}
}
}
private <T extends ActiveMQConnectionFactory> T doCreateConnectionFactory(
Class<T> factoryClass) throws Exception {
ArtemisMode mode = this.properties.getMode();
if (mode == null) {
mode = deduceMode();
}
if (mode == ArtemisMode.EMBEDDED) {
return createEmbeddedConnectionFactory(factoryClass);
}
return createNativeConnectionFactory(factoryClass);
}
/**
* Deduce the {@link ArtemisMode} to use if none has been set.
*/
private ArtemisMode deduceMode() {
if (this.properties.getEmbedded().isEnabled()
&& ClassUtils.isPresent(EMBEDDED_JMS_CLASS, null)) {
return ArtemisMode.EMBEDDED;
}
return ArtemisMode.NATIVE;
}
private <T extends ActiveMQConnectionFactory> T createEmbeddedConnectionFactory(
Class<T> factoryClass) throws Exception {
try {
TransportConfiguration transportConfiguration = new TransportConfiguration(
InVMConnectorFactory.class.getName(), this.properties.getEmbedded()
.generateTransportParameters());
ServerLocator serviceLocator = ActiveMQClient
.createServerLocatorWithoutHA(transportConfiguration);
return factoryClass.getConstructor(ServerLocator.class).newInstance(
serviceLocator);
}
catch (NoClassDefFoundError ex) {
throw new IllegalStateException("Unable to create InVM "
+ "Artemis connection, ensure that artemis-jms-server.jar "
+ "is in the classpath", ex);
}
}
private <T extends ActiveMQConnectionFactory> T createNativeConnectionFactory(
Class<T> factoryClass) throws Exception {
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);
Constructor<T> constructor = factoryClass.getConstructor(boolean.class,
TransportConfiguration[].class);
return constructor.newInstance(false,
new TransportConfiguration[] { transportConfiguration });
}
}

@ -0,0 +1,78 @@
/*
* 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.
* 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.artemis;
import java.io.File;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory;
import org.apache.activemq.artemis.core.server.JournalType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Configuration used to create the embedded Artemis server.
*
* @author Eddú Meléndez
* @author Stephane Nicol
* @author Phillip Webb
*/
class ArtemisEmbeddedConfigurationFactory {
private Log logger = LogFactory.getLog(ArtemisEmbeddedConfigurationFactory.class);
private final ArtemisProperties.Embedded properties;
public ArtemisEmbeddedConfigurationFactory(ArtemisProperties properties) {
this.properties = properties.getEmbedded();
}
public Configuration createConfiguration() {
ConfigurationImpl configuration = new ConfigurationImpl();
configuration.setSecurityEnabled(false);
configuration.setPersistenceEnabled(this.properties.isPersistent());
String dataDir = getDataDir();
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(),
this.properties.generateTransportParameters());
configuration.getAcceptorConfigurations().add(transportConfiguration);
if (this.properties.isDefaultClusterPassword()) {
this.logger.debug("Using default Artemis 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, "artemis-data").getAbsolutePath();
}
}

@ -0,0 +1,128 @@
/*
* 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.
* 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.artemis;
import java.util.Collection;
import java.util.List;
import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
import org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration;
import org.apache.activemq.artemis.jms.server.config.TopicConfiguration;
import org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;
import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
/**
* Configuration used to create the embedded Artemis server.
*
* @author Eddú Meléndez
* @author Phillip Webb
* @author Stephane Nicoll
*/
@Configuration
@ConditionalOnClass(name = ArtemisConnectionFactoryFactory.EMBEDDED_JMS_CLASS)
@ConditionalOnProperty(prefix = "spring.artemis.embedded", name = "enabled", havingValue = "true", matchIfMissing = true)
class ArtemisEmbeddedServerConfiguration {
@Autowired
private ArtemisProperties properties;
@Autowired(required = false)
private List<ArtemisConfigurationCustomizer> configurationCustomizers;
@Autowired(required = false)
private List<JMSQueueConfiguration> queuesConfiguration;
@Autowired(required = false)
private List<TopicConfiguration> topicsConfiguration;
@Bean
@ConditionalOnMissingBean
public org.apache.activemq.artemis.core.config.Configuration artemisConfiguration() {
return new ArtemisEmbeddedConfigurationFactory(this.properties)
.createConfiguration();
}
@Bean(initMethod = "start", destroyMethod = "stop")
@ConditionalOnMissingBean
public EmbeddedJMS artemisServer(
org.apache.activemq.artemis.core.config.Configuration configuration,
JMSConfiguration jmsConfiguration) {
EmbeddedJMS server = new EmbeddedJMS();
customize(configuration);
server.setConfiguration(configuration);
server.setJmsConfiguration(jmsConfiguration);
server.setRegistry(new ArtemisNoOpBindingRegistry());
return server;
}
private void customize(
org.apache.activemq.artemis.core.config.Configuration configuration) {
if (this.configurationCustomizers != null) {
AnnotationAwareOrderComparator.sort(this.configurationCustomizers);
for (ArtemisConfigurationCustomizer customizer : this.configurationCustomizers) {
customizer.customize(configuration);
}
}
}
@Bean
@ConditionalOnMissingBean
public JMSConfiguration artemisJmsConfiguration() {
JMSConfiguration configuration = new JMSConfigurationImpl();
addAll(configuration.getQueueConfigurations(), this.queuesConfiguration);
addAll(configuration.getTopicConfigurations(), this.topicsConfiguration);
addQueues(configuration, this.properties.getEmbedded().getQueues());
addTopics(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) {
JMSQueueConfigurationImpl jmsQueueConfiguration = new JMSQueueConfigurationImpl();
jmsQueueConfiguration.setName(queue);
jmsQueueConfiguration.setDurable(persistent);
jmsQueueConfiguration.setBindings("/queue/" + queue);
configuration.getQueueConfigurations().add(jmsQueueConfiguration);
}
}
private void addTopics(JMSConfiguration configuration, String[] topics) {
for (String topic : topics) {
TopicConfigurationImpl topicConfiguration = new TopicConfigurationImpl();
topicConfiguration.setName(topic);
topicConfiguration.setBindings("/topic/" + topic);
configuration.getTopicConfigurations().add(topicConfiguration);
}
}
}

@ -0,0 +1,38 @@
/*
* 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.
* 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.artemis;
/**
* Define the mode in which Artemis can operate.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 1.3.0
*/
public enum ArtemisMode {
/**
* Connect to a broker using the native Artemis protocol (i.e. netty).
*/
NATIVE,
/**
* Embed (i.e. start) the broker in the application.
*/
EMBEDDED
}

@ -0,0 +1,48 @@
/*
* 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.
* 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.artemis;
import org.apache.activemq.artemis.spi.core.naming.BindingRegistry;
/**
* A no-op implementation of the {@link BindingRegistry}.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 1.3.0
*/
public class ArtemisNoOpBindingRegistry implements BindingRegistry {
@Override
public Object lookup(String s) {
return null;
}
@Override
public boolean bind(String s, Object o) {
return false;
}
@Override
public void unbind(String s) {
}
@Override
public void close() {
}
}

@ -0,0 +1,202 @@
/*
* 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.
* 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.artemis;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for Artemis
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 1.3.0
*/
@ConfigurationProperties(prefix = "spring.artemis")
public class ArtemisProperties {
/**
* Artemis deployment mode, auto-detected by default. Can be explicitly set to
* "native" or "embedded".
*/
private ArtemisMode mode;
/**
* Artemis broker host.
*/
private String host = "localhost";
/**
* Artemis broker port.
*/
private int port = 61616;
private final Embedded embedded = new Embedded();
public ArtemisMode getMode() {
return this.mode;
}
public void setMode(ArtemisMode 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 Artemis server.
*/
public static class Embedded {
private static final AtomicInteger serverIdCounter = new AtomicInteger();
/**
* Server id. By default, an auto-incremented counter is used.
*/
private int serverId = serverIdCounter.getAndIncrement();
/**
* Enable embedded mode if the Artemis server APIs are available.
*/
private boolean enabled = true;
/**
* Enable persistent store.
*/
private boolean persistent;
/**
* Journal file directory. Not necessary if persistence is turned off.
*/
private String dataDirectory;
/**
* Comma-separated list of queues to create on startup.
*/
private String[] queues = new String[0];
/**
* Comma-separated list of topics to create on startup.
*/
private String[] topics = new String[0];
/**
* Cluster password. Randomly generated on startup by default.
*/
private String clusterPassword = UUID.randomUUID().toString();
private boolean defaultClusterPassword = true;
public int getServerId() {
return this.serverId;
}
public void setServerId(int serverId) {
this.serverId = serverId;
}
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;
}
/**
* Creates the minimal transport parameters for an embedded transport
* configuration.
* @return the transport parameters
* @see TransportConstants#SERVER_ID_PROP_NAME
*/
public Map<String, Object> generateTransportParameters() {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put(TransportConstants.SERVER_ID_PROP_NAME, getServerId());
return parameters;
}
}
}

@ -0,0 +1,62 @@
/*
* 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.
* 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.artemis;
import javax.jms.ConnectionFactory;
import javax.transaction.TransactionManager;
import org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* Configuration for Artemis XA {@link ConnectionFactory}.
*
* @author Eddú Meléndez
* @author Phillip Webb
* @since 1.3.0
*/
@Configuration
@ConditionalOnMissingBean(ConnectionFactory.class)
@ConditionalOnClass(TransactionManager.class)
@ConditionalOnBean(XAConnectionFactoryWrapper.class)
class ArtemisXAConnectionFactoryConfiguration {
@Primary
@Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" })
public ConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory,
ArtemisProperties properties, XAConnectionFactoryWrapper wrapper)
throws Exception {
return wrapper.wrapConnectionFactory(new ArtemisConnectionFactoryFactory(
beanFactory, properties)
.createConnectionFactory(ActiveMQXAConnectionFactory.class));
}
@Bean
public ConnectionFactory nonXaJmsConnectionFactory(ListableBeanFactory beanFactory,
ArtemisProperties properties) {
return new ArtemisConnectionFactoryFactory(beanFactory, properties)
.createConnectionFactory(ActiveMQXAConnectionFactory.class);
}
}

@ -0,0 +1,22 @@
/*
* 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.
* 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.
*/
/**
* Auto-configuration for Artemis.
*
* @author Eddú Meléndez
*/
package org.springframework.boot.autoconfigure.jms.artemis;

@ -32,6 +32,7 @@ org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.hornetq.HornetQAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchDataAutoConfiguration,\

@ -0,0 +1,421 @@
/*
* 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.
* 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.artemis;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
import org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration;
import org.apache.activemq.artemis.jms.server.config.TopicConfiguration;
import org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;
import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.SessionCallback;
import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.jms.support.destination.DynamicDestinationResolver;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Tests for {@link ArtemisAutoConfiguration}.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
*/
public class ArtemisAutoConfigurationTests {
@Rule
public final TemporaryFolder folder = new TemporaryFolder();
private AnnotationConfigApplicationContext context;
@After
public void tearDown() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void nativeConnectionFactory() {
load(EmptyConfiguration.class, "spring.artemis.mode:native");
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertEquals(jmsTemplate.getConnectionFactory(), connectionFactory);
assertNettyConnectionFactory(connectionFactory, "localhost", 61616);
}
@Test
public void nativeConnectionFactoryCustomHost() {
load(EmptyConfiguration.class, "spring.artemis.mode:native",
"spring.artemis.host:192.168.1.144", "spring.artemis.port:9876");
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertNettyConnectionFactory(connectionFactory, "192.168.1.144", 9876);
}
@Test
public void embeddedConnectionFactory() {
load(EmptyConfiguration.class, "spring.artemis.mode:embedded");
ArtemisProperties properties = this.context.getBean(ArtemisProperties.class);
assertEquals(ArtemisMode.EMBEDDED, properties.getMode());
assertEquals(1, this.context.getBeansOfType(EmbeddedJMS.class).size());
org.apache.activemq.artemis.core.config.Configuration configuration = this.context
.getBean(org.apache.activemq.artemis.core.config.Configuration.class);
assertFalse("Persistence disabled by default",
configuration.isPersistenceEnabled());
assertFalse("Security disabled by default", configuration.isSecurityEnabled());
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertInVmConnectionFactory(connectionFactory);
}
@Test
public void embeddedConnectionFactoryByDefault() {
// No mode is specified
load(EmptyConfiguration.class);
assertEquals(1, this.context.getBeansOfType(EmbeddedJMS.class).size());
org.apache.activemq.artemis.core.config.Configuration configuration = this.context
.getBean(org.apache.activemq.artemis.core.config.Configuration.class);
assertFalse("Persistence disabled by default",
configuration.isPersistenceEnabled());
assertFalse("Security disabled by default", configuration.isSecurityEnabled());
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertInVmConnectionFactory(connectionFactory);
}
@Test
public void nativeConnectionFactoryIfEmbeddedServiceDisabledExplicitly() {
// No mode is specified
load(EmptyConfiguration.class, "spring.artemis.embedded.enabled:false");
assertEquals(0, this.context.getBeansOfType(EmbeddedJMS.class).size());
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertNettyConnectionFactory(connectionFactory, "localhost", 61616);
}
@Test
public void embeddedConnectionFactorEvenIfEmbeddedServiceDisabled() {
// No mode is specified
load(EmptyConfiguration.class, "spring.artemis.mode:embedded",
"spring.artemis.embedded.enabled:false");
assertEquals(0, this.context.getBeansOfType(EmbeddedJMS.class).size());
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertInVmConnectionFactory(connectionFactory);
}
@Test
public void embeddedServerWithDestinations() {
load(EmptyConfiguration.class, "spring.artemis.embedded.queues=Queue1,Queue2",
"spring.artemis.embedded.topics=Topic1");
DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("Queue1", true);
checker.checkQueue("Queue2", true);
checker.checkQueue("QueueDoesNotExist", true);
checker.checkTopic("Topic1", true);
checker.checkTopic("TopicDoesNotExist", false);
}
@Test
public void embeddedServerWithDestinationConfig() {
load(DestinationConfiguration.class);
DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("sampleQueue", true);
checker.checkTopic("sampleTopic", true);
}
@Test
public void embeddedServiceWithCustomJmsConfiguration() {
// Ignored with custom config
load(CustomJmsConfiguration.class, "spring.artemis.embedded.queues=Queue1,Queue2");
DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("custom", true); // See CustomJmsConfiguration
checker.checkQueue("Queue1", true);
checker.checkQueue("Queue2", true);
}
@Test
public void embeddedServiceWithCustomArtemisConfiguration() {
load(CustomArtemisConfiguration.class);
org.apache.activemq.artemis.core.config.Configuration configuration = this.context
.getBean(org.apache.activemq.artemis.core.config.Configuration.class);
assertEquals("customFooBar", configuration.getName());
}
@Test
public void embeddedWithPersistentMode() throws IOException, JMSException {
File dataFolder = this.folder.newFolder();
// Start the server and post a message to some queue
load(EmptyConfiguration.class, "spring.artemis.embedded.queues=TestQueue",
"spring.artemis.embedded.persistent:true",
"spring.artemis.embedded.dataDirectory:" + dataFolder.getAbsolutePath());
final String msgId = UUID.randomUUID().toString();
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
jmsTemplate.send("TestQueue", new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(msgId);
}
});
this.context.close(); // Shutdown the broker
// Start the server again and check if our message is still here
load(EmptyConfiguration.class, "spring.artemis.embedded.queues=TestQueue",
"spring.artemis.embedded.persistent:true",
"spring.artemis.embedded.dataDirectory:" + dataFolder.getAbsolutePath());
JmsTemplate jmsTemplate2 = this.context.getBean(JmsTemplate.class);
jmsTemplate2.setReceiveTimeout(1000L);
Message message = jmsTemplate2.receive("TestQueue");
assertNotNull("No message on persistent queue", message);
assertEquals("Invalid message received on queue", msgId,
((TextMessage) message).getText());
}
@Test
public void severalEmbeddedBrokers() {
load(EmptyConfiguration.class, "spring.artemis.embedded.queues=Queue1");
AnnotationConfigApplicationContext anotherContext = doLoad(
EmptyConfiguration.class, "spring.artemis.embedded.queues=Queue2");
try {
ArtemisProperties properties = this.context.getBean(ArtemisProperties.class);
ArtemisProperties anotherProperties = anotherContext
.getBean(ArtemisProperties.class);
assertTrue("ServerId should not match", properties.getEmbedded()
.getServerId() < anotherProperties.getEmbedded().getServerId());
DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("Queue1", true);
checker.checkQueue("Queue2", true);
DestinationChecker anotherChecker = new DestinationChecker(anotherContext);
anotherChecker.checkQueue("Queue2", true);
anotherChecker.checkQueue("Queue1", true);
}
finally {
anotherContext.close();
}
}
@Test
public void connectToASpecificEmbeddedBroker() {
load(EmptyConfiguration.class, "spring.artemis.embedded.serverId=93",
"spring.artemis.embedded.queues=Queue1");
AnnotationConfigApplicationContext anotherContext = doLoad(
EmptyConfiguration.class, "spring.artemis.mode=embedded",
"spring.artemis.embedded.serverId=93", // Connect to the "main" broker
"spring.artemis.embedded.enabled=false"); // do not start a specific one
try {
DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("Queue1", true);
DestinationChecker anotherChecker = new DestinationChecker(anotherContext);
anotherChecker.checkQueue("Queue1", true);
}
finally {
anotherContext.close();
}
}
private TransportConfiguration assertInVmConnectionFactory(
ActiveMQConnectionFactory connectionFactory) {
TransportConfiguration transportConfig = getSingleTransportConfiguration(connectionFactory);
assertEquals(InVMConnectorFactory.class.getName(),
transportConfig.getFactoryClassName());
return transportConfig;
}
private TransportConfiguration assertNettyConnectionFactory(
ActiveMQConnectionFactory connectionFactory, String host, int port) {
TransportConfiguration transportConfig = getSingleTransportConfiguration(connectionFactory);
assertEquals(NettyConnectorFactory.class.getName(),
transportConfig.getFactoryClassName());
assertEquals(host, transportConfig.getParams().get("host"));
assertEquals(port, transportConfig.getParams().get("port"));
return transportConfig;
}
private TransportConfiguration getSingleTransportConfiguration(
ActiveMQConnectionFactory connectionFactory) {
TransportConfiguration[] transportConfigurations = connectionFactory
.getServerLocator().getStaticTransportConfigurations();
assertEquals(1, transportConfigurations.length);
return transportConfigurations[0];
}
private void load(Class<?> config, String... environment) {
this.context = doLoad(config, environment);
}
private AnnotationConfigApplicationContext doLoad(Class<?> config,
String... environment) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(config);
applicationContext.register(ArtemisAutoConfigurationWithoutXA.class,
JmsAutoConfiguration.class);
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
applicationContext.refresh();
return applicationContext;
}
private static class DestinationChecker {
private final JmsTemplate jmsTemplate;
private final DestinationResolver destinationResolver;
private DestinationChecker(ApplicationContext applicationContext) {
this.jmsTemplate = applicationContext.getBean(JmsTemplate.class);
this.destinationResolver = new DynamicDestinationResolver();
}
public void checkQueue(String name, boolean shouldExist) {
checkDestination(name, false, shouldExist);
}
public void checkTopic(String name, boolean shouldExist) {
checkDestination(name, true, shouldExist);
}
public void checkDestination(final String name, final boolean pubSub,
final boolean shouldExist) {
this.jmsTemplate.execute(new SessionCallback<Void>() {
@Override
public Void doInJms(Session session) throws JMSException {
try {
Destination destination = DestinationChecker.this.destinationResolver
.resolveDestinationName(session, name, pubSub);
if (!shouldExist) {
throw new IllegalStateException("Destination '" + name
+ "' was not expected but got " + destination);
}
}
catch (JMSException e) {
if (shouldExist) {
throw new IllegalStateException("Destination '" + name
+ "' was expected but got " + e.getMessage());
}
}
return null;
}
});
}
}
@Configuration
protected static class EmptyConfiguration {
}
@Configuration
protected static class DestinationConfiguration {
@Bean
JMSQueueConfiguration sampleQueueConfiguration() {
JMSQueueConfigurationImpl jmsQueueConfiguration = new JMSQueueConfigurationImpl();
jmsQueueConfiguration.setName("sampleQueue");
jmsQueueConfiguration.setSelector("foo=bar");
jmsQueueConfiguration.setDurable(false);
jmsQueueConfiguration.setBindings("/queue/1");
return jmsQueueConfiguration;
}
@Bean
TopicConfiguration sampleTopicConfiguration() {
TopicConfigurationImpl topicConfiguration = new TopicConfigurationImpl();
topicConfiguration.setName("sampleTopic");
topicConfiguration.setBindings("/topic/1");
return topicConfiguration;
}
}
@Configuration
protected static class CustomJmsConfiguration {
@Bean
public JMSConfiguration myJmsConfiguration() {
JMSConfiguration config = new JMSConfigurationImpl();
JMSQueueConfiguration jmsQueueConfiguration = new JMSQueueConfigurationImpl();
jmsQueueConfiguration.setName("custom");
jmsQueueConfiguration.setDurable(false);
config.getQueueConfigurations().add(jmsQueueConfiguration);
return config;
}
}
@Configuration
protected static class CustomArtemisConfiguration {
@Bean
public ArtemisConfigurationCustomizer myArtemisCustomize() {
return new ArtemisConfigurationCustomizer() {
@Override
public void customize(
org.apache.activemq.artemis.core.config.Configuration configuration) {
configuration.setClusterPassword("Foobar");
configuration.setName("customFooBar");
}
};
}
}
@Configuration
@EnableConfigurationProperties(ArtemisProperties.class)
@Import({ ArtemisEmbeddedServerConfiguration.class,
ArtemisConnectionFactoryConfiguration.class })
protected static class ArtemisAutoConfigurationWithoutXA {
}
}

@ -0,0 +1,75 @@
/*
* 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.
* 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.artemis;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.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 ArtemisEmbeddedConfigurationFactory}
*
* @author Eddú Meléndez
* @author Stephane Nicol
* @author Phillip Webb
*/
public class ArtemisEmbeddedConfigurationFactoryTests {
@Test
public void defaultDataDir() {
ArtemisProperties properties = new ArtemisProperties();
properties.getEmbedded().setPersistent(true);
Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties)
.createConfiguration();
assertThat(configuration.getJournalDirectory(),
startsWith(System.getProperty("java.io.tmpdir")));
assertThat(configuration.getJournalDirectory(), endsWith("/journal"));
}
@Test
public void persistenceSetup() {
ArtemisProperties properties = new ArtemisProperties();
properties.getEmbedded().setPersistent(true);
Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties)
.createConfiguration();
assertThat(configuration.isPersistenceEnabled(), equalTo(true));
assertThat(configuration.getJournalType(), equalTo(JournalType.NIO));
}
@Test
public void generatedClusterPassword() throws Exception {
ArtemisProperties properties = new ArtemisProperties();
Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties)
.createConfiguration();
assertThat(configuration.getClusterPassword().length(), equalTo(36));
}
@Test
public void specificClusterPassword() throws Exception {
ArtemisProperties properties = new ArtemisProperties();
properties.getEmbedded().setClusterPassword("password");
Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties)
.createConfiguration();
assertThat(configuration.getClusterPassword(), equalTo("password"));
}
}

@ -48,6 +48,7 @@
<!-- Third Party -->
<activemq.version>5.11.1</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<artemis.version>1.0.0</artemis.version>
<aspectj.version>1.8.6</aspectj.version>
<atomikos.version>3.9.3</atomikos.version>
<bitronix.version>2.1.4</bitronix.version>
@ -933,6 +934,16 @@
<artifactId>activemq-web-console</artifactId>
<version>${activemq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-jms-client</artifactId>
<version>${artemis.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-jms-server</artifactId>
<version>${artemis.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>

@ -484,7 +484,19 @@ 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/hornetq/HornetQProperties.{sc-ext}[HornetQProperties])
# ARTEMIS ({sc-spring-boot-autoconfigure}/jms/artemis/ArtemisProperties.{sc-ext}[ArtemisProperties])
spring.artemis.mode= # connection mode (native, embedded)
spring.artemis.host=localhost # hornetQ host (native mode)
spring.artemis.port=5445 # hornetQ port (native mode)
spring.artemis.embedded.enabled=true # if the embedded server is enabled (needs hornetq-jms-server.jar)
spring.artemis.embedded.server-id= # auto-generated id of the embedded server (integer)
spring.artemis.embedded.persistent=false # message persistence
spring.artemis.embedded.data-directory= # location of data content (when persistence is enabled)
spring.artemis.embedded.queues= # comma-separated queues to create on startup
spring.artemis.embedded.topics= # comma-separated topics to create on startup
spring.artemis.embedded.cluster-password= # customer password (randomly generated by default)
# HORNETQ ({sc-spring-boot-autoconfigure}/jms/hornetq/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)

@ -2515,6 +2515,43 @@ to send and receive messages.
[[boot-features-activemq]]
==== ActiveMQ support
Spring Boot can also configure a `ConnectionFactory` when it detects that ActiveMQ is
available on the classpath. If the broker is present, an embedded broker is started and
configured automatically (as long as no broker URL is specified through configuration).
ActiveMQ configuration is controlled by external configuration properties in
`+spring.activemq.*+`. For example, you might declare the following section in
`application.properties`:
[source,properties,indent=0]
----
spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret
----
See
{sc-spring-boot-autoconfigure}/jms/activemq/ActiveMQProperties.{sc-ext}[`ActiveMQProperties`]
for more of the supported options.
By default, ActiveMQ creates a destination if it does not exist yet, so destinations are
resolved against their provided names.
[[boot-features-artemis]]
==== Artemis support
Apache Artemis was formed in 2015 when HornetQ was donated to the Apache Foundation. All
the features listed in the <<boot-features-hornetq>> section below can be applied to
Artemis. Simply replace `+++spring.hornetq.*+++` properties with `+++spring.artemis.*+++`
and use `spring-boot-starter-artemis` instead of `spring-boot-starter-hornetq`.
NOTE: You should not try and use Artemis and HornetQ and the same time.
[[boot-features-hornetq]]
==== HornetQ support
Spring Boot can auto-configure a `ConnectionFactory` when it detects that HornetQ is
@ -2559,32 +2596,6 @@ through configuration.
[[boot-features-activemq]]
==== ActiveMQ support
Spring Boot can also configure a `ConnectionFactory` when it detects that ActiveMQ is
available on the classpath. If the broker is present, an embedded broker is started and
configured automatically (as long as no broker URL is specified through configuration).
ActiveMQ configuration is controlled by external configuration properties in
`+spring.activemq.*+`. For example, you might declare the following section in
`application.properties`:
[source,properties,indent=0]
----
spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret
----
See
{sc-spring-boot-autoconfigure}/jms/activemq/ActiveMQProperties.{sc-ext}[`ActiveMQProperties`]
for more of the supported options.
By default, ActiveMQ creates a destination if it does not exist yet, so destinations are
resolved against their provided names.
[[boot-features-jms-jndi]]
==== Using a JNDI ConnectionFactory
If you are running your application in an Application Server Spring Boot will attempt to

@ -264,6 +264,9 @@ The following application starters are provided by Spring Boot under the
|`spring-boot-starter-aop`
|Support for aspect-oriented programming including `spring-aop` and AspectJ.
|`spring-boot-starter-artemis`
|Support for "`Java Message Service API`" via Apache Artemis.
|`spring-boot-starter-batch`
|Support for "`Spring Batch`" including HSQLDB database.

@ -23,6 +23,7 @@
<module>spring-boot-starter</module>
<module>spring-boot-starter-amqp</module>
<module>spring-boot-starter-aop</module>
<module>spring-boot-starter-artemis</module>
<module>spring-boot-starter-batch</module>
<module>spring-boot-starter-cache</module>
<module>spring-boot-starter-cloud-connectors</module>

@ -0,0 +1,34 @@
<?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.3.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-starter-artemis</artifactId>
<name>Spring Boot Artemis Starter</name>
<description>Spring Boot Artemis 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.apache.activemq</groupId>
<artifactId>artemis-jms-client</artifactId>
</dependency>
</dependencies>
</project>
Loading…
Cancel
Save