RabbitMQ的Java应用(3) -- 使用spring-boot-starter-amqp开发生产者应用

本文详细介绍了如何使用Spring Boot的spring-boot-starter-amqp库开发RabbitMQ生产者应用,包括使用AsyncRabbitTemplate实现异步消息发送、BatchingRabbitTemplate批量发送消息、RabbitMQ注解简化应用代码以及对象类型消息的发送。通过实例展示了各种场景下的消息处理策略,帮助读者理解如何高效地使用Spring AMQP进行消息通信。
摘要由CSDN通过智能技术生成

上一篇我们介绍了如何使用Spring AMQP和RabbitMQ结合,开发消费者应用程序,使用的是Xml配置的Spring框架。

本篇我们仍然使用Spring AMQP开发生产者应用,不过我们使用零 XML配置的Spring Boot环境进行开发,使用的库是spring-boot-starter-amqp库。

使用Spring-boot-starter-amqp搭建框架

我们使用Spring Boot 1.4.3 RELEASE版本,pom.xml文件内容如下:

<?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>
 
    <groupId>com.example</groupId>
    <artifactId>SpringMQProducer</artifactId>
    <version>0.1.0</version>
    <packaging>jar</packaging>
 
    <name>SpringMQProducer</name>
    <description>The MQ producer in spring boot environment</description>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.3.RELEASE</version>
        <relativePath/>
    </parent>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

需要注意的是,当使用spring-boot-configuration-processor库时会默认打开RabbitAutoConfiguration,它会自动创建一个 CachingConnectionFactory对象,一个RabbitTemplate对象,一个AmqpAdmin对象以及一个RabbitMessageTemplate对象。

