SpringBoot整合RabbitMQ

github地址:springboot-learn

环境搭建

搭建springboot项目

自己搭建

RabbitMq安装配置

rabbitMq是用erlang写的,需要先安装erlang写到环境变量中再安装rabbitMq安装教程本文不过多解释

POM依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.2</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<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.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
        <version>1.18.4</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

YML配置

spring:
  application:
    name: spring-boot-rabbitmq
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

主要代码

RabbitConfig

配置必要的队列、交换机、路由key并绑定(binging)

  • Broker:它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输,

  • Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。

  • Queue:消息的载体,每个消息都会被投到一个或多个队列。

  • Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来.

  • Routing Key:路由关键字,exchange根据这个关键字进行消息投递。

  • vhost:虚拟主机,一个broker里可以有多个vhost,用作不同用户的权限分离。

  • Producer:消息生产者,就是投递消息的程序.

  • Consumer:消息消费者,就是接受消息的程序.

  • Channel:消息通道,在客户端的每个连接里,可建立多个channel.

@Configuration
public class RabbitConfig {
     //队列名
    public static final String FANOUT_QUEUE_NAME = "test_fanout_queue";
    public static final String FANOUT_QUEUE_NAME1 = "test_fanout_queue1";
    public static final String TEST_FANOUT_EXCHANGE = "testFanoutExchange";

    public static final String DIRECT_QUEUE_NAME = "test_direct_queue";
    public static final String TEST_DIRECT_EXCHANGE = "testDirectExchange";
    public static final String DIRECT_ROUTINGKEY = "test";

    public static final String TOPIC_QUEUE_NAME = "test_topic_queue";
    public static final String TEST_TOPIC_EXCHANGE = "testTopicExchange";
    public static final String TOPIC_ROUTINGKEY = "test.*";
}

Fanout交换机

扇形交换机,接收到消息后会将消息转发到所有队列

//创建队列
@Bean
public Queue createFanoutQueue() {
    return new Queue(FANOUT_QUEUE_NAME);
}

//创建队列
@Bean
public Queue createFanoutQueue1() {
    return new Queue(FANOUT_QUEUE_NAME1);
}

//创建交换机
@Bean
public FanoutExchange defFanoutExchange() {
    return new FanoutExchange(TEST_FANOUT_EXCHANGE);
}

//队列与交换机进行绑定
@Bean
Binding bindingFanout() {
    return BindingBuilder.bind(createFanoutQueue()).
            to(defFanoutExchange());
}

//队列与交换机进行绑定
@Bean
Binding bindingFanout1() {
    return BindingBuilder.bind(createFanoutQueue1()).
            to(defFanoutExchange());
}

Direct交换机

直连型交换机,根据消息携带的路由键,将消息转发给对应的队列

//创建队列
@Bean
public Queue createDirectQueue() {
    return new Queue(DIRECT_QUEUE_NAME);
}

@Bean
DirectExchange directExchange(){
    return new DirectExchange(TEST_DIRECT_EXCHANGE);
}

@Bean
Binding bindingDirect() {
    return BindingBuilder.bind(createDirectQueue()).
            to(directExchange()).
            with(DIRECT_ROUTINGKEY);
}

Topic交换机

主题交换机,根据消息携带的路由键和交换机与队列绑定键的规则,将消息转发给对应的队列

//创建队列
@Bean
public Queue createTopicQueue() {
    return new Queue(TOPIC_QUEUE_NAME);
}

@Bean
TopicExchange defTopicExchange(){
    return new TopicExchange(TEST_TOPIC_EXCHANGE);
}

@Bean
Binding bindingTopic() {
    return BindingBuilder.bind(createTopicQueue()).
            to(defTopicExchange()).
            with(TOPIC_ROUTINGKEY);
}

上面定义了三种类型的queue,exchange,和routingkey,预先定义,并且将队列,绑定到指定Exchange上,定义其routingKey。并使用@Bean注解定义为实体。

生产者

新建MsgProducer类作为信息发送

@Component
public class MsgProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void send2FanoutTestQueue(String massage){
        rabbitTemplate.convertAndSend(RabbitConfig.TEST_FANOUT_EXCHANGE,
                "", massage);
    }

    public void send2DirectTestQueue(String massage){
        rabbitTemplate.convertAndSend(RabbitConfig.TEST_DIRECT_EXCHANGE,
                RabbitConfig.DIRECT_ROUTINGKEY, massage);
    }

    public void send2TopicTestAQueue(String massage){
        rabbitTemplate.convertAndSend(RabbitConfig.TEST_TOPIC_EXCHANGE,
                "test.aaa", massage);
    }

    public void send2TopicTestBQueue(String massage){
        rabbitTemplate.convertAndSend(RabbitConfig.TEST_TOPIC_EXCHANGE,
                "test.bbb", massage);
    }
}

消费者

只建了一个项目,所以生产者和消费者在同一项目

@Component
@Slf4j
public class MsgConsumer {

