消息驱动/整合SpringCloud
1、准备工作

- Eureka服务器
- Eureka客户端,Producer:用于生产消息,Consumer:用于消费消息
- RabbitMQ作为服务在window系统中运行,所以暂用RabbitMQ进行搭建测试,之后再更换为kafka
server:
port: 9000
spring:
application:
name: atm-msg-consumer
#rabbitmq:
# host: localhost
# port: 5762
# username: guest
# password: guest
# 均使用默认的配置,所以可以无需配置,需要修改时,再配置
2、生产者/RabbitMQ
2.1、引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
2.2、SendMessageInterface
package com.atm.cloud;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.SubscribableChannel;
/**
* 发送消息的服务接口,用来绑定Topic
*/
public interface SendMessageInterface {
/**
* 声明一个方法用来订阅渠道,使用output注解,声明渠道名称,从这里输出一个消息
*/
@Output("myInput")
SubscribableChannel sendMsg();
}
2.3、SendMessageController
package com.atm.cloud
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.integration.support.MessageBuilder
import org.springframework.messaging.Message
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@RestController
public class SendMessageController {
@Autowired
private SendMessageInterface sendMessageInterface
@GetMapping("/send")
public String sendMsg() {
Message msg = MessageBuilder.withPayload("Hello World".getBytes())
.build()
sendMessageInterface.sendMsg().send(msg)
return "Success"
}
}
2.4、MsgProducerApp
package com.atm.cloud
import java.util.Scanner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.builder.SpringApplicationBuilder
import org.springframework.cloud.netflix.eureka.EnableEurekaClient
import org.springframework.cloud.stream.annotation.EnableBinding
@SpringBootApplication
@EnableEurekaClient
@EnableBinding(SendMessageInterface.class)//开启绑定
public class MsgProducerApp {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in)
String port = scanner.nextLine()
new SpringApplicationBuilder(MsgProducerApp.class).properties(
"server.port=" + port).run(args)
}
}


3、消费者/RabbitMQ
3.1、引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
3.2、ReadMessageInterface
package com.atm.cloud;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;
/**
* 用于接收消息
*/
public interface ReadMessageInterface {
@Input("myInput")
SubscribableChannel readMsg();
}
3.3、MsgConsumerApp
package com.atm.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
@SpringBootApplication
@EnableDiscoveryClient
@EnableBinding(ReadMessageInterface.class)
public class MsgConsumerApp {
public static void main(String[] args) {
SpringApplication.run(MsgConsumerApp.class, args);
}
/**
* 用于监听接收的消息
*/
@StreamListener("myInput")
public void onListen(byte[] msg) {
System.out.println("接收到的消息:" + new String(msg));
}
}

- 我们无需关心消息如何发送与接收,我们只需要知道其中的内容是什么
- 目前我们已经使用RabbitMQ发送和接收消息了,接下来我们要使用kafka
- 只需要更换绑定器即可,SpringCloud默认提供了两个绑定器,一个绑定器是绑定了RabbitMQ,一个是绑定kafka,所有调用消息中间件的代码都已经在绑定器中实现了,绑定期类似与适配器,使用不同的消息代理中间件就使用不同的绑定器
4、生产者/消费者-Kafka
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

5、消费者组
spring:
application:
name: spring-msg-consumer3
##配置消费者组
cloud:
stream:
bindings:
myInput:
group: groupB
5.1、Sink、Source、Processor
- 为了简化开发,SpringCloud Stream内置了三个接口,Sink、Source、Processor
- Processor继承了Sink和Source,实际应用中可以考虑只使用Processor
public interface Sink {
String INPUT = "input";
@Input(Sink.INPUT)
SubscribableChannel input();
}
public interface Source {
String OUTPUT = "output";
@Output(Source.OUTPUT)
SubscribableChannel output();
}
- 根据这两个接口可知,实际上帮我们内置了”input”和“output”两个通道,那么在大多数情况下,我们就可以不必编写服务接口,甚至不必使用@input和@output两个注解,在绑定通道时加入Sink.class
/**
* 用于接收消息,可以不需要了
*/
public interface ReadMessageInterface {
@Input("myInput")
SubscribableChannel readMsg();
}
/**
* 发送消息的服务接口,用来绑定Topic
*/
public interface SendMessageInterface {
/**
* 声明一个方法用来订阅渠道,使用output注解,声明渠道名称,从这里输出一个消息
*/
@Output("input")
SubscribableChannel sendMsg();
}
package com.atm.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.cloud.stream.messaging.Source;
@SpringBootApplication
@EnableDiscoveryClient
@EnableBinding(value={Sink.class})
public class MsgConsumerApp {
public static void main(String[] args) {
SpringApplication.run(MsgConsumerApp.class, args);
}
/**
* 用于监听接收的消息
*/
@StreamListener(Sink.INPUT)
public void onListen(byte[] msg) {
System.out.println("A:接收到的消息:" + new String(msg));
}
}