├── .gitignore ├── PITCHME.md ├── pom.xml ├── spring-initializr-streamkafka.png └── src └── main ├── java └── com │ └── kaviddiss │ └── streamkafka │ ├── StreamKafkaApplication.java │ ├── config │ └── StreamsConfig.java │ ├── model │ └── Greetings.java │ ├── service │ ├── GreetingsListener.java │ └── GreetingsService.java │ ├── stream │ └── GreetingsStreams.java │ └── web │ └── GreetingsController.java └── resources └── application.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | data/ 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | nbproject/private/ 21 | build/ 22 | nbbuild/ 23 | dist/ 24 | nbdist/ 25 | .nb-gradle/ -------------------------------------------------------------------------------- /PITCHME.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Stream with Kafka 2 | by David Kiss (http://kaviddiss.com/2018/03/03/spring-cloud-stream-kafka/) 3 | 4 | --- 5 | 6 | ### Overview 7 | This sample project demonstrates how to build [real-time streaming](https://aws.amazon.com/streaming-data/) applications using [event-driven architecture](https://thenewstack.io/event-driven-architecture-wave-future/), 8 | [Spring Boot](https://thenewstack.io/event-driven-architecture-wave-future/), 9 | [Spring Cloud Stream](https://cloud.spring.io/spring-cloud-stream/), 10 | [Apache Kafka](https://kafka.apache.org/) and 11 | [Lombok](https://projectlombok.org/). 12 | 13 | +++ 14 | 15 | By end of this tutorial you'll have a simple Spring Boot based Greetings microservice running that 16 | 1. takes a message from a REST api 17 | 2. writes it to a Kafka topic 18 | 3. reads it from the topic 19 | 4. outputs it to the console 20 | 21 | --- 22 | 23 | ### Let's get started! 24 | 25 | --- 26 | 27 | ### What is Spring Cloud Streaming? 28 | Spring Cloud Stream is a framework built upon Spring Boot for building message-driven microservices. 29 | 30 | --- 31 | 32 | ### What is Kafka? 33 | Kafka is a popular high performant and horizontally scalable messaging platform originally developed by LinkedIn. 34 | 35 | --- 36 | 37 | ### Installing Kafka 38 | 39 | +++ 40 | 41 | Download Kafka from [here](https://kafka.apache.org/downloads) and untar it: 42 | ``` 43 | > tar -xzf kafka_2.11-1.0.0.tgz 44 | > cd kafka_2.11-1.0.0 45 | ``` 46 | 47 | +++ 48 | 49 | Start Zookeeper and Kafka 50 | 51 | On Windows: 52 | ``` 53 | > bin\windows\zookeeper-server-start.bat config\zookeeper.properties 54 | > bin\windows\kafka-server-start.bat config\server.properties 55 | ``` 56 | 57 | On Linux or Mac: 58 | ``` 59 | > bin/zookeeper-server-start.sh config/zookeeper.properties 60 | > bin/kafka-server-start.sh config/server.properties 61 | ``` 62 | 63 | +++ 64 | 65 | If Kafka is not running and fails to start after your computer wakes up from hibernation, delete the ```/kafka-logs``` folder and then start Kafka again. 66 | 67 | --- 68 | 69 | ### What is Lombok? 70 | Lombok is a java framework that automatically generates getters, setters, toString(), builders, loggers, etc. in the code. 71 | 72 | --- 73 | 74 | ### Maven dependencies 75 | 76 | +++ 77 | 78 | Go to https://start.spring.io to create a maven project: 79 | ![Spring Initializer](spring-initializr-streamkafka.png) 80 | 81 | +++ 82 | 83 | 1. Add necessary dependencies: ```Spring Cloud Stream```, ```Kafka```, ```Devtools``` (for hot redeploys during development, optional), ```Actuator``` (for monitoring application, optional), ```Lombok``` (make sure to also have the Lombok plugin installed in your IDE) 84 | 2. Click the Generate Project button to download the project as a zip file 85 | 3. Extract zip file and import the maven project to your favourite IDE 86 | 87 | +++ 88 | 89 | Notice the maven dependencies in the ```pom.xml``` file: 90 | ``` 91 | 92 | org.springframework.boot 93 | spring-boot-starter-actuator 94 | 95 | 96 | org.springframework.cloud 97 | spring-cloud-stream 98 | 99 | 100 | org.springframework.cloud 101 | spring-cloud-starter-stream-kafka 102 | 103 | ``` 104 | 105 | +++ 106 | 107 | ``` 108 | 109 | 110 | org.projectlombok 111 | lombok 112 | true 113 | 114 | 115 | 116 | 117 | org.springframework.boot 118 | spring-boot-devtools 119 | true 120 | 121 | ``` 122 | 123 | +++ 124 | 125 | ... also the `````` section: 126 | ``` 127 | 128 | 129 | 130 | 131 | org.springframework.boot 132 | spring-boot-dependencies 133 | ${spring-boot.version} 134 | pom 135 | import 136 | 137 | ... 138 | ``` 139 | 140 | +++ 141 | 142 | ``` 143 | ... 144 | 145 | org.springframework.cloud 146 | spring-cloud-stream-dependencies 147 | ${spring-cloud-stream.version} 148 | pom 149 | import 150 | 151 | 152 | 153 | ``` 154 | 155 | +++ 156 | 157 | ... and the `````` section: 158 | ``` 159 | 160 | spring-milestones 161 | Spring Milestones 162 | http://repo.spring.io/libs-milestone 163 | 164 | false 165 | 166 | 167 | ``` 168 | 169 | --- 170 | 171 | ### Define the Kafka streams 172 | ``` 173 | package com.kaviddiss.streamkafka.stream; 174 | 175 | import org.springframework.cloud.stream.annotation.Input; 176 | import org.springframework.cloud.stream.annotation.Output; 177 | import org.springframework.messaging.MessageChannel; 178 | import org.springframework.messaging.SubscribableChannel; 179 | ``` 180 | 181 | +++ 182 | 183 | ``` 184 | public interface GreetingsStreams { 185 | String INPUT = "greetings-in"; 186 | String OUTPUT = "greetings-out"; 187 | 188 | @Input(INPUT) 189 | SubscribableChannel inboundGreetings(); 190 | 191 | @Output(OUTPUT) 192 | MessageChannel outboundGreetings(); 193 | } 194 | ``` 195 | 196 | +++ 197 | 198 | In order for our application to be able to communicate with Kafka, we'll need to define an outbound stream to write messages to a Kafka topic, and an inbound stream to read messages from a Kafka topic. 199 | 200 | +++ 201 | 202 | Spring Cloud provides a convenient way to do this by simply creating an interface that defines a separate method for each stream. 203 | 204 | +++ 205 | 206 | The ```inboundGreetings()``` method defines the inbound stream to read from Kafka and ```outboundGreetings()``` method defines the outbound stream to write to Kafka. 207 | 208 | +++ 209 | 210 | During runtime Spring will create a java proxy based implementation of the ```GreetingsStreams``` interface that can be injected as a Spring Bean anywhere in the code to access our two streams. 211 | 212 | --- 213 | 214 | ### Configure Spring Cloud Stream 215 | Our next step is to configure Spring Cloud Stream to bind to our streams in the ```GreetingsStreams``` interface. 216 | 217 | +++ 218 | 219 | This can be done by creating a ```@Configuration``` class ```com.kaviddiss.streamkafka.config.StreamsConfig``` with below code: 220 | 221 | +++ 222 | 223 | ``` 224 | package com.kaviddiss.streamkafka.config; 225 | 226 | import com.kaviddiss.streamkafka.stream.GreetingsStreams; 227 | import org.springframework.cloud.stream.annotation.EnableBinding; 228 | 229 | @EnableBinding(GreetingsStreams.class) 230 | public class StreamsConfig { 231 | } 232 | ``` 233 | 234 | +++ 235 | 236 | Binding the streams is done using the ```@EnableBinding``` annotation where the ```GreatingsService``` interface is passed to. 237 | 238 | --- 239 | 240 | ### Configuration properties for Kafka 241 | 242 | By default, the configuration properties are stored in the ```src/main/resources/application.properties``` file. 243 | 244 | +++ 245 | 246 | However I prefer to use the YAML format as it's less verbose and allows to keep both common and environment-specific properties in the same file. 247 | 248 | +++ 249 | 250 | For now, let's rename ```application.properties``` to ```application.yaml``` and paste below config snippet into the file: 251 | 252 | +++ 253 | 254 | ``` 255 | spring: 256 | cloud: 257 | stream: 258 | kafka: 259 | binder: 260 | brokers: localhost:9092 261 | bindings: 262 | greetings-in: 263 | destination: greetings 264 | contentType: application/json 265 | greetings-out: 266 | destination: greetings 267 | contentType: application/json 268 | ``` 269 | 270 | +++ 271 | 272 | The above configuration properties configure the address of the Kafka server to connect to, and the Kafka topic we use for both the inbound and outbound streams in our code. They both must use the same Kafka topic! 273 | 274 | +++ 275 | 276 | The ```contentType``` properties tell Spring Cloud Stream to send/receive our message objects as ```String```s in the streams. 277 | 278 | --- 279 | 280 | ### Create the message object 281 | 282 | Create a simple ```com.kaviddiss.streamkafka.model.Greetings``` class with below code that will represent the message object we read from and write to the ```greetings``` Kafka topic: 283 | 284 | +++ 285 | 286 | ``` 287 | package com.kaviddiss.streamkafka.model; 288 | 289 | // lombok autogenerates getters, setters, toString() and a builder (see https://projectlombok.org/): 290 | import lombok.Builder; 291 | import lombok.Getter; 292 | import lombok.Setter; 293 | import lombok.ToString; 294 | 295 | @Getter @Setter @ToString @Builder 296 | public class Greetings { 297 | private long timestamp; 298 | private String message; 299 | } 300 | ``` 301 | 302 | +++ 303 | 304 | Notice how the class doesn't have any getters and setters thanks to the Lombok annotations. The ```@ToString``` will generate a ```toString()``` method using the class' fields and the ```@Builder``` annotation will allow us creating ```Greetings``` objects using fluent builder (see below). 305 | 306 | --- 307 | 308 | ### Create service layer to write to Kafka 309 | 310 | Let's create the ```com.kaviddiss.streamkafka.service.GreetingsService``` class with below code that will write a ```Greetings``` object to the ```greetings``` Kafka topic: 311 | 312 | +++ 313 | 314 | ``` 315 | package com.kaviddiss.streamkafka.service; 316 | 317 | import com.kaviddiss.streamkafka.model.Greetings; 318 | import com.kaviddiss.streamkafka.stream.GreetingsStreams; 319 | import lombok.extern.slf4j.Slf4j; 320 | import org.springframework.messaging.MessageChannel; 321 | import org.springframework.messaging.MessageHeaders; 322 | import org.springframework.messaging.support.MessageBuilder; 323 | import org.springframework.stereotype.Service; 324 | import org.springframework.util.MimeTypeUtils; 325 | ``` 326 | 327 | +++ 328 | 329 | ``` 330 | @Service 331 | @Slf4j 332 | public class GreetingsService { 333 | private final GreetingsStreams greetingsStreams; 334 | 335 | public GreetingsService(GreetingsStreams greetingsStreams) { 336 | this.greetingsStreams = greetingsStreams; 337 | } 338 | ``` 339 | 340 | +++ 341 | 342 | ``` 343 | public void sendGreeting(final Greetings greetings) { 344 | log.info("Sending greetings {}", greetings); 345 | 346 | MessageChannel messageChannel = greetingsStreams.outboundGreetings(); 347 | messageChannel.send(MessageBuilder 348 | .withPayload(greetings) 349 | .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON) 350 | .build()); 351 | } 352 | } 353 | ``` 354 | 355 | +++ 356 | 357 | The ```@Service``` annotation will configure this class as a Spring Bean and inject the ```GreetingsService``` dependency via the constructor. 358 | 359 | +++ 360 | 361 | The ```@Slf4j``` annotation will generate an SLF4J logger field that we can use for logging. 362 | 363 | +++ 364 | 365 | In the ```sendGreeting()``` method we use the injected ```GreetingsStream``` object to send a message represented by the ```Greetings``` object. 366 | 367 | --- 368 | 369 | ### Create REST api 370 | 371 | Now we'll be creating a REST api endpoint that will trigger sending a message to Kafka using the ```GreetingsService``` Spring Bean: 372 | 373 | +++ 374 | 375 | ``` 376 | package com.kaviddiss.streamkafka.web; 377 | 378 | import com.kaviddiss.streamkafka.model.Greetings; 379 | import com.kaviddiss.streamkafka.service.GreetingsService; 380 | import org.springframework.http.HttpStatus; 381 | import org.springframework.web.bind.annotation.GetMapping; 382 | import org.springframework.web.bind.annotation.RequestParam; 383 | import org.springframework.web.bind.annotation.ResponseStatus; 384 | import org.springframework.web.bind.annotation.RestController; 385 | ``` 386 | 387 | +++ 388 | 389 | ``` 390 | @RestController 391 | public class GreetingsController { 392 | private final GreetingsService greetingsService; 393 | 394 | public GreetingsController(GreetingsService greetingsService) { 395 | this.greetingsService = greetingsService; 396 | } 397 | ``` 398 | 399 | +++ 400 | 401 | ``` 402 | @GetMapping("/greetings") 403 | @ResponseStatus(HttpStatus.ACCEPTED) 404 | public void greetings(@RequestParam("message") String message) { 405 | Greetings greetings = Greetings.builder() 406 | .message(message) 407 | .timestamp(System.currentTimeMillis()) 408 | .build(); 409 | 410 | greetingsService.sendGreeting(greetings); 411 | } 412 | } 413 | ``` 414 | 415 | +++ 416 | 417 | The ```@RestController``` annotation tells Spring that this is a Controller bean (the C from MVC). The ```greetings()``` method defines an ```HTTP GET /greetings``` endpoint that takes a ```message``` request param and passes it to the ```sendGreeting()``` method in ```GreetingsService```. 418 | 419 | --- 420 | 421 | ### Listening on the greetings Kafka topic 422 | 423 | Let's create a ```com.kaviddiss.streamkafka.service.GreetingsListener``` class that will listen to messages on the ```greetings``` Kafka topic and log them on the console: 424 | 425 | +++ 426 | 427 | ``` 428 | package com.kaviddiss.streamkafka.service; 429 | 430 | import com.kaviddiss.streamkafka.model.Greetings; 431 | import com.kaviddiss.streamkafka.stream.GreetingsStreams; 432 | import lombok.extern.slf4j.Slf4j; 433 | import org.springframework.cloud.stream.annotation.StreamListener; 434 | import org.springframework.messaging.handler.annotation.Payload; 435 | import org.springframework.stereotype.Component; 436 | ``` 437 | 438 | +++ 439 | 440 | ``` 441 | @Component 442 | @Slf4j 443 | public class GreetingsListener { 444 | @StreamListener(GreetingsStreams.INPUT) 445 | public void handleGreetings(@Payload Greetings greetings) { 446 | log.info("Received greetings: {}", greetings); 447 | } 448 | } 449 | ``` 450 | 451 | +++ 452 | 453 | The ```@Component``` annotation similarly to ```@Service``` and ```@RestController``` defines a Spring Bean. 454 | 455 | +++ 456 | 457 | ```GreetingsListener``` has a single method, ```handleGreetings()``` that will be invoked by Spring Cloud Stream with every new ```Greetings``` message object on the ```greetings``` Kafka topic. This is thanks to the ```@StreamListener``` annotation configured for the ```handleGreetings()``` method. 458 | 459 | --- 460 | 461 | ### Running the application 462 | The last piece of the puzzle is the ```com.kaviddiss.streamkafka.StreamKafkaApplication``` class that was auto-generated by the Spring Initializer: 463 | 464 | +++ 465 | 466 | ``` 467 | package com.kaviddiss.streamkafka; 468 | 469 | import org.springframework.boot.SpringApplication; 470 | import org.springframework.boot.autoconfigure.SpringBootApplication; 471 | 472 | @SpringBootApplication 473 | public class StreamKafkaApplication { 474 | 475 | public static void main(String[] args) { 476 | SpringApplication.run(StreamKafkaApplication.class, args); 477 | } 478 | } 479 | ``` 480 | 481 | +++ 482 | 483 | No need to make any changes here. You can either run this class as a Java application from your IDE, or run the application from the command line using the Spring Boot maven plugin: 484 | 485 | ``` 486 | > mvn spring-boot:run 487 | ``` 488 | 489 | +++ 490 | 491 | Once the application is running, go to http://localhost:8080/greetings?message=hello in the browser and check your console. 492 | 493 | --- 494 | 495 | ### Summary 496 | I hope you enjoyed this tutorial. Feel free to ask any questions and leave your feedback. 497 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.kaviddiss 8 | spring-cloud-stream-kafka-demo 9 | 0.0.1-SNAPSHOT 10 | 11 | 12 | UTF-8 13 | UTF-8 14 | 1.8 15 | 1.5.9.RELEASE 16 | Ditmars.SR1 17 | 18 | 19 | 20 | 21 | spring-milestones 22 | Spring Milestones 23 | http://repo.spring.io/libs-milestone 24 | 25 | false 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-dependencies 36 | ${spring-boot.version} 37 | pom 38 | import 39 | 40 | 41 | org.springframework.cloud 42 | spring-cloud-stream-dependencies 43 | ${spring-cloud-stream.version} 44 | pom 45 | import 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-actuator 54 | 55 | 56 | org.springframework.cloud 57 | spring-cloud-stream 58 | 59 | 60 | org.springframework.cloud 61 | spring-cloud-starter-stream-kafka 62 | 63 | 64 | 65 | 66 | org.projectlombok 67 | lombok 68 | true 69 | 70 | 71 | 72 | 73 | org.springframework.boot 74 | spring-boot-devtools 75 | true 76 | 77 | 78 | 79 | 80 | 81 | 82 | org.springframework.boot 83 | spring-boot-maven-plugin 84 | 85 | 86 | org.apache.maven.plugins 87 | maven-compiler-plugin 88 | 89 | ${java.version} 90 | ${java.version} 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /spring-initializr-streamkafka.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidkiss/spring-cloud-streams-kafka-demo/aa826bba4ac11de6bbdb1b454ebfb79fcc95c422/spring-initializr-streamkafka.png -------------------------------------------------------------------------------- /src/main/java/com/kaviddiss/streamkafka/StreamKafkaApplication.java: -------------------------------------------------------------------------------- 1 | package com.kaviddiss.streamkafka; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class StreamKafkaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(StreamKafkaApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/kaviddiss/streamkafka/config/StreamsConfig.java: -------------------------------------------------------------------------------- 1 | package com.kaviddiss.streamkafka.config; 2 | 3 | import com.kaviddiss.streamkafka.stream.GreetingsStreams; 4 | import org.springframework.cloud.stream.annotation.EnableBinding; 5 | 6 | @EnableBinding(GreetingsStreams.class) 7 | public class StreamsConfig { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/kaviddiss/streamkafka/model/Greetings.java: -------------------------------------------------------------------------------- 1 | package com.kaviddiss.streamkafka.model; 2 | 3 | // lombok autogenerates getters, setters, toString() and a builder (see https://projectlombok.org/): 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | 9 | @Getter @Setter @ToString @Builder 10 | public class Greetings { 11 | private long timestamp; 12 | private String message; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/kaviddiss/streamkafka/service/GreetingsListener.java: -------------------------------------------------------------------------------- 1 | package com.kaviddiss.streamkafka.service; 2 | 3 | import com.kaviddiss.streamkafka.model.Greetings; 4 | import com.kaviddiss.streamkafka.stream.GreetingsStreams; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.cloud.stream.annotation.StreamListener; 7 | import org.springframework.messaging.handler.annotation.Payload; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | @Slf4j 12 | public class GreetingsListener { 13 | @StreamListener(GreetingsStreams.INPUT) 14 | public void handleGreetings(@Payload Greetings greetings) { 15 | log.info("Received greetings: {}", greetings); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/kaviddiss/streamkafka/service/GreetingsService.java: -------------------------------------------------------------------------------- 1 | package com.kaviddiss.streamkafka.service; 2 | 3 | import com.kaviddiss.streamkafka.model.Greetings; 4 | import com.kaviddiss.streamkafka.stream.GreetingsStreams; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.messaging.MessageChannel; 7 | import org.springframework.messaging.MessageHeaders; 8 | import org.springframework.messaging.support.MessageBuilder; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.util.MimeTypeUtils; 11 | 12 | @Service 13 | @Slf4j 14 | public class GreetingsService { 15 | private final GreetingsStreams greetingsStreams; 16 | 17 | public GreetingsService(GreetingsStreams greetingsStreams) { 18 | this.greetingsStreams = greetingsStreams; 19 | } 20 | 21 | public void sendGreeting(final Greetings greetings) { 22 | log.info("Sending greetings {}", greetings); 23 | 24 | MessageChannel messageChannel = greetingsStreams.outboundGreetings(); 25 | messageChannel.send(MessageBuilder 26 | .withPayload(greetings) 27 | .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON) 28 | .build()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/kaviddiss/streamkafka/stream/GreetingsStreams.java: -------------------------------------------------------------------------------- 1 | package com.kaviddiss.streamkafka.stream; 2 | 3 | import org.springframework.cloud.stream.annotation.Input; 4 | import org.springframework.cloud.stream.annotation.Output; 5 | import org.springframework.messaging.MessageChannel; 6 | import org.springframework.messaging.SubscribableChannel; 7 | 8 | public interface GreetingsStreams { 9 | String INPUT = "greetings-in"; 10 | String OUTPUT = "greetings-out"; 11 | 12 | @Input(INPUT) 13 | SubscribableChannel inboundGreetings(); 14 | 15 | @Output(OUTPUT) 16 | MessageChannel outboundGreetings(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/kaviddiss/streamkafka/web/GreetingsController.java: -------------------------------------------------------------------------------- 1 | package com.kaviddiss.streamkafka.web; 2 | 3 | import com.kaviddiss.streamkafka.model.Greetings; 4 | import com.kaviddiss.streamkafka.service.GreetingsService; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestParam; 8 | import org.springframework.web.bind.annotation.ResponseStatus; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | public class GreetingsController { 13 | private final GreetingsService greetingsService; 14 | 15 | public GreetingsController(GreetingsService greetingsService) { 16 | this.greetingsService = greetingsService; 17 | } 18 | 19 | @GetMapping("/greetings") 20 | @ResponseStatus(HttpStatus.ACCEPTED) 21 | public void greetings(@RequestParam("message") String message) { 22 | Greetings greetings = Greetings.builder() 23 | .message(message) 24 | .timestamp(System.currentTimeMillis()) 25 | .build(); 26 | 27 | greetingsService.sendGreeting(greetings); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | stream: 4 | kafka: 5 | binder: 6 | brokers: localhost:9092 7 | bindings: 8 | greetings-in: 9 | destination: greetings 10 | contentType: application/json 11 | greetings-out: 12 | destination: greetings 13 | contentType: application/json 14 | --------------------------------------------------------------------------------