Browse Source
- If RabbitTemplate is on the classpath, turn on autodetection. - Create a RabbitTemplate, a Rabbit ConnectionFactory, and a RabbitAdmin is spring.rabbitmq.dynamic:true - Enable some **spring.rabbitmq** properties like host, port, username, password, and dynamic - Add tests to verify functionality - Add Groovy CLI functionality. Base it on @EnableRabbitMessaging. Add spring-amqp to the path. - Create rabbit.groovy test to prove it all works. - Make Queue and TopicExchange top-level Spring beans in rabbit.groovy test scriptpull/64/head
10 changed files with 401 additions and 5 deletions
@ -0,0 +1,140 @@
@@ -0,0 +1,140 @@
|
||||
/* |
||||
* 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 org.springframework.boot.autoconfigure.amqp; |
||||
|
||||
import org.springframework.amqp.core.AmqpAdmin; |
||||
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; |
||||
import org.springframework.amqp.rabbit.core.RabbitAdmin; |
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link RabbitTemplate}. |
||||
* |
||||
* @author Greg Turnquist |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnClass({ RabbitTemplate.class }) |
||||
@EnableConfigurationProperties |
||||
public class RabbitTemplateAutoConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnExpression("${spring.rabbitmq.dynamic:true}") |
||||
@ConditionalOnMissingBean(AmqpAdmin.class) |
||||
public AmqpAdmin amqpAdmin(CachingConnectionFactory connectionFactory) { |
||||
return new RabbitAdmin(connectionFactory); |
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnMissingBean(RabbitTemplate.class) |
||||
protected static class RabbitTemplateCreator { |
||||
|
||||
@Autowired |
||||
CachingConnectionFactory connectionFactory; |
||||
|
||||
@Bean |
||||
public RabbitTemplate rabbitTemplate() { |
||||
return new RabbitTemplate(this.connectionFactory); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnMissingBean(CachingConnectionFactory.class) |
||||
@EnableConfigurationProperties(RabbitConnectionFactoryProperties.class) |
||||
protected static class RabbitConnectionFactoryCreator { |
||||
|
||||
@Autowired |
||||
private RabbitConnectionFactoryProperties config; |
||||
|
||||
@Bean |
||||
public CachingConnectionFactory connectionFactory() { |
||||
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(this.config.getHost()); |
||||
connectionFactory.setPort(this.config.getPort()); |
||||
if (this.config.getUsername() != null) { |
||||
connectionFactory.setUsername(this.config.getUsername()); |
||||
} |
||||
if (this.config.getPassword() != null) { |
||||
connectionFactory.setPassword(this.config.getPassword()); |
||||
} |
||||
return connectionFactory; |
||||
} |
||||
} |
||||
|
||||
@ConfigurationProperties(name = "spring.rabbitmq") |
||||
public static class RabbitConnectionFactoryProperties { |
||||
|
||||
private String host = "localhost"; |
||||
|
||||
private int port = 5672; |
||||
|
||||
private String username; |
||||
|
||||
private String password; |
||||
|
||||
private boolean dynamic = true; |
||||
|
||||
public String getHost() { |
||||
return host; |
||||
} |
||||
|
||||
public void setHost(String host) { |
||||
this.host = host; |
||||
} |
||||
|
||||
public int getPort() { |
||||
return port; |
||||
} |
||||
|
||||
public void setPort(int port) { |
||||
this.port = port; |
||||
} |
||||
|
||||
public String getUsername() { |
||||
return username; |
||||
} |
||||
|
||||
public void setUsername(String username) { |
||||
this.username = username; |
||||
} |
||||
|
||||
public String getPassword() { |
||||
return password; |
||||
} |
||||
|
||||
public void setPassword(String password) { |
||||
this.password = password; |
||||
} |
||||
|
||||
public boolean isDynamic() { |
||||
return dynamic; |
||||
} |
||||
|
||||
public void setDynamic(boolean dynamic) { |
||||
this.dynamic = dynamic; |
||||
} |
||||
|
||||
} |
||||
} |
||||
@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
|
||||
/* |
||||
* 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 org.springframework.boot.autoconfigure.amqp; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.amqp.core.AmqpAdmin; |
||||
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; |
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory; |
||||
import org.springframework.amqp.rabbit.core.RabbitAdmin; |
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate; |
||||
import org.springframework.boot.TestUtils; |
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
import static junit.framework.Assert.assertEquals; |
||||
import static junit.framework.Assert.assertNotNull; |
||||
import static junit.framework.Assert.fail; |
||||
|
||||
/** |
||||
* Tests for {@link RabbitTemplateAutoConfiguration}. |
||||
* |
||||
* @author Greg Turnquist |
||||
*/ |
||||
public class RabbitTemplateAutoconfigurationTests { |
||||
|
||||
private AnnotationConfigApplicationContext context; |
||||
|
||||
@Test |
||||
public void testDefaultRabbitTemplate() { |
||||
this.context = new AnnotationConfigApplicationContext(); |
||||
this.context.register(TestConfiguration.class, RabbitTemplateAutoConfiguration.class); |
||||
this.context.refresh(); |
||||
RabbitTemplate rabbitTemplate = this.context.getBean(RabbitTemplate.class); |
||||
CachingConnectionFactory connectionFactory = this.context.getBean(CachingConnectionFactory.class); |
||||
RabbitAdmin amqpAdmin = this.context.getBean(RabbitAdmin.class); |
||||
assertNotNull(rabbitTemplate); |
||||
assertNotNull(connectionFactory); |
||||
assertNotNull(amqpAdmin); |
||||
assertEquals(rabbitTemplate.getConnectionFactory(), connectionFactory); |
||||
assertEquals(connectionFactory.getHost(), "localhost"); |
||||
} |
||||
|
||||
@Test |
||||
public void testRabbitTemplateWithOverrides() { |
||||
this.context = new AnnotationConfigApplicationContext(); |
||||
this.context.register(TestConfiguration.class, RabbitTemplateAutoConfiguration.class); |
||||
TestUtils.addEnviroment(this.context, "spring.rabbitmq.host:remote-server", |
||||
"spring.rabbitmq.port:9000", "spring.rabbitmq.username:alice", "spring.rabbitmq.password:secret"); |
||||
this.context.refresh(); |
||||
CachingConnectionFactory connectionFactory = this.context.getBean(CachingConnectionFactory.class); |
||||
assertEquals(connectionFactory.getHost(), "remote-server"); |
||||
assertEquals(connectionFactory.getPort(), 9000); |
||||
} |
||||
|
||||
@Test |
||||
public void testConnectionFactoryBackoff() { |
||||
this.context = new AnnotationConfigApplicationContext(); |
||||
this.context.register(TestConfiguration2.class, RabbitTemplateAutoConfiguration.class); |
||||
this.context.refresh(); |
||||
RabbitTemplate rabbitTemplate = this.context.getBean(RabbitTemplate.class); |
||||
CachingConnectionFactory connectionFactory = this.context.getBean(CachingConnectionFactory.class); |
||||
assertEquals(rabbitTemplate.getConnectionFactory(), connectionFactory); |
||||
assertEquals(connectionFactory.getHost(), "otherserver"); |
||||
assertEquals(connectionFactory.getPort(), 8001); |
||||
} |
||||
|
||||
@Test |
||||
public void testStaticQueues() { |
||||
this.context = new AnnotationConfigApplicationContext(); |
||||
this.context.register(TestConfiguration.class, RabbitTemplateAutoConfiguration.class); |
||||
TestUtils.addEnviroment(this.context, "spring.rabbitmq.dynamic:false"); |
||||
this.context.refresh(); |
||||
try { |
||||
this.context.getBean(AmqpAdmin.class); |
||||
fail("There should NOT be an AmqpAdmin bean when dynamic is switch to false"); |
||||
} catch (Exception e) {} |
||||
} |
||||
|
||||
@Configuration |
||||
protected static class TestConfiguration { |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
protected static class TestConfiguration2 { |
||||
@Bean |
||||
ConnectionFactory aDifferentConnectionFactory() { |
||||
return new CachingConnectionFactory("otherserver", 8001); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
package org.test |
||||
|
||||
import java.util.concurrent.CountDownLatch |
||||
|
||||
@Log |
||||
@Configuration |
||||
@EnableRabbitMessaging |
||||
class RabbitExample implements CommandLineRunner { |
||||
|
||||
private CountDownLatch latch = new CountDownLatch(1) |
||||
|
||||
@Autowired |
||||
RabbitTemplate rabbitTemplate |
||||
|
||||
private String queueName = "spring-boot" |
||||
|
||||
@Bean |
||||
Queue queue() { |
||||
new Queue(queueName, false) |
||||
} |
||||
|
||||
@Bean |
||||
TopicExchange exchange() { |
||||
new TopicExchange("spring-boot-exchange") |
||||
} |
||||
|
||||
/** |
||||
* The queue and topic exchange cannot be inlined inside this method and have |
||||
* dynamic creation with Spring AMQP work properly. |
||||
*/ |
||||
@Bean |
||||
Binding binding(Queue queue, TopicExchange exchange) { |
||||
BindingBuilder |
||||
.bind(queue) |
||||
.to(exchange) |
||||
.with("spring-boot") |
||||
} |
||||
|
||||
@Bean |
||||
SimpleMessageListenerContainer container(CachingConnectionFactory connectionFactory) { |
||||
return new SimpleMessageListenerContainer( |
||||
connectionFactory: connectionFactory, |
||||
queueNames: [queueName], |
||||
messageListener: new MessageListenerAdapter(new Receiver(latch:latch), "receive") |
||||
) |
||||
} |
||||
|
||||
void run(String... args) { |
||||
log.info "Sending RabbitMQ message..." |
||||
rabbitTemplate.convertAndSend(queueName, "Greetings from Spring Boot via RabbitMQ") |
||||
latch.await() |
||||
} |
||||
|
||||
} |
||||
|
||||
@Log |
||||
class Receiver { |
||||
CountDownLatch latch |
||||
|
||||
def receive(String message) { |
||||
log.info "Received ${message}" |
||||
latch.countDown() |
||||
} |
||||
} |
||||
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
/* |
||||
* 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 org.springframework.boot.cli.compiler.autoconfigure; |
||||
|
||||
import org.codehaus.groovy.ast.ClassNode; |
||||
import org.codehaus.groovy.control.CompilationFailedException; |
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer; |
||||
import org.springframework.boot.cli.compiler.AstUtils; |
||||
import org.springframework.boot.cli.compiler.CompilerAutoConfiguration; |
||||
import org.springframework.boot.cli.compiler.DependencyCustomizer; |
||||
|
||||
import java.lang.annotation.*; |
||||
|
||||
/** |
||||
* {@link CompilerAutoConfiguration} for Spring Rabbit. |
||||
* |
||||
* @author Greg Turnquist |
||||
*/ |
||||
public class RabbitCompilerAutoConfiguration extends CompilerAutoConfiguration { |
||||
|
||||
@Override |
||||
public boolean matches(ClassNode classNode) { |
||||
// Slightly weird detection algorithm because there is no @Enable annotation for
|
||||
// Integration
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableRabbitMessaging"); |
||||
} |
||||
|
||||
@Override |
||||
public void applyDependencies(DependencyCustomizer dependencies) |
||||
throws CompilationFailedException { |
||||
dependencies.add("org.springframework.amqp", "spring-rabbit", |
||||
dependencies.getProperty("spring-rabbit.version")); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void applyImports(ImportCustomizer imports) throws CompilationFailedException { |
||||
imports.addStarImports("org.springframework.amqp.rabbit.core", |
||||
"org.springframework.amqp.rabbit.connection", |
||||
"org.springframework.amqp.rabbit.listener", |
||||
"org.springframework.amqp.rabbit.listener.adapter", |
||||
"org.springframework.amqp.core").addImports(EnableRabbitMessaging.class.getCanonicalName()); |
||||
} |
||||
|
||||
@Target(ElementType.TYPE) |
||||
@Documented |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
public static @interface EnableRabbitMessaging { |
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
Loading…
Reference in new issue