@Configuration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
   	@Configuration
	@ConditionalOnMissingBean(ConnectionFactory.class)
	protected static class RabbitConnectionFactoryCreator {
		@Bean
		public CachingConnectionFactory rabbitConnectionFactory(RabbitProperties config)
                {
                 ........
 
        @Configuration
	@Import(RabbitConnectionFactoryCreator.class)
	protected static class RabbitTemplateConfiguration {
           @Bean
	   @ConditionalOnSingleCandidate(ConnectionFactory.class)
	   @ConditionalOnMissingBean(RabbitTemplate.class)
	   public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
           ........
 
        @Bean
	@ConditionalOnSingleCandidate(ConnectionFactory.class)
	@ConditionalOnProperty(prefix = "spring.rabbitmq", name = "dynamic", matchIfMissing = true)
	@ConditionalOnMissingBean(AmqpAdmin.class)
	public AmqpAdmin amqpAdmin(ConnectionFactory connectionFactory) {
		return new RabbitAdmin(connectionFactory);
	}
 
        .......
        @Configuration
	@ConditionalOnClass(RabbitMessagingTemplate.class)
	@ConditionalOnMissingBean(RabbitMessagingTemplate.class)
	@Import(RabbitTemplateConfiguration.class)
	protected static class MessagingTemplateConfiguration {
 
	@Bean
	@ConditionalOnSingleCandidate(RabbitTemplate.class)
	public RabbitMessagingTemplate rabbitMessagingTemplate(
			RabbitTemplate rabbitTemplate) {
		return new RabbitMessagingTemplate(rabbitTemplate);
	}

如果我们想定制自己的ConnectionFactory,RabbitTemplate等对象,建议在Configuration中将其禁用:





@Configuration
@ComponentScan("com.qf.rabbitmq")
@EnableAutoConfiguration(exclude = RabbitAutoConfiguration.class)
@SpringBootApplication
public class SpringMqProducerApplication {
 
	public static void main(String[] args) {
		SpringApplication.run(SpringMqProducerApplication.class, args);
	}
}

在src/main/resources目录下创建application.properties文件,添加rabbitmq相关设置,以spring.rabbitmq为前缀,这样它会自动映射到RabbitProperties配置类
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=rabbitmq_producer
spring.rabbitmq.password=123456
spring.rabbitmq.virtualHost=test_vhosts

添加RabbitConfig类,用于创建自定义ConnectionFactory,RabbitAdmin,RabbitTemplate等。 这个类头部如下所示
@Configuration
@EnableConfigurationProperties(RabbitProperties.class)
public class RabbitConfig
{
    @Autowired
    private RabbitProperties rabbitProperties;

这里用到了org.springframework.boot.autoconfigure.amqp.RabbitProperties类,记录application.properties中的RabbitMQ连接设置。

再创建ConnectionFactory:

@Bean("connectionFactory")
 public ConnectionFactory getConnectionFactory() {
        com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory =
                new com.rabbitmq.client.ConnectionFactory();
        rabbitConnectionFactory.setHost(rabbitProperties.getHost());
        rabbitConnectionFactory.setPort(rabbitProperties.getPort());
        rabbitConnectionFactory.setUsername(rabbitProperties.getUsername());
        rabbitConnectionFactory.setPassword(rabbitProperties.getPassword());
        rabbitConnectionFactory.setVirtualHost(rabbitProperties.getVirtualHost());
 
        ConnectionFactory connectionFactory = new CachingConnectionFactory(rabbitConnectionFactory);
        return connectionFactory;
 }
这里可以像消费者应用里提到的那样,设置CacheMode和最大缓存数,我们这里暂不设置。 再创建RabbitAdmin对象

@Bean(name="rabbitAdmin")
public RabbitAdmin getRabbitAdmin()
{
    RabbitAdmin rabbitAdmin = new RabbitAdmin(getConnectionFactory());
    rabbitAdmin.setAutoStartup(true);
    return rabbitAdmin;
}
定义MessageConverter和MessagePropertiesConverter对象

@Bean(name="serializerMessageConverter")
public MessageConverter getMessageConverter(){
        return new SimpleMessageConverter();
}
 
@Bean(name="messagePropertiesConverter")
public MessagePropertiesConverter getMessagePropertiesConverter()
{
    return new DefaultMessagePropertiesConverter();
}
定义发送消息所用的RabbitTemplate对象,由于我们的场景要求发送之后立即从消费者处获得返回消息,因此我们在RabbitTemplate对象中设置了ReplyAddress,而且在下面的MessageListenerContainer中将这个对象作为Listener设置到Container中。

@Bean(name="rabbitTemplate")
public RabbitTemplate getRabbitTemplate()
{
   RabbitTemplate rabbitTemplate = new RabbitTemplate(getConnectionFactory());
   rabbitTemplate.setUseTemporaryReplyQueues(false);
   rabbitTemplate.setMessageConverter(getMessageConverter());
   rabbitTemplate.setMessagePropertiesConverter(getMessagePropertiesConverter());
   rabbitTemplate.setReplyAddress(AppConstants.REPLY_QUEUE_NAME);
   rabbitTemplate.setReceiveTimeout(60000);
   return rabbitTemplate;
}
使用RabbitAdmin对象定义发送消息Exchange/Queue/Binding,返回消息Exchange/Queue/Binding对象,如果它们在RabbitMQ中已经存在,下面的定义代码可以省略.这里的Exchange/Queue名称和前面的消费者应用使用的相同。

@Bean(name="springMessageQueue")    
public Queue createQueue(@Qualifier("rabbitAdmin")RabbitAdmin rabbitAdmin)
{
    Queue sendQueue = new Queue(AppConstants.SEND_QUEUE_NAME,true,false,false);
    rabbitAdmin.declareQueue(sendQueue);
    return sendQueue;
}
 
@Bean(name="springMessageExchange")
public Exchange createExchange(@Qualifier("rabbitAdmin")RabbitAdmin rabbitAdmin)
{
    DirectExchange sendExchange = new DirectExchange(AppConstants.SEND_EXCHANGE_NAME,true,false);
    rabbitAdmin.declareExchange(sendExchange);
    return sendExchange;
}
 
@Bean(name="springMessageBinding")
public Binding createMessageBinding(@Qualifier("rabbitAdmin")RabbitAdmin rabbitAdmin)
{
    Map<String,Object> arguments = new HashMap<String,Object>();
    Binding sendMessageBinding =
            new Binding(AppConstants.SEND_QUEUE_NAME, Binding.DestinationType.QUEUE,
                        AppConstants.SEND_EXCHANGE_NAME, AppConstants.SEND_MESSAGE_KEY, arguments);
    rabbitAdmin.declareBinding(sendMessageBinding);
    return sendMessageBinding;
}
 
@Bean(name="springReplyMessageQueue")
public Queue createReplyQueue(@Qualifier("rabbitAdmin")RabbitAdmin rabbitAdmin)
{
    Queue replyQueue = new Queue(AppConstants.REPLY_QUEUE_NAME,true,false,false);
    rabbitAdmin.declareQueue(replyQueue);
    return replyQueue;
}
 
@Bean(name="springReplyMessageExchange")
public Exchange createReplyExchange(@Qualifier("rabbitAdmin")RabbitAdmin rabbitAdmin)
{
    DirectExchange replyExchange = new DirectExchange(AppConstants.REPLY_EXCHANGE_NAME,true,false);
    rabbitAdmin.declareExchange(replyExchange);
    return replyExchange;
}
 
@Bean(name="springReplyMessageBinding")
public Binding createReplyMessageBinding(@Qualifier("rabbitAdmin")RabbitAdmin rabbitAdmin)
{
    Map<String,Object> arguments = new HashMap<String,Object>();
    Binding replyMessageBinding =
            new Binding(AppConstants.REPLY_QUEUE_NAME, Binding.DestinationType.QUEUE,
                        AppConstants.REPLY_EXCHANGE_NAME, AppConstants.REPLY_MESSAGE_KEY, arguments);
    rabbitAdmin.declareBinding(replyMessageBinding);
    return replyMessageBinding;
}
最后定义接收返回消息的Message Listener Container,这里的Listener属性设置的是上面创建的RabbitTemplate对象。

@Bean(name="replyMessageListenerContainer")
public SimpleMessageListenerContainer createReplyListenerContainer() {
     SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer();
     listenerContainer.setConnectionFactory(getConnectionFactory());
     listenerContainer.setQueueNames(AppConstants.REPLY_QUEUE_NAME);
     listenerContainer.setMessageConverter(getMessageConverter());
     listenerContainer.setMessageListener(getRabbitTemplate());
     listenerContainer.setRabbitAdmin(getRabbitAdmin());
     listenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);
     return listenerContainer;
}
我们还定义了一个ThreadPoolExecutor对象,用于RabbitTemplate异步执行,发送和接收消息使用。
@Bean(name="threadExecutor")
public ThreadPoolTaskExecutor createThreadPoolTaskExecutor()
{
    ThreadPoolTaskExecutor threadPoolTaskExecutor =
            new ThreadPoolTaskExecutor();
    threadPoolTaskExecutor.setCorePoolSize(5);
    threadPoolTaskExecutor.setMaxPoolSize(10);
    threadPoolTaskExecutor.setQueueCapacity(200);
    threadPoolTaskExecutor.setKeepAliveSeconds(20000);
    return threadPoolTaskExecutor;
}

我们的生产者-消费者场景是系列1中提到的RPC方式计算阶乘,使用Rest接口调用生产者应用,生产者应用发送消息给消费者应用,计算出阶乘结果返回给生产者。 
为了实现这个场景,我们先在生产者程序中定义用于发送请求消息和接收返回消息的服务接口SendMessageService和它的实现类SendMessageServiceImpl类。
public interface SendMessageService
{
    String sendMessage(String message);
}
 
@Service("sendMessageService")
public class SendMessageServiceImpl implements SendMessageService
{
    @Autowired
    private ThreadPoolTaskExecutor executor;
 
    public String sendMessage(String message)
    {
        CompletableFuture<String> resultCompletableFuture =
                CompletableFuture.supplyAsync(new MQSenderSupplier(message), executor);
        try
        {
            String result = resultCompletableFuture.get();
            return result;
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        catch (ExecutionException e)
        {
            e.printStackTrace();
        }
        return null;
    }
}
在实现类中,我们将发送请求消息和接收返回消息交给一个Supplier对象(JDK 1.8引入)在后台线程池中异步执行,我们自定义了MQSenderSupplier类,实现了发送请求和接收返回消息的操作。
public class  MQSenderSupplier implements Supplier<String> {
 
    private String message;
 
    public MQSenderSupplier(String message)
    {
        this.message = message;
    }
 
    public String get()
    {
        Date sendTime = new Date();
        String correlationId = UUID.randomUUID().toString();
 
        MessagePropertiesConverter messagePropertiesConverter =
                (MessagePropertiesConverter) ApplicationContextUtil.getBean("messagePropertiesConverter");
 
        RabbitTemplate rabbitTemplate =
                 (RabbitTemplate)ApplicationContextUtil.getBean("rabbitTemplate");
 
        AMQP.Basic
eue)和绑定(Binding)的配置。以下是示例代码: ``` @Configuration public class RabbitMQConfig { // 定义交换器名称 public static final String EXCHANGE_NAME = "my_exchange"; // 定义队列名称 public static final String SMS_QUEUE_NAME = "sms_queue"; public static final String EMAIL_QUEUE_NAME = "email_queue"; // 定义路由键 public static final String SMS_ROUTING_KEY = "sms"; public static final String EMAIL_ROUTING_KEY = "email"; // 配置交换器 @Bean public DirectExchange directExchange() { return new DirectExchange(EXCHANGE_NAME); } // 配置短信队列 @Bean public Queue smsQueue() { return new Queue(SMS_QUEUE_NAME); } // 配置邮件队列 @Bean public Queue emailQueue() { return new Queue(EMAIL_QUEUE_NAME); } // 配置短信队列绑定 @Bean public Binding smsBinding() { return BindingBuilder.bind(smsQueue()).to(directExchange()).with(SMS_ROUTING_KEY); } // 配置邮件队列绑定 @Bean public Binding emailBinding() { return BindingBuilder.bind(emailQueue()).to(directExchange()).with(EMAIL_ROUTING_KEY); } } ``` 在上述代码中,我们使用了Direct交换器,定义了sms_queue和email_queue两个队列,以及sms和email两个路由键。我们还通过@Bean注解将它们配置到Spring容器中。 接下来,我们需要在application.properties中添加RabbitMQ连接配置: ``` spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=guest ``` 最后,我们需要实现一个消息生产者Controller,示例代码如下: ``` @RestController public class MessageController { @Autowired private AmqpTemplate amqpTemplate; @GetMapping("/sendSms") public String sendSms() { String message = "Hello, this is a SMS message!"; amqpTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, RabbitMQConfig.SMS_ROUTING_KEY, message); return "Send SMS message: " + message; } @GetMapping("/sendEmail") public String sendEmail() { String message = "Hello, this is an email message!"; amqpTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, RabbitMQConfig.EMAIL_ROUTING_KEY, message); return "Send email message: " + message; } } ``` 在上述代码中,我们使用AmqpTemplate接口的convertAndSend方法将消息发送到RabbitMQ中。通过访问/sendSms和/sendEmail接口,我们可以向sms_queue和email_queue发送消息。 以上就是一个简单的Spring Boot + RabbitMQ消息生产者的实现。希望对你有所帮助!
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值