springcloud的消息驱动-stream

知识共享许可协议 版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

目录

一:消息驱动

二:搭建简单的消息发送-接受者

三:消息分组

四:指定消息接收

五:消息返回

六:动态消息通道绑定


一:消息驱动

  前面几章,我们说完了cloud的基本组件。下面我们就聊聊cloud的一些非必须但是重要的组件。第一个组件就是springcloud stream。stream是基于kafka或者rabbitmq的构建于Spring Integration的消息机制的应用。简而言之,就是封装了kafka或者rabbitmq中间组件的消息层应用。几个重要的概念:

   ~Binder:这是个抽象概念,我更愿意叫其消息绑定器。在stream中,就是通过其来外观表现通道管理和组件类型

  ~Publish-Subscribe:消息的驱动方式。在这里,我们不需要去在意其消息件的实现,独立创建一个通道,将消息发送到通道中,

                                        发送给全部或者指定的部分。

  ~Consumer Groups:消息分组,这其实是kafka中的概念,只不过在stream中扩展了rabbitmq中概念。

  ~Durability:消息选择持久化

  ~Bindings:stream的绑定,将消息中间件和stream的配置器连接起来,对内封装。

二:搭建简单的消息发送-接受者

1.消息发送者(生产者)

  (1)aoolication.yml

spring:
  application:
    name: provider-demo
  cloud:
    stream:
      binders:
        test:
          type: rabbit                        ###声明消息组件类型
          environment:
            spring:
              rabbitmq:                       ###消息链接
                addresses: 127.0.0.1
                port: 5672
                username: guest
                password: guest
               
      bindings:
        testOutPut:                               ###声明消息通道,注意这里声明一定后面的代码中一定是这个通道名称
          destination: testRabbit
          content-type: application/json
          default-binder: test

server:
  port: 8079



   (2)消息通道和消息发送

package springcloud.stream.mq;

import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;

/**
 * 消息通道设计
 *
 *
 * @author monxz
 *
 * @date 2019年6月20日
 */
public interface  MqMessageSource {

    String TEST_OUT_PUT = "testOutPut";   //这里的名称和yml配置中的声明一致

    @Output(TEST_OUT_PUT)
    MessageChannel testOutPut();

}
package springcloud.stream.mq;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;

/**
 * 
 *消息发送
 *
 * @author monxz
 *
 * @date 2019年6月20日
 */
@EnableBinding(MqMessageSource.class)
public class MqMessageProducer {
    @Autowired
    @Output(MqMessageSource.TEST_OUT_PUT)
    private MessageChannel channel;


    public void sendMsg(String msg) {
        channel.send(MessageBuilder.withPayload(msg).build());
        System.err.println("消息发送成功00:"+msg);
    }
    
  
}

  (3)Controller实现消息发送

package springcloud.stream.controller;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import springcloud.stream.domain.User;
import springcloud.stream.mq.MqMessageProducer;

@RestController
@RequestMapping("/user")
public class UserController {
	
    @Autowired
    private MqMessageProducer mqMessageProducer;


  
    @GetMapping(value = "/testMq")
    public String testMq(@RequestParam("msg")String msg){
    	mqMessageProducer.sendMsg(msg);
    	
        
        return "发送成功";
    }
}

2.消息接受者(消费者)

 (1)application.yml

  

spring:
  application:
    name: consumer-demo
  cloud:
    stream:
      binders:
        test:
          type: rabbit
          environment:
            spring:
              rabbitmq:
                addresses: 127.0.0.1
                port: 5672
                username: guest
                password: guest

      bindings:
        testInPut:              ###接受者通道名称
          destination: testRabbit
          content-type: application/json
          default-binder: test
                  
  
server:
  port: 8089

  (2)消息接收

   

/**
 * 消息接收通道
 *
 *
 * @author monxz
 *
 * @date 2019年6月20日
 */
public interface  MqMessageSource {

    String TEST_IN_PUT = "testInPut";

    @Input(TEST_IN_PUT)
    SubscribableChannel testInPut();

}/**
 * 消息接收通道
 *
 *
 * @author monxz
 *
 * @date 2019年6月20日
 */
public interface  MqMessageSource {

    String TEST_IN_PUT = "testInPut";

    @Input(TEST_IN_PUT)
    SubscribableChannel testInPut();

}

  

package cn.org.zhixiang.mq;

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;

/**
 * 消息接收
 *
 *
 * @author monxz
 *
 * @date 2019年6月20日
 */

@EnableBinding(MqMessageSource.class)
public class MqMessageConsumer {
    @StreamListener(MqMessageSource.TEST_IN_PUT)
    public void messageInPut(Message<String> message) {
        System.err.println(" 消息(01)接收成功:" + message.getPayload());
    }

}

三:消息分组

 说明:上述中实现了消息传递是一种临时的,而在我们需要持久化是和分组时。

 (1)消息生产者(同上一样)

(2)消息消费者(除了yml配置有点不一样)

      

spring:
  application:
    name: consumer-demo
  cloud:
    stream:
      binders:
        test:
          type: rabbit
          environment:
            spring:
              rabbitmq:
                addresses: 127.0.0.1
                port: 5672
                username: guest
                password: guest

      bindings:
        testInPut:
          destination: testRabbit
          content-type: application/json
          default-binder: test 
          group:  group2            ###新增分组
     

       
         
server:
  port: 8090

复制客户端4分,分成2各组,测试发现一个组只能有一个接收消息

四:指定消息接收

 说明:指定消息接受者

 1.消息生产者

    (1)yml配置