    @RabbitListener(
            bindings =
                    {
                            @QueueBinding(value = @Queue(value = RabbitConfig.FANOUT_QUEUE_NAME, durable = "true"),
                                    exchange = @Exchange(value = RabbitConfig.TEST_FANOUT_EXCHANGE, type = "fanout"))
                    })
    @RabbitHandler
    public void processFanoutMsg(Message massage) {
        String msg = new String(massage.getBody(), StandardCharsets.UTF_8);
        log.info("received Fanout message : " + msg);
    }

    @RabbitListener(
            bindings =
                    {
                            @QueueBinding(value = @Queue(value = RabbitConfig.FANOUT_QUEUE_NAME1, durable = "true"),
                                    exchange = @Exchange(value = RabbitConfig.TEST_FANOUT_EXCHANGE, type = "fanout"))
                    })
    @RabbitHandler
    public void processFanout1Msg(Message massage) {
        String msg = new String(massage.getBody(), StandardCharsets.UTF_8);
        log.info("received Fanout1 message : " + msg);
    }

    @RabbitListener(
            bindings =
                    {
                            @QueueBinding(value = @Queue(value = RabbitConfig.DIRECT_QUEUE_NAME, durable = "true"),
                                    exchange = @Exchange(value = RabbitConfig.TEST_DIRECT_EXCHANGE),
                                    key = RabbitConfig.DIRECT_ROUTINGKEY)
                    })
    @RabbitHandler
    public void processDirectMsg(Message massage) {
        String msg = new String(massage.getBody(), StandardCharsets.UTF_8);
        log.info("received Direct message : " + msg);
    }

    @RabbitListener(
            bindings =
                    {
                            @QueueBinding(value = @Queue(value = RabbitConfig.TOPIC_QUEUE_NAME, durable = "true"),
                                    exchange = @Exchange(value = RabbitConfig.TEST_TOPIC_EXCHANGE, type = "topic"),
                                    key = RabbitConfig.TOPIC_ROUTINGKEY)
                    })
    @RabbitHandler
    public void processTopicMsg(Message massage) {
        String msg = new String(massage.getBody(), StandardCharsets.UTF_8);
        log.info("received Topic message : " + msg);
    }

}

消费者类中通过@RabbitListener@RabbitHandler注解将一个方法定义为消息监听的方法@RabbitListener可以通过定义bindings={@QueueBinding}@QueueBinding可以通过赋值value=@Queue(value = RabbitConfig.FANOUT_QUEUE_NAME, durable = "true")定义出消息队列名,@QueueBinding也可以通过赋值exchange=@Exchange(value = RabbitConfig.TEST_FANOUT_EXCHANGE, type = "fanout")来定义当前方法所监听的Exchange,以及类型,类型默认是direct.

controller

@RequestMapping("/rabbit")
@Controller
@Slf4j
public class RabbitMQController {

    @Autowired
    private MsgProducer msgProducer;

    @GetMapping(value = "/sendFanout")
    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    public void sendMsg(){
        msgProducer.send2FanoutTestQueue("this is a test fanout message!");
    }

    @GetMapping(value = "/sendDirect")
    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    public void sendDirectMsg(){
        msgProducer.send2DirectTestQueue("this is a test direct message!");
    }

    @GetMapping(value = "/sendDirectA")
    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    public void sendTopicAMsg(){
        msgProducer.send2TopicTestAQueue("this is a test topic aaa message!");
    }

    @GetMapping(value = "/sendTopicB")
    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    public void sendTopicBMsg(){
        msgProducer.send2TopicTestBQueue("this is a test topic bbb message!");
    }
}

测试

访问 fanout - http://localhost:8080/rabbit/sendFanout

​ direct - http://localhost:8080/rabbit/sendDirect

​ - http://localhost:8080/rabbit/sendDirectA

​ topic - http://localhost:8080/rabbit/sendTopicB

不使用YML来配置RabbitMQ

将yml文件中的tabbitmq注释

创建rabbitmq.properties

# rabbitmq配置
rabbit.host = localhost
rabbit.port = 5672
rabbit.userName = guest
rabbit.passWord = guest

RabbitMQ实体类库

@Data
@Component
@ConfigurationProperties(prefix = "rabbit")
@PropertySource("classpath:rabbitmq.properties")
public class User {

    private String host;
    private Integer port;
    private String userName;
    private String passWord;
}

关于上面注解可以看springboot基础配置

配置类

@Autowired
private User user;

@Bean
public ConnectionFactory factory() {
    CachingConnectionFactory factory = new CachingConnectionFactory();
    factory.setHost(user.getHost());
    factory.setPort(user.getPort());
    factory.setUsername(user.getUserName());
    factory.setPassword(user.getPassWord());
    return factory;
}

@Bean
public AmqpAdmin amqpAdmin() {
    return new RabbitAdmin(factory());
}

@Bean
public RabbitTemplate rabbitTemplate() {
    return new RabbitTemplate(factory());
}

/**
 * 可视化
 * @param factory
 * @return
 */
@Bean
public SimpleMessageListenerContainer container(ConnectionFactory factory) {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(factory);
    container.setConsumerTagStrategy(new ConsumerTagStrategy() {
        @Override
        public String createConsumerTag(String s) {
            return null;
        }
    });
    return container ;
}

需要加上@Configuration注解

posted @ 2021-02-20 14:42  zcb_bai  阅读(120)  评论(0编辑  收藏  举报