Spring Cloud Stream is a framework for building message-driven microservices. The application interacts with the binder object in Spring Cloud Stream through inputs (equivalent to message consumer) or outputs (equivalent to message producer). The Binder object is used to shield the underlying MQ details. It is responsible for intervening with specific messages. software interaction.
Table of contents
Solve pain points
MQ message middleware is widely used in scenarios such as application decoupling, asynchronous message processing, and traffic peak shaving.
Different MQ message middlewares have different internal mechanisms including usage methods. For example, RabbitMQ has the concept of Exchange (switch/switch), and kafka has concepts such as Topic and Partition. The differences of MQ message middleware are not conducive to us. For upper-layer development applications, when our system wants to switch from the original RabbitMQ to Kafka, we will find it more difficult, and many operations may need to be repeated (because the application is coupled with a specific MQ message middleware). get up).
Spring Cloud Stream has a good upper-level abstraction, which allows us to decouple from the specific message middleware, shielding the detailed differences of the underlying specific MQ message middleware, just like Hibernate shields the specific database (like Mysql/Oracle) . In this way
, it will become easier for us to learn, develop, and maintain MQ. Currently Spring Cloud Stream supports RabbitMQ and Kafka.
concept
inputs : (equivalent to message consumer)
outputs : (equivalent to message producer)
Binder : Use it to shield
the detailed differences between different underlying MQ message middleware. When it is necessary to change to other message middleware, All we need to do is replace the corresponding Binder binder without modifying any application logical
architecture diagram :
Stream programming annotations
annotation | describe |
---|---|
@Input (used in consumer projects) | The annotation identifies the input channel through which messages received enter the application. |
@Output (used in producer projects) | The annotation identifies the output channel through which published messages will leave the application. |
@StreamListener (used in consumer projects to monitor the arrival of messages) | The listening queue is used to receive messages from the consumer's queue (with message listening...) |
@EnableBinding | Bind Channel and Exchange (for RabbitMQ) together |
Build services
producer service
- Create a new submodule under lagou_parent: m-cloud-stream-producer-9090
- Add dependencies in pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
- application.yml add configuration
server:
port: 9090
spring:
application:
name: m-cloud-stream-producer
cloud:
stream:
binders: # 绑定MQ服务信息(此处我们是RabbitMQ)
mRabbitMQbinder: # 给Binder定义的名称,⽤于后⾯的关联
type: rabbit
environment: # MQ环境配置(⽤户名、密码等)
spring:
rabbitmq:
host: 127.0.0.1
username: guest
password: guest
bindings: # 关联整合通道和binder对象
output: # output是我们定义的通道名称,此处不能乱改
destination: m-cloud-stream-producer-exchange
content-type: text/plain
binder: mRabbitMQbinder
#注册发现
eureka:
client:
service-url:
defaultZone: http://CloudEurekaServerA:8761/eureka,http://CloudEurekaServerB:8762/eureka
instance:
prefer-ip-address: true
instance-id: ${
spring.cloud.client.ip-address}:${
spring.application.name}:${
server.port}:@project.version@
- Startup class
@SpringBootApplication
@EnableDiscoveryClient
public class MCloudStreamProducer9090 {
public static void main(String[] args) {
SpringApplication.run(MCloudStreamProducer9090.class, args);
}
}
- service
public interface IMessageProducer {
public void sendMessage(String content);
}
@EnableBinding(Source.class)
public class IMessageProducerImpl implements IMessageProducer {
@Autowired
private Source source;
@Override
public void sendMessage(String content) {
source.output().send(MessageBuilder.withPayload(content).build());
}
}
- Test class
@SpringBootTest(classes = {
MCloudStreamProducer9090.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class MCloudStreamProducer9090Test {
@Autowired
private IMessageProducer iMessageProducer;
@Test
public void testSendMessage() {
iMessageProducer.sendMessage("hello world");
}
}
consumer services
- Create a new submodule under lagou_parent: m-cloud-stream-consumer-9091
- Add dependencies in pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
- application.yml add configuration
server:
port: 9091
spring:
application:
name: m-cloud-stream-consumer
cloud:
stream:
binders: # 绑定MQ服务信息(此处我们是RabbitMQ)
mRabbitMQbinder: # 给Binder定义的名称,⽤于后⾯的关联
type: rabbit
environment: # MQ环境配置(⽤户名、密码等)
spring:
rabbitmq:
host: 127.0.0.1
username: guest
password: guest
bindings: # 关联整合通道和binder对象
input: # output是我们定义的通道名称,此处不能乱改
destination: m-cloud-stream-producer-exchange
content-type: text/plain
binder: mRabbitMQbinder
group: rabbit-a
#注册发现
eureka:
client:
service-url:
defaultZone: http://CloudEurekaServerA:8761/eureka,http://CloudEurekaServerB:8762/eureka
instance:
prefer-ip-address: true
instance-id: ${
spring.cloud.client.ip-address}:${
spring.application.name}:${
server.port}:@project.version@
- Startup class
@SpringBootApplication
@EnableDiscoveryClient
public class McloudSteamConsumer9091 {
public static void main(String[] args) {
SpringApplication.run(McloudSteamConsumer9091.class, args);
}
}
- service
@EnableBinding(Sink.class)
public class MessageConsumerService {
@StreamListener(Sink.INPUT)
public void receMessage(Message<String> message){
System.out.println("=========接收到的消息:" + message);
}
}
- copy m-cloud-stream-consumer-9091 构建 m-cloud-stream-consumer-9092
verify
- Producers send messages and consumers receive them
- Messages within the same group will not be consumed repeatedly (start m-cloud-stream-consumer-9092)
Stream advanced custom message channel
Stream has two built-in interfaces, Source and Sink, which respectively define the input stream with binding "input" and the output stream with "output". We can also
customize various input and output streams (channels), but in fact we can Our service uses multiple binders, multiple input channels and output channels, but by default it has one input channel and one output channel. What should we do? We can customize message channels. Follow the example of Source and Sink and define your own name for your channel. Multiple input channels and output channels can be written in one class.
- Define interface
interface CustomChannel {
String INPUT_LOG = "inputLog";
String OUTPUT_LOG = "outputLog";
@Input(INPUT_LOG)
SubscribableChannel inputLog();
@Output(OUTPUT_LOG)
MessageChannel outputLog();
}
- In
@EnableBinding
the annotation, bind the custom interface - When using
@StreamListener
for monitoring, you need to specify CustomChannel.INPUT_LOG
bindings:
inputLog:
destination: mmExchange
outputLog:
destination: eduExchange