spring:
  application:
    name: provider-demo
  cloud:
    stream:
      binders:
        test:
          type: rabbit
          environment:
            spring:
              rabbitmq:
                addresses: 127.0.0.1
                port: 5672
                username: guest
                password: guest
               
      bindings:
        testOutPut:
          destination: testRabbit
          content-type: application/json
          default-binder: test
          producer:                                               #添加消息指定
            partitionKeyExpression: headers['partitionKey']       #头部设定 partitionKey 属性
            partitionCount: 2                                     #个数

server:
  port: 8079



 (2)消息发送中配置

package springcloud.stream.mq;

import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;


public interface  MqMessageSource {

    String TEST_OUT_PUT = "testOutPut";

    @Output(TEST_OUT_PUT)
    MessageChannel testOutPut();

}
package springcloud.stream.mq;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;


@EnableBinding(MqMessageSource.class)
public class MqMessageProducer {
    @Autowired
    @Output(MqMessageSource.TEST_OUT_PUT)
    private MessageChannel channel;

  
    public void sendMsg(String msg,Integer parkey) {
        channel.send(MessageBuilder.withPayload(msg).setHeader("partitionKey", parkey).build()); //配置属性
        System.err.println("消息发送成功00:"+msg);
    }
    
  
}

(3).controller

  

package springcloud.stream.controller;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import springcloud.stream.domain.User;
import springcloud.stream.mq.MqMessageProducer;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private MqMessageProducer mqMessageProducer;


 
    @GetMapping(value = "/testMq")
    public String testMq(@RequestParam("msg")String msg,@RequestParam("partitionKey")Integer partitionKey){
    	mqMessageProducer.sendMsg(msg,partitionKey);
    	
        
        return "发送成功";
    }
}

2.消息接受者

spring:
  application:
    name: consumer-demo
  cloud:
    stream:
      binders:
        test:
          type: rabbit
          environment:
            spring:
              rabbitmq:
                addresses: 127.0.0.1
                port: 5672
                username: guest
                password: guest

      bindings:
        testInPut:
          destination: testRabbit
          content-type: application/json
          default-binder: test
          consumer:
            partitioned: true              #消息接收
      instance-count: 2                    #个数 
      instance-index: 1                    #索引
server:
  port: 8092

  其他没变。注意服务端的partitionKey属性对应着 instance-index的值

五:消息返回

说明:消息接收完成返回给服务端接收完成

 1.生产者:这里其实消息生产者就变成了变成上面的消息接受者

	
	/**
    *消息接受者,返回客户端
	 * 接收到消息并且返回
	 * @param message
	 * @return
	 */
    @StreamListener(MqMessageSource.TEST_IN_PUT)
    @SendTo({"msg_return"})
    public String messageInPut(Message<String> message) {
        System.err.println(" 消息(04)接收成功:" + message.getPayload());
        return "消息04接收到信息,并添加返回";
    }	

 2.消费者

  

package springcloud.stream.mq;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.stereotype.Component;



/**
 * d
 *
 * @author syj
 * CreateTime 2018/12/03
 * describe:
 */
@Component
@EnableBinding(MqMessageSource.class)
public class MqMessageProducer {
    @Autowired
    @Output(MqMessageSource.TEST_OUT_PUT)
    private MessageChannel channel;


    public void sendMsg(String msg,Integer parkey) {
        channel.send(MessageBuilder.withPayload(msg).setHeader("partitionKey", parkey).build());
        System.err.println("消息发送成功00:"+msg);
    }
    
    @StreamListener(MqMessageSource.TEST_IN_PUT)   //这里的名称桶@SendTo里面的值一样
    public void getReturnMsg(Message<String> message) {
    	System.err.println("消息是否已经被消费:"+message.getPayload());
    }
   
}

六:动态消息通道绑定

  说明:动态绑定消息通道,代码改于(二),

1.修改生产者

package springcloud.stream.mq;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.binding.BinderAwareChannelResolver;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Component;



@Component
@EnableBinding
public class MqMessageProducer {


      
    
    //动态绑定的发送者 
    @Autowired
    private BinderAwareChannelResolver  reslover;
     
    //通过dest指定某一个通道
    public void DySendMsg(String msg,String dest) {
    	System.err.println("消息发送");
    	reslover.resolveDestination(dest).send(
    			MessageBuilder.withPayload(msg)
    			.build()
    			);
    }
}

3.修改消费者

package springcloud.mq;

import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;


public interface  MqMessageSource {

   

    //动态绑定通道,定义2个通道
    String  Dy_c1="dy-c1";
    String Dy_c2="dy-c2";
    
    @Input(Dy_c1)
    SubscribableChannel Dyc1();
    
    @Input(Dy_c2)
    SubscribableChannel Dyc2();
}
package springcloud.mq;

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Component;


/**
 * 定义通道监听
 *
 *
 * @author monxz
 *
 * @date 2019年6月20日
 */
@EnableBinding(MqMessageSource.class)
public class MqMessageConsumer {
	
    
    /**
     * 动态消息1
     * @param message
     */
    @StreamListener(MqMessageSource.Dy_c1)
    public void  dyc1(Message<String> message) {
    	System.err.println("动态通道接收到消息,内容为:"+message.getPayload());
    }
    
    /**
     * 动态消息2
     * @param message
     */
    @StreamListener(MqMessageSource.Dy_c2)
    public void  dyc2(Message<String> message) {
    	System.err.println("动态通道接收到消息,内容为:"+message.getPayload());
    }
}

猜你喜欢

转载自blog.csdn.net/qq_35755863/article/details/92970106