Add JMS autoconfig support

* application.properties support for spring.jms and spring.activemq

* more tests to verify ActiveMQConnectionFactory pooling

* Groovy support and simple sample with activemq

* Groovy detection mechanism is @EnableJmsMessaging annotation
pull/57/merge
Greg Turnquist 11 years ago committed by Dave Syer
parent e16a0278ae
commit fa6e6fde6c

@ -31,6 +31,11 @@
<artifactId>activemq-core</artifactId> <artifactId>activemq-core</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.apache.tomcat.embed</groupId> <groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId> <artifactId>tomcat-embed-core</artifactId>

@ -19,10 +19,13 @@ package org.springframework.boot.autoconfigure.jms;
import javax.jms.ConnectionFactory; import javax.jms.ConnectionFactory;
import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.pool.PooledConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.JmsTemplate;
@ -38,28 +41,97 @@ public class JmsTemplateAutoConfiguration {
@Configuration @Configuration
@ConditionalOnMissingBean(JmsTemplate.class) @ConditionalOnMissingBean(JmsTemplate.class)
@EnableConfigurationProperties(JmsTemplateProperties.class)
protected static class JmsTemplateCreator { protected static class JmsTemplateCreator {
@Autowired
private JmsTemplateProperties config;
@Autowired @Autowired
private ConnectionFactory connectionFactory; private ConnectionFactory connectionFactory;
@Bean @Bean
public JmsTemplate jmsTemplate() { public JmsTemplate jmsTemplate() {
JmsTemplate jmsTemplate = new JmsTemplate(this.connectionFactory); JmsTemplate jmsTemplate = new JmsTemplate(this.connectionFactory);
jmsTemplate.setPubSubDomain(true); jmsTemplate.setPubSubDomain(this.config.isPubSubDomain());
return jmsTemplate; return jmsTemplate;
} }
} }
@ConfigurationProperties(name = "spring.jms")
public static class JmsTemplateProperties {
private boolean pubSubDomain = true;
public boolean isPubSubDomain() {
return pubSubDomain;
}
public void setPubSubDomain(boolean pubSubDomain) {
this.pubSubDomain = pubSubDomain;
}
}
@Configuration @Configuration
@ConditionalOnClass(ActiveMQConnectionFactory.class) @ConditionalOnClass(ActiveMQConnectionFactory.class)
@ConditionalOnMissingBean(ConnectionFactory.class) @ConditionalOnMissingBean(ConnectionFactory.class)
@EnableConfigurationProperties(ActiveMQConnectionFactoryProperties.class)
protected static class ActiveMQConnectionFactoryCreator { protected static class ActiveMQConnectionFactoryCreator {
@Autowired
private ActiveMQConnectionFactoryProperties config;
@Bean @Bean
ConnectionFactory connectionFactory() { ConnectionFactory connectionFactory() {
return new ActiveMQConnectionFactory("vm://localhost"); if (this.config.isPooled()) {
PooledConnectionFactory pool = new PooledConnectionFactory();
pool.setConnectionFactory(new ActiveMQConnectionFactory(this.config.getBrokerURL()));
return pool;
} else {
return new ActiveMQConnectionFactory(this.config.getBrokerURL());
}
}
}
@ConfigurationProperties(name = "spring.activemq")
public static class ActiveMQConnectionFactoryProperties {
private String brokerURL = "tcp://localhost:61616";
private boolean inMemory = true;
private boolean pooled = false;
// Will override brokerURL if inMemory is set to true
public String getBrokerURL() {
if (this.inMemory) {
return "vm://localhost";
} else {
return this.brokerURL;
}
}
public void setBrokerURL(String brokerURL) {
this.brokerURL = brokerURL;
}
public boolean isInMemory() {
return inMemory;
}
public void setInMemory(boolean inMemory) {
this.inMemory = inMemory;
}
public boolean isPooled() {
return pooled;
}
public void setPooled(boolean pooled) {
this.pooled = pooled;
} }
} }

@ -19,9 +19,11 @@ package org.springframework.boot.autoconfigure.jms;
import javax.jms.ConnectionFactory; import javax.jms.ConnectionFactory;
import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.pool.PooledConnectionFactory;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.TestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -53,6 +55,7 @@ public class JmsTemplateAutoConfigurationTests {
assertNotNull(jmsTemplate); assertNotNull(jmsTemplate);
assertNotNull(connectionFactory); assertNotNull(connectionFactory);
assertEquals(jmsTemplate.getConnectionFactory(), connectionFactory); assertEquals(jmsTemplate.getConnectionFactory(), connectionFactory);
assertEquals(((ActiveMQConnectionFactory)jmsTemplate.getConnectionFactory()).getBrokerURL(), "vm://localhost");
} }
@Test @Test
@ -107,6 +110,110 @@ public class JmsTemplateAutoConfigurationTests {
assertFalse(jmsTemplate.isPubSubDomain()); assertFalse(jmsTemplate.isPubSubDomain());
} }
@Test
public void testJmsTemplateOverridden() {
this.context = new AnnotationConfigApplicationContext();
this.context
.register(TestConfiguration.class, JmsTemplateAutoConfiguration.class);
TestUtils.addEnviroment(this.context, "spring.jms.pubSubDomain:false");
this.context.refresh();
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertNotNull(jmsTemplate);
assertFalse(jmsTemplate.isPubSubDomain());
assertNotNull(connectionFactory);
assertEquals(jmsTemplate.getConnectionFactory(), connectionFactory);
}
@Test
public void testActiveMQOverriddenStandalone() {
this.context = new AnnotationConfigApplicationContext();
this.context
.register(TestConfiguration.class, JmsTemplateAutoConfiguration.class);
TestUtils.addEnviroment(this.context, "spring.activemq.inMemory:false");
this.context.refresh();
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertNotNull(jmsTemplate);
assertNotNull(connectionFactory);
assertEquals(jmsTemplate.getConnectionFactory(), connectionFactory);
assertEquals(((ActiveMQConnectionFactory)jmsTemplate.getConnectionFactory()).getBrokerURL(),
"tcp://localhost:61616");
}
@Test
public void testActiveMQOverriddenRemoteHost() {
this.context = new AnnotationConfigApplicationContext();
this.context
.register(TestConfiguration.class, JmsTemplateAutoConfiguration.class);
TestUtils.addEnviroment(this.context, "spring.activemq.inMemory:false",
"spring.activemq.brokerURL:tcp://remote-host:10000");
this.context.refresh();
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertNotNull(jmsTemplate);
assertNotNull(connectionFactory);
assertEquals(jmsTemplate.getConnectionFactory(), connectionFactory);
assertEquals(((ActiveMQConnectionFactory)jmsTemplate.getConnectionFactory()).getBrokerURL(),
"tcp://remote-host:10000");
}
@Test
public void testActiveMQOverriddenPool() {
this.context = new AnnotationConfigApplicationContext();
this.context
.register(TestConfiguration.class, JmsTemplateAutoConfiguration.class);
TestUtils.addEnviroment(this.context, "spring.activemq.pooled:true");
this.context.refresh();
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
PooledConnectionFactory pool = this.context
.getBean(PooledConnectionFactory.class);
assertNotNull(jmsTemplate);
assertNotNull(pool);
assertEquals(jmsTemplate.getConnectionFactory(), pool);
ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory) pool.getConnectionFactory();
assertEquals("vm://localhost", factory.getBrokerURL());
}
@Test
public void testActiveMQOverriddenPoolAndStandalone() {
this.context = new AnnotationConfigApplicationContext();
this.context
.register(TestConfiguration.class, JmsTemplateAutoConfiguration.class);
TestUtils.addEnviroment(this.context, "spring.activemq.pooled:true",
"spring.activemq.inMemory:false");
this.context.refresh();
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
PooledConnectionFactory pool = this.context
.getBean(PooledConnectionFactory.class);
assertNotNull(jmsTemplate);
assertNotNull(pool);
assertEquals(jmsTemplate.getConnectionFactory(), pool);
ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory) pool.getConnectionFactory();
assertEquals("tcp://localhost:61616", factory.getBrokerURL());
}
@Test
public void testActiveMQOverriddenPoolAndRemoteServer() {
this.context = new AnnotationConfigApplicationContext();
this.context
.register(TestConfiguration.class, JmsTemplateAutoConfiguration.class);
TestUtils.addEnviroment(this.context, "spring.activemq.pooled:true",
"spring.activemq.inMemory:false", "spring.activemq.brokerURL:tcp://remote-host:10000");
this.context.refresh();
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
PooledConnectionFactory pool = this.context
.getBean(PooledConnectionFactory.class);
assertNotNull(jmsTemplate);
assertNotNull(pool);
assertEquals(jmsTemplate.getConnectionFactory(), pool);
ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory) pool.getConnectionFactory();
assertEquals("tcp://remote-host:10000", factory.getBrokerURL());
}
@Configuration @Configuration
protected static class TestConfiguration { protected static class TestConfiguration {
} }

