SpringBoot与消息

我与影子孤独终老i 提交于 2020-02-07 03:05:15

消息服务的两个重要概念:
1.消息代理
2.目的地
目的地有两种:
a.队列:点对点消息通信:消息只有唯一的发送者和接受者,但不是只有一个接收者,也就是说发送者发送的消息可以被多个接收者接收,但信息被其中一个接收者接受后,其他接收者不可接受。
b.主题:发布/订阅消息通信:发送者将消息发送到主题,这个主题的所有订阅者会在消息到达时同时接收到消息。
当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地。

消息规范:
1.JMS Java消息服务,不能跨平台、跨语言,实现:ActiveMQ、HornetMQ
2.AMQP 高级消息队列协议,实现:RabbitMQ

Spring支持:
1.spring-jms提供了对JMS的支持;spring-rabbit提供了对AMQP的支持
2.需要ConnectionFactory的实现来连接消息代理
3.提供JmsTemplate、RabbitTemplate来发送消息
4.@JmsListener、@RabbitListener注解在方法上监听消息代理发布的消息
5.@EnableJms、@EnableRabbit开启支持
6.JmsAutoConfiguration、RabbitAutoConfiguration自动配置

  • RabbitMQ
  • Exchange类型:
    四种类型:direct、fanout、topic、header(header用的很少且性能差)。

    direct:点对点通信,根据路由键匹配,完全符合bind规则才进行发送
    fanout:广播
    topic:可以对路由键进行模糊匹配,以单词为单位,单词之间用"."隔开。可使用的通配符为:符号#:匹配0个或多个单词;符号*:匹配一个单词

    rabbitmq端口:5672 管理界面端口:15672

    创建一个消息交换器和队列绑定:
    1.首先创建exchange,type选择exchange的类型,durability选择可持续化,durable为持久化即重启rabbitmq仍保留
    2.然后创建queue
    3.点击创建的exchange进行绑定,填绑定的queue和路由键

    Springboot使用rabbitmq:
    1.依赖:

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

    2.配置:

    spring.rabbitmq.host=localhost
    spring.rabbitmq.username=guest
    spring.rabbitmq.password=guest
    #如果不配置端口和virtual——host,默认端口就是5672,默认virtual-host是"/"
    spring.rabbitmq.port=5672 
    spring.rabbitmq.virtual-host=/
    

    3.发送消息:

  • direct
  • Message(消息头+消息体)需要自己构造序列化

    rabbitTemplate.send(exchange,routekey,messsage);
    

    不想构造Message(消息头+消息体),可以使用

    rabbitTemplate.convertAndSend(exchange,routekey,object);
    

    该方法自动序列化object,并发送
    示例:

    @Test
    void sendTest01() {
        Map<String,Object> map=new HashMap<>();
        map.put("msg","这是第一个消息");
        map.put("data", Arrays.asList("helloworld",123,true));
        //发送消息
        //对象被默认序列化后发送出去
        //exchange.directtest为交换器的名称;test为路由键
        rabbitTemplate.convertAndSend("exchange.directtest","test",map);
    }
    

    如果想用json串进行序列化的方式进行消息发送可添加配置类进行配置:

    @Configuration
    public class MyAMQPConfig {
    
        @Bean
        public MessageConverter messageConverter(){
            return new Jackson2JsonMessageConverter();
        }
    }
    
  • fanout
  • 示例:

    @Test
    void sendTest02() {
        Map<String,Object> map=new HashMap<>();
        map.put("msg","这是第二个消息");
        map.put("data", Arrays.asList("fanout",123,true));
        //发送消息
        //fanout不需要写路由键
        //对象被默认序列化后发送出去
        rabbitTemplate.convertAndSend("exchange.fanout","",map);
    }
    
  • topic
  • 跟direct一样,只是接收方根据路由键和绑定规则进行模糊匹配,示例:

    @Test
    void sendTest03() {
        Map<String,Object> map=new HashMap<>();
        map.put("msg","这是第三个消息");
        map.put("data", Arrays.asList("topic",123,true));
        //发送消息
        //对象被默认序列化后发送出去
        rabbitTemplate.convertAndSend("exchange.topic","test.news",map);
    }
    

    4.接收消息:
    得到的是Message格式的数据(消息头+消息体)

    rabbitTemplate.receive(queues);
    

    得到的是对象(消息体转成的对象)

    rabbitTemplate.receiveAndConvert(queues);
    

    示例:

    @Test
    void receiveTest01() {
        //接收消息,一个接收者接受数据后,队列中就没有了
        //test为路由键
        Object obj = rabbitTemplate.receiveAndConvert("test");
    }
    

    5.监听:
    需要在启动项开启注释@EnableRabbit
    然后配置server类
    监听Object类型的信息的示例:

    @Service
    public class TestService {
    
      @RabbitListener(queues = "test.news")
      public void receive01(Map map){
          System.out.println("收到消息"+map);
      }
    }
    

    监听Message类型的信息的示例:

    @Service
    public class TestService {
    
      @RabbitListener(queues = "test.news")
      public void receive02(Message msg){
          System.out.println(msg.getBody());
          System.out.println(msg.getMessageProperties());
      }
    }
    

    6.通过AmqpAdmin组件管理Queue、Exchange、Binding
    创建Exchange示例:

    @Test
    public void createExchange(){
        amqpAdmin.declareExchange(new DirectExchange("exchange.adqpadmin.direct"));
        amqpAdmin.declareExchange(new FanoutExchange("exchange.adqpadmin.fanout"));
        amqpAdmin.declareExchange(new TopicExchange("exchange.adqpadmin.topic"));
    }
    

    创建Queue示例:

    @Test
    public void createQueue(){
        amqpAdmin.declareQueue(new Queue("amqp.queue",true));
    }
    

    创建Binding示例:

    //new Binding(String destination, DestinationType type, String exchange, String routekey, Map<String,Object> arguments)
    //destination是队列名
    @Test
    public void createBinding(){
        amqpAdmin.declareBinding(new Binding("amqp.queue", Binding.DestinationType.QUEUE,"exchange.adqpadmin","amqp.test",null));
    }
    

    topic的Binding示例:

    @Test
    public void createBindingtopic(){
        amqpAdmin.declareBinding(new Binding("amqp.queue", Binding.DestinationType.QUEUE,"exchange.adqpadmin.topic","amqp.*",null));
    }
    
    易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
    该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!