本文通过实战项目基于事件驱动架构实现实时流处理应用,使用到Spring Boot、Spring mvc、Spring Cloud Stream、Apache Kafka、Lombok。读完基本能够理解基于流的微服务应用。
让我们开始吧。
Spring Cloud Stream是基于Spring Boot构建消息驱动微服务框架。Kafka是高性能的、可伸缩的分布式消息代理平台。Lombok让我们简化java Beandinginess。下面简单介绍下安装Kafka,并新建SpringBoot项目。
在官网下载kafka,注意和你本机的scala版本一致。解压后启动kafka服务。
启动zookeeper, 如果windows环境,bin/window/对应的.bat文件:
$ bin/zookeeper-server-start.sh config/zookeeper.properties
启动kafka, 如果windows环境,bin/window/对应的.bat文件:
$ bin/kafka-server-start.sh config/server.properties
使用Idea新建Spring Boot项目,并增加下列依赖:
spring-cloud-stream、spring-kafka、spring-cloud-stream-binder-kafka、spring-boot-starter-web、spring-boot-starter-actuator、lombok、spring-boot-devtools。完整代码如下:
4.0.0
com.dataz
streamkafka
0.0.1-SNAPSHOT
streamkafka
streamkafka
1.8
UTF-8
UTF-8
2.3.7.RELEASE
Hoxton.SR9
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-stream
org.springframework.cloud
spring-cloud-stream-binder-kafka
org.springframework.kafka
spring-kafka
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
runtime
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.cloud
spring-cloud-stream-test-support
test
org.springframework.kafka
spring-kafka-test
test
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-dependencies
${spring-boot.version}
pom
import
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
1.8
UTF-8
org.springframework.boot
spring-boot-maven-plugin
2.3.7.RELEASE
com.dataz.streamkafka.StreamkafkaApplication
repackage
repackage
我们的项目需要于kafka进行通讯,因此需要定义输出流(往kafka主题写消息)、输入流(从kafka主题中读消息)。Spring Cloud 提供了便捷方式实现上述功能,仅需要简单创建接口,给每个流向指定相应方法。代码如下:
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 GreetingsStreams {
String INPUT = "greetings-in";
String OUTPUT = "greetings-out";
/**
* input
* @return SubscribableChannel
*/
@Input(INPUT)
SubscribableChannel inboundGreetings();
/**
* output
* @return MessageChannel
*/
@Output(OUTPUT)
MessageChannel outboundGreetings();
}
inboundGreetings() 方法定义输入流从 Kafka 读取消息,outboundGreetings() 方法定义输出流往kafka写消息。应用运行时Spring会创建java代理实现GreetingsStreams 接口,它可作为Spring Bean注入至任何需要访问两个流向的业务。
接下来配置Spring Cloud Stream,绑定至流接口GreetingsStreams 。通过@Configuration注解实现:
import org.springframework.cloud.stream.annotation.EnableBinding;
@EnableBinding(GreetingsStreams.class)
public class StreamsConfig {
}
@EnableBinding注解指定GreetingsStreams接口实现绑定。
Spring Boot项目默认生成了application.properties,但我习惯使用yaml文件,新建application.yaml文件,配置下列内容:
spring:
cloud:
stream:
kafka:
binder:
brokers: localhost:9092
bindings:
greetings-in:
destination: greetings
contentType: application/json
greetings-out:
destination: greetings
contentType: application/json
上面配置了kafka代理地址,kafka主题,这里输入流和输出流必须使用相同主题。contentType熟悉告诉Spring Cloud Stream发送接收消息对象作为json String.
创建Greetings类,表示消息对象,用于读取或写入消息:
import lombok.*;
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Greetings {
private long timestamp;
private String message;
}
上面注解都是lombok的注解,比较直观,不再解释。
创建GreetingsService 类,sendGreeting方法实现往kafka主题写Greetings消息:
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.MimeTypeUtils;
@Service
@Slf4j
public class GreetingsService {
private final GreetingsStreams greetingsStreams;
public GreetingsService(GreetingsStreams greetingsStreams) {
this.greetingsStreams = greetingsStreams;
}
public void sendGreeting(final Greetings greetings) {
log.info("Sending greetings {}", greetings);
MessageChannel messageChannel = greetingsStreams.outboundGreetings();
messageChannel.send(MessageBuilder
.withPayload(greetings)
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
.build());
}
}
@Service 注解配置该类作为Spring Bean,通过构造函数注入GreetingsStreams。
@Slf4j 注解生成slf4j日志,用于使用日志。
现在创建REST API,用于触发发送消息给kafka,通过注入GreetingsService Bean实现:
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingsController {
private final GreetingsService greetingsService;
public GreetingsController(GreetingsService greetingsService) {
this.greetingsService = greetingsService;
}
@GetMapping("/greetings")
@ResponseStatus(HttpStatus.ACCEPTED)
public void greetings(@RequestParam("message") String message) {
Greetings greetings = Greetings.builder()
.message(message)
.timestamp(System.currentTimeMillis())
.build();
greetingsService.sendGreeting(greetings);
}
}
@RestController注解告诉Spring这是Controllerbean。greetings方法定义入口点HTTP GET /greetings
接收消息,最终通过sendGreeting发送消息。
创建GreetingsListener类,监听greetings主题并在控制台打印日志:
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class GreetingsListener {
@StreamListener(GreetingsStreams.INPUT)
public void handleGreetings(@Payload Greetings greetings) {
log.info("Received greetings: {}", greetings);
}
}
@Component 注解与@Service、@RestController类似,定义Spring Bean。GreetingsListener 只有一个方法handleGreetings,每次从kafka主题greetings读取新消息时会执行该方法。这是因为@StreamListener注解配置在该方法上。
该类是Spring Boot项目生成的:
@SpringBootApplication
public class StreamkafkaApplication {
public static void main(String[] args) {
SpringApplication.run(StreamkafkaApplication.class, args);
}
}
不需要任何修改,直接运行下列命令:
mvn spring-boot:run
启动成功后,在浏览器中输入下列内容,然后检查控制台:
localhost:8080/greetings?message=hello
本文介绍了Spring Cloud Stream 搭建与Kafka交互的事件流处理微服务应用。