@ -1,11 +1,13 @@
package org.test package org.test
@Grab("org.apache.activemq:activemq-all:5.4.0") @Grab("org.apache.activemq:activemq-all:5.4.0")
@Grab("org.apache.activemq:activemq-pool:5.4.0")
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
@Configuration
@Log @Log
@Configuration
@EnableJmsMessaging
class JmsExample implements CommandLineRunner { class JmsExample implements CommandLineRunner {
private CountDownLatch latch = new CountDownLatch(1) private CountDownLatch latch = new CountDownLatch(1)
@ -30,7 +32,6 @@ class JmsExample implements CommandLineRunner {
session.createObjectMessage("Greetings from Spring Boot via ActiveMQ") session.createObjectMessage("Greetings from Spring Boot via ActiveMQ")
} as MessageCreator } as MessageCreator
log.info "Sending JMS message..." log.info "Sending JMS message..."
jmsTemplate.pubSubDomain = true
jmsTemplate.send("spring-boot", messageCreator) jmsTemplate.send("spring-boot", messageCreator)
latch.await() latch.await()
} }

@ -23,6 +23,8 @@ import org.springframework.boot.cli.compiler.AstUtils;
import org.springframework.boot.cli.compiler.CompilerAutoConfiguration; import org.springframework.boot.cli.compiler.CompilerAutoConfiguration;
import org.springframework.boot.cli.compiler.DependencyCustomizer; import org.springframework.boot.cli.compiler.DependencyCustomizer;
import java.lang.annotation.*;
/** /**
* {@link CompilerAutoConfiguration} for Spring JMS. * {@link CompilerAutoConfiguration} for Spring JMS.
* *
@ -32,8 +34,9 @@ public class JmsCompilerAutoConfiguration extends CompilerAutoConfiguration {
@Override @Override
public boolean matches(ClassNode classNode) { public boolean matches(ClassNode classNode) {
return AstUtils.hasAtLeastOneFieldOrMethod(classNode, "JmsTemplate", // Slightly weird detection algorithm because there is no @Enable annotation for
"DefaultMessageListenerContainer", "SimpleMessageListenerContainer"); // Spring JMS
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableJmsMessaging");
} }
@Override @Override
@ -49,7 +52,15 @@ public class JmsCompilerAutoConfiguration extends CompilerAutoConfiguration {
public void applyImports(ImportCustomizer imports) throws CompilationFailedException { public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
imports.addStarImports("javax.jms", "org.springframework.jms.core", imports.addStarImports("javax.jms", "org.springframework.jms.core",
"org.springframework.jms.listener", "org.springframework.jms.listener",
"org.springframework.jms.listener.adapter"); "org.springframework.jms.listener.adapter")
.addImports(EnableJmsMessaging.class.getCanonicalName());
}
@Target(ElementType.TYPE)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public static @interface EnableJmsMessaging {
} }
} }

@ -111,6 +111,11 @@
<artifactId>activemq-core</artifactId> <artifactId>activemq-core</artifactId>
<version>${activemq.version}</version> <version>${activemq.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<version>${activemq.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.tomcat.embed</groupId> <groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId> <artifactId>tomcat-embed-core</artifactId>

Loading…
Cancel
Save