SpringBoot项目实战--RabbitMQ

1、在pom.xml文件中添加以下依赖:

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2、在 application.properties文件中添加配置信息:

spring.rabbitmq.username=XXX
spring.rabbitmq.password=XXX
spring.rabbitmq.virtualHost=XXX
spring.rabbitmq.addresses=ip:port,ip:port
或者从第三方配置信息中读取:

/**
 *
 */
import com.sohu.sns.manager.util.JsonMapper;
import org.apache.commons.lang3.StringUtils;

import java.util.Map;

/**
 * mq连接配置
 */
public class AmqpInit {
	private static final JsonMapper jsonMapper = JsonMapper.nonEmptyMapper();
	public static void init() {
		try {
			String mqConfig = ZooKeeperInit.getData("/mq.properties");
			if (StringUtils.isEmpty(mqConfig)) {
				throw new Exception("mq.properties is not found in zk.");
			} else {
				Map<String,Object> configMap = jsonMapper.fromJson(mqConfig,Map.class);
				//初始化ConnectionFactory需要参数
				System.setProperty("spring.rabbitmq.username", configMap.get("user_name").toString());
				System.setProperty("spring.rabbitmq.password", configMap.get("pwd").toString());
				System.setProperty("spring.rabbitmq.virtualHost", configMap.get("virtual_host").toString());
				System.setProperty("spring.rabbitmq.addresses", configMap.get("hosts").toString());

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

才用此种配置时在服务启动时需要初始化信息。

更多配置参考配置类信息:

@ConfigurationProperties(
    prefix = "spring.rabbitmq"
)
public class RabbitProperties {
    private String host = "localhost";
    private int port = 5672;
    private String username;
    private String password;
    private final RabbitProperties.Ssl ssl = new RabbitProperties.Ssl();
    private String virtualHost;
    private String addresses;
    private Integer requestedHeartbeat;
}


3、添加mq配置信息:

import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;

@Configuration
public class AmqpConfig {
    @Bean
    public RabbitMessagingTemplate rabbitMessagingTemplate(RabbitTemplate rabbitTemplate) {
        RabbitMessagingTemplate rabbitMessagingTemplate = new RabbitMessagingTemplate();
        rabbitMessagingTemplate.setMessageConverter(jackson2Converter());
        rabbitMessagingTemplate.setRabbitTemplate(rabbitTemplate);
        return rabbitMessagingTemplate;
    }
    @Bean
    public MappingJackson2MessageConverter jackson2Converter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        return converter;
    }

}

由于我在项目中需要往多个实例中发送消息,所以采用Fanout Exchange 类型,在生产中发送消息无需进行其他配置,发送消息代码如下:

@Service
public class SendMessageServiceImpl implements SendMessageService{
    private static final JsonMapper jsonMapper = JsonMapper.nonEmptyMapper();
    private static Logger log = LoggerFactory.getLogger(SendMessageServiceImpl.class);
    @Autowired
    private RabbitTemplate rabbitMessagingTemplate;
    @Override
    public void sendMessageToMQ(String modelType, String operateType, Object data) {
        Map<String,Object> mqDataMap = Maps.newConcurrentMap();
        mqDataMap.put("modelType",modelType);
        mqDataMap.put("operateType",operateType);
        mqDataMap.put("data",data);
        String exchangeName = System.getProperties().get("spring.rabbitmq.exchange_name").toString();
        String message = jsonMapper.toJson(mqDataMap);
        log.info("send message to mq..........."+message);
        rabbitMessagingTemplate.convertAndSend(exchangeName,null,message);
    }
}
只需要把消息发送到指定名称的交换机中即可。
4、消费者配置:

添加mq服务器配置信息,同生产者配置。

添加消费配置:

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by zhangnan on 2016/12/22.
 */
@Configuration
public class AmqpConfig{
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }
    @Bean
    public Queue mqQueue(RabbitAdmin rabbitAdmin) {
        String queueName = System.getProperties().get("spring.rabbitmq.queue").toString();
        Queue queue = new Queue(queueName,true);
        rabbitAdmin.declareQueue(queue);
        return queue;
    }

    @Bean
    public FanoutExchange mqExchange(RabbitAdmin rabbitAdmin) {
        String exchangeName = System.getProperties().get("spring.rabbitmq.exchange_name").toString();
        //将消息分发到所有的绑定队列,无routingkey的概念
        FanoutExchange exchange = new FanoutExchange(exchangeName);
        rabbitAdmin.declareExchange(exchange);
        return exchange;
    }
    @Bean
    public Binding mqBinding(RabbitAdmin rabbitAdmin) {
        return BindingBuilder.bind(mqQueue(rabbitAdmin)).to(mqExchange(rabbitAdmin));
    }
}
声明交换路由和队列,并且把队列和交换路由进行绑定。

消费消息:

@Service
public class ReceiverMessageServiceImpl {
    private static final JsonMapper jsonMapper = JsonMapper.nonEmptyMapper();
    private static Logger log = LoggerFactory.getLogger(ReceiverMessageServiceImpl.class);
    @RabbitListener(queues = "${spring.rabbitmq.queue}")
    @RabbitHandler
    public void receiveQueue(String message) {
        log.info("receiver message from mq........"+message);
        
    }
}
由于在初始化配置信息时:spring.rabbitmq.queue采用的是一下配置:

System.setProperty("spring.rabbitmq.queue", configMap.get("queue_name").toString()+ InetAddress.getLocalHost());
所以可以实现,每个实例的声明的队列是不一样的,实现消息的广播发送到每个队列中。接收消息也非常简单,只需要添加两个注解,监控指定的队列就可以了,再有消息到达时,就可以消费信息。

5、遇到的问题:

在发送消息时,我刚开始采用的监听的模式,在需要发送消息的地方抛出监听事件,在监听中发送消息mq队列中,在实际测试后发现消息会重复发送,后来废弃这种方式,采用现有的在Service中直接发送消息,重复发送消息的问题解决。

@Component
public class EventListener implements ApplicationListener{
    private static Logger log = LoggerFactory.getLogger(EventListener.class);
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {

    }
}











  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值