├── .github
└── FUNDING.yml
├── .gitignore
├── .mvn
└── wrapper
│ └── maven-wrapper.properties
├── README.md
├── avro-2-de-serialization
├── README.md
├── avro-2-consumer-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ivanfranchin
│ │ │ │ ├── avro2consumerservice
│ │ │ │ ├── Avro2ConsumerServiceApplication.java
│ │ │ │ └── news
│ │ │ │ │ ├── NewsListener.java
│ │ │ │ │ └── NewsListenerConfig.java
│ │ │ │ └── commons
│ │ │ │ └── avroserialization
│ │ │ │ └── avro
│ │ │ │ └── NewsMessage.java
│ │ └── resources
│ │ │ ├── application.properties
│ │ │ ├── avro
│ │ │ └── news-message.avsc
│ │ │ └── banner.txt
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── ivanfranchin
│ │ └── avro2consumerservice
│ │ └── Avro2ConsumerServiceApplicationTests.java
├── avro-2-producer-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ivanfranchin
│ │ │ │ ├── avro2producerservice
│ │ │ │ ├── Avro2ProducerServiceApplication.java
│ │ │ │ ├── news
│ │ │ │ │ ├── News.java
│ │ │ │ │ ├── NewsEmitter.java
│ │ │ │ │ └── NewsEmitterConfig.java
│ │ │ │ └── simulation
│ │ │ │ │ └── SimulationRunner.java
│ │ │ │ └── commons
│ │ │ │ └── avroserialization
│ │ │ │ └── avro
│ │ │ │ └── NewsMessage.java
│ │ └── resources
│ │ │ ├── application.properties
│ │ │ ├── avro
│ │ │ └── news-message.avsc
│ │ │ └── banner.txt
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── ivanfranchin
│ │ └── avro2producerservice
│ │ └── Avro2ProducerServiceApplicationTests.java
└── pom.xml
├── avro-3-de-serialization
├── README.md
├── avro-3-consumer-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ivanfranchin
│ │ │ │ └── avro3consumerservice
│ │ │ │ ├── Avro3ConsumerServiceApplication.java
│ │ │ │ ├── avro
│ │ │ │ └── NewsMessage.java
│ │ │ │ └── news
│ │ │ │ ├── NewsListener.java
│ │ │ │ ├── NewsListenerConfig.java
│ │ │ │ └── SpecificAvroWithSchemaDeserializer.java
│ │ └── resources
│ │ │ ├── application.properties
│ │ │ ├── avro
│ │ │ └── news-message.avsc
│ │ │ └── banner.txt
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── ivanfranchin
│ │ └── avro3consumerservice
│ │ └── Avro3ConsumerServiceApplicationTests.java
├── avro-3-producer-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ivanfranchin
│ │ │ │ └── avro3producerservice
│ │ │ │ ├── Avro3ProducerServiceApplication.java
│ │ │ │ ├── avro
│ │ │ │ └── NewsMessage.java
│ │ │ │ ├── news
│ │ │ │ ├── News.java
│ │ │ │ ├── NewsEmitter.java
│ │ │ │ └── NewsEmitterConfig.java
│ │ │ │ └── simulation
│ │ │ │ └── SimulationRunner.java
│ │ └── resources
│ │ │ ├── application.properties
│ │ │ ├── avro
│ │ │ └── news-message.avsc
│ │ │ └── banner.txt
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── ivanfranchin
│ │ └── avro3producerservice
│ │ └── Avro3ProducerServiceApplicationTests.java
└── pom.xml
├── avro-de-serialization
├── README.md
├── avro-consumer-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ivanfranchin
│ │ │ │ └── avroconsumerservice
│ │ │ │ ├── AvroConsumerServiceApplication.java
│ │ │ │ ├── avro
│ │ │ │ └── NewsMessage.java
│ │ │ │ └── news
│ │ │ │ ├── AvroDeserializer.java
│ │ │ │ ├── NewsListener.java
│ │ │ │ └── NewsListenerConfig.java
│ │ └── resources
│ │ │ ├── application.properties
│ │ │ ├── avro
│ │ │ └── news-message.avsc
│ │ │ └── banner.txt
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── ivanfranchin
│ │ └── avroconsumerservice
│ │ └── AvroConsumerServiceApplicationTests.java
├── avro-producer-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ivanfranchin
│ │ │ │ └── avroproducerservice
│ │ │ │ ├── AvroProducerServiceApplication.java
│ │ │ │ ├── avro
│ │ │ │ └── NewsMessage.java
│ │ │ │ ├── news
│ │ │ │ ├── AvroSerializer.java
│ │ │ │ ├── News.java
│ │ │ │ ├── NewsEmitter.java
│ │ │ │ └── NewsEmitterConfig.java
│ │ │ │ └── simulation
│ │ │ │ └── SimulationRunner.java
│ │ └── resources
│ │ │ ├── application.properties
│ │ │ ├── avro
│ │ │ └── news-message.avsc
│ │ │ └── banner.txt
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── ivanfranchin
│ │ └── avroproducerservice
│ │ └── AvroProducerServiceApplicationTests.java
└── pom.xml
├── build-docker-images.sh
├── docker-compose.yml
├── documentation
├── avro-2-de-serialization.excalidraw
├── avro-2-de-serialization.jpeg
├── avro-3-de-serialization.excalidraw
├── avro-3-de-serialization.jpeg
├── avro-de-serialization.excalidraw
├── avro-de-serialization.jpeg
├── json-de-serialization.excalidraw
├── json-de-serialization.jpeg
├── string-de-serialization.excalidraw
└── string-de-serialization.jpeg
├── json-de-serialization
├── README.md
├── json-consumer-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ivanfranchin
│ │ │ │ └── jsonconsumerservice
│ │ │ │ ├── JsonConsumerServiceApplication.java
│ │ │ │ └── news
│ │ │ │ ├── News.java
│ │ │ │ ├── NewsListener.java
│ │ │ │ └── NewsListenerConfig.java
│ │ └── resources
│ │ │ ├── application.properties
│ │ │ └── banner.txt
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── ivanfranchin
│ │ └── jsonconsumerservice
│ │ └── JsonConsumerServiceApplicationTests.java
├── json-producer-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ivanfranchin
│ │ │ │ └── jsonproducerservice
│ │ │ │ ├── JsonProducerServiceApplication.java
│ │ │ │ ├── news
│ │ │ │ ├── News.java
│ │ │ │ ├── NewsEmitter.java
│ │ │ │ └── NewsEmitterConfig.java
│ │ │ │ └── simulation
│ │ │ │ └── SimulationRunner.java
│ │ └── resources
│ │ │ ├── application.properties
│ │ │ └── banner.txt
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── ivanfranchin
│ │ └── jsonproducerservice
│ │ └── JsonProducerServiceApplicationTests.java
└── pom.xml
├── mvnw
├── mvnw.cmd
├── my-functions.sh
├── pom.xml
├── remove-docker-images.sh
└── string-de-serialization
├── README.md
├── pom.xml
├── string-consumer-service
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── ivanfranchin
│ │ │ └── stringconsumerservice
│ │ │ ├── StringConsumerServiceApplication.java
│ │ │ └── news
│ │ │ ├── NewsListener.java
│ │ │ └── NewsListenerConfig.java
│ └── resources
│ │ ├── application.properties
│ │ └── banner.txt
│ └── test
│ └── java
│ └── com
│ └── ivanfranchin
│ └── jsonconsumerservice
│ └── StringConsumerServiceApplicationTests.java
└── string-producer-service
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── ivanfranchin
│ │ └── stringproducerservice
│ │ ├── StringProducerServiceApplication.java
│ │ ├── news
│ │ ├── News.java
│ │ ├── NewsEmitter.java
│ │ └── NewsEmitterConfig.java
│ │ └── simulation
│ │ └── SimulationRunner.java
└── resources
│ ├── application.properties
│ └── banner.txt
└── test
└── java
└── com
└── ivanfranchin
└── jsonproducerservice
└── StringProducerServiceApplicationTests.java
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: ivangfr
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### STS ###
7 | .apt_generated
8 | .classpath
9 | .factorypath
10 | .project
11 | .settings
12 | .springBeans
13 | .sts4-cache
14 |
15 | ### IntelliJ IDEA ###
16 | .idea
17 | *.iws
18 | *.iml
19 | *.ipr
20 |
21 | ### NetBeans ###
22 | /nbproject/private/
23 | /nbbuild/
24 | /dist/
25 | /nbdist/
26 | /.nb-gradle/
27 | build/
28 | !**/src/main/**/build/
29 | !**/src/test/**/build/
30 |
31 | ### VS Code ###
32 | .vscode/
33 |
34 | ### MAC OS ###
35 | *.DS_Store
36 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | wrapperVersion=3.3.2
18 | distributionType=only-script
19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # spring-kafka-de-serialization-types
2 |
3 | The goal of this project is to play with [`Spring for Apache Kafka`](https://docs.spring.io/spring-kafka/reference/index.html). We've implemented 5 examples of `producer` and `consumer` services that exchanges messages through [`Apache Kafka`](https://kafka.apache.org/) using different types of serialization and approaches.
4 |
5 | ## Proof-of-Concepts & Articles
6 |
7 | On [ivangfr.github.io](https://ivangfr.github.io), I have compiled my Proof-of-Concepts (PoCs) and articles. You can easily search for the technology you are interested in by using the filter. Who knows, perhaps I have already implemented a PoC or written an article about what you are looking for.
8 |
9 | ## Examples
10 |
11 | The following examples demonstrate a **producer** that pushes _"News"_ messages to a topic in `Kafka` and a **consumer** that listens those messages from `Kafka`.
12 |
13 | | Example | Diagram |
14 | |--------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------|
15 | | [string-de-serialization](https://github.com/ivangfr/spring-kafka-de-serialization-types/tree/master/string-de-serialization#spring-kafka-de-serialization-types) |  |
16 | | [json-de-serialization](https://github.com/ivangfr/spring-kafka-de-serialization-types/tree/master/json-de-serialization#spring-kafka-de-serialization-types) |  |
17 | | [avro-de-serialization](https://github.com/ivangfr/spring-kafka-de-serialization-types/tree/master/avro-de-serialization#spring-kafka-de-serialization-types) |  |
18 | | [avro-2-de-serialization](https://github.com/ivangfr/spring-kafka-de-serialization-types/tree/master/avro-2-de-serialization#spring-kafka-de-serialization-types) |  |
19 | | [avro-3-de-serialization](https://github.com/ivangfr/spring-kafka-de-serialization-types/tree/master/avro-3-de-serialization#spring-kafka-de-serialization-types) |  |
20 |
21 | ## Prerequisites
22 |
23 | - [`Java 21+`](https://www.oracle.com/java/technologies/downloads/#java21)
24 | - Some containerization tool [`Docker`](https://www.docker.com), [`Podman`](https://podman.io), etc.
25 |
26 | ## Start Environment
27 |
28 | - Open a terminal and inside the `spring-kafka-de-serialization-types` root folder run:
29 | ```
30 | docker compose up -d
31 | ```
32 |
33 | - Wait for Docker containers to be up and running. To check it, run:
34 | ```
35 | docker ps -a
36 | ```
37 |
38 | ## Useful Links
39 |
40 | - **Schema Registry UI**
41 |
42 | `Schema Registry UI` can be accessed at http://localhost:8001
43 |
44 | - **Kafka Topics UI**
45 |
46 | `Kafka Topics UI` can be accessed at http://localhost:8085
47 |
48 | - **Kafka Manager**
49 |
50 | `Kafka Manager` can be accessed at http://localhost:9000
51 |
52 | _Configuration_
53 | - First, you must create a new cluster. Click on `Cluster` (dropdown on the header) and then on `Add Cluster`;
54 | - Type the name of your cluster in `Cluster Name` field, for example: `MyCluster`;
55 | - Type `zookeeper:2181` in `Cluster Zookeeper Hosts` field;
56 | - Enable checkbox `Poll consumer information (Not recommended for large # of consumers if ZK is used for offsets tracking on older Kafka versions)`;
57 | - Click on `Save` button at the bottom of the page.
58 |
59 | ## Shutdown
60 |
61 | To stop and remove docker compose containers, network and volumes, go to a terminal and, inside the `spring-kafka-de-serialization-types` root folder, run the command below:
62 | ```
63 | docker compose down -v
64 | ```
65 |
66 | ## Cleanup
67 |
68 | To remove the Docker created by this project, go to a terminal and, inside the `spring-kafka-de-serialization-types` root folder, run the following script:
69 | ```
70 | ./remove-docker-images.sh all
71 | ```
72 |
73 | ## References
74 |
75 | - https://codenotfound.com/spring-kafka-consumer-producer-example.html
76 | - https://codenotfound.com/spring-kafka-json-serializer-deserializer-example.html
77 | - https://codenotfound.com/spring-kafka-apache-avro-serializer-deserializer-example.html
--------------------------------------------------------------------------------
/avro-2-de-serialization/README.md:
--------------------------------------------------------------------------------
1 | # spring-kafka-de-serialization-types
2 | ## `> avro-2-de-serialization`
3 |
4 | 
5 |
6 | This sample demonstrates a **producer** that pushes `News` messages to a topic in `Kafka` and a **consumer** that listens those messages from `Kafka`:
7 | - **Producer** serializes the message `key` using `StringSerializer` and the message `value` using `KafkaAvroSerializer`;
8 | - **Consumer** deserializes the message `key` using `StringDeserializer` and the message `value` using `KafkaAvroDeserializer`;
9 | - This type of serialization uses `Schema Registry`;
10 | - The Java class generated from the `Avro` schema **MUST** have the same `name` and `package (or namespace)` in the producer and the consumer;
11 | - **Producer** creates the Kafka topics and **Consumer** doesn't.
12 |
13 | ## Start Environment
14 |
15 | Before starting producer and consumer, the services present in `docker-compose.yml` file must be up and running as explained in [Start Environment](https://github.com/ivangfr/spring-kafka-de-serialization-types#start-environment) section of the main README:
16 |
17 | ## Running applications using Maven
18 |
19 | > **Note**: run `avro-2-producer-service` first so that it can create the `Kafka` topics.
20 |
21 | - **avro-2-producer-service**
22 |
23 | - Open a terminal and navigate to the `spring-kafka-de-serialization-types` root folder;
24 | - Run application:
25 | ```
26 | ./mvnw clean spring-boot:run --projects avro-2-de-serialization/avro-2-producer-service
27 | ```
28 | > The Java class `com.ivanfranchin.commons.avroserialization.avro.NewsMessage` is generated by the Avro file `news-message.avsc` present in `src/main/resources/avro` by running the command:
29 | > ```
30 | > ./mvnw generate-sources --projects avro-2-de-serialization/avro-2-producer-service
31 | > ```
32 | - As soon as the producer is up and running, it will start pushing automatically and randomly `News` messages to `Kafka` topic `avro-2-de-serialization-news`. The default `interval` between messages is `3 seconds`.
33 |
34 | - **avro-2-consumer-service**
35 |
36 | - Open another terminal and make sure you are in `spring-kafka-de-serialization-types` root folder;
37 | - Run application:
38 | ```
39 | ./mvnw clean spring-boot:run --projects avro-2-de-serialization/avro-2-consumer-service
40 | ```
41 | > The Java class `com.ivanfranchin.commons.avroserialization.avro.NewsMessage` is generated by the Avro file `news-message.avsc` present in `src/main/resources/avro` by running the command:
42 | > ```
43 | > ./mvnw generate-sources --projects avro-2-de-serialization/avro-2-consumer-service
44 | > ```
45 | - Once the consumer is up and running, it will start listening `News` messages from the `Kafka` topic `avro-2-de-serialization-news`.
46 |
47 | ## Running applications as Docker containers
48 |
49 | - ### Build Docker images
50 |
51 | In a terminal and, inside the `spring-kafka-de-serialization-types` root folder, run:
52 | ```
53 | ./build-docker-images.sh avro-2-de-serialization
54 | ```
55 |
56 | - ### Environment variables
57 |
58 | **avro-2-producer-service** and **avro-2-consumer-service**
59 |
60 | | Environment Variable | Description |
61 | |------------------------|-------------------------------------------------------------------------|
62 | | `KAFKA_HOST` | Specify host of the `Kafka` message broker to use (default `localhost`) |
63 | | `KAFKA_PORT` | Specify port of the `Kafka` message broker to use (default `29092`) |
64 | | `SCHEMA_REGISTRY_HOST` | Specify host of the `Schema Registry` to use (default `localhost`) |
65 | | `SCHEMA_REGISTRY_PORT` | Specify port of the `Schema Registry` to use (default `8081`) |
66 |
67 | - ### Run Docker containers
68 |
69 | > **Note**: run `avro-2-producer-service` first so that it can create the `Kafka` topics.
70 |
71 | - **avro-2-producer-service**
72 |
73 | In a terminal, run the following Docker command:
74 | ```
75 | docker run --rm --name avro-2-producer-service -p 9086:9086 \
76 | -e KAFKA_HOST=kafka -e KAFKA_PORT=9092 -e SCHEMA_REGISTRY_HOST=schema-registry \
77 | --network=spring-kafka-de-serialization-types_default \
78 | ivanfranchin/avro-2-producer-service:1.0.0
79 | ```
80 |
81 | - **avro-2-consumer-service**
82 |
83 | In another terminal, run the Docker command below:
84 | ```
85 | docker run --rm --name avro-2-consumer-service -p 9087:9087 \
86 | -e KAFKA_HOST=kafka -e KAFKA_PORT=9092 -e SCHEMA_REGISTRY_HOST=schema-registry \
87 | --network=spring-kafka-de-serialization-types_default \
88 | ivanfranchin/avro-2-consumer-service:1.0.0
89 | ```
90 |
91 | ## Shutdown
92 |
93 | - Go to the terminals where the applications are running and press `Ctrl+C`;
94 | - Stop the services present in `docker-compose.yml` as explained in [Shutdown](https://github.com/ivangfr/spring-kafka-de-serialization-types#shutdown) section of the main README.
95 |
96 | ## Cleanup
97 |
98 | To remove the Docker images created by this example, go to a terminal and, inside the `spring-kafka-de-serialization-types` root folder, run the following script:
99 | ```
100 | ./remove-docker-images.sh avro-2-de-serialization
101 | ```
102 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-consumer-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.ivanfranchin
7 | avro-2-de-serialization
8 | 1.0.0
9 | ../pom.xml
10 |
11 | avro-2-consumer-service
12 | avro-2-consumer-service
13 | Demo project for Spring Boot
14 |
15 |
16 | org.springframework.boot
17 | spring-boot-starter-web
18 |
19 |
20 | org.springframework.kafka
21 | spring-kafka
22 |
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-test
27 | test
28 |
29 |
30 | org.springframework.kafka
31 | spring-kafka-test
32 | test
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-consumer-service/src/main/java/com/ivanfranchin/avro2consumerservice/Avro2ConsumerServiceApplication.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro2consumerservice;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class Avro2ConsumerServiceApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(Avro2ConsumerServiceApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-consumer-service/src/main/java/com/ivanfranchin/avro2consumerservice/news/NewsListener.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro2consumerservice.news;
2 |
3 | import com.ivanfranchin.commons.avroserialization.avro.NewsMessage;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.kafka.annotation.KafkaListener;
7 | import org.springframework.kafka.listener.adapter.ConsumerRecordMetadata;
8 | import org.springframework.messaging.handler.annotation.Payload;
9 | import org.springframework.stereotype.Service;
10 |
11 | @Service
12 | public class NewsListener {
13 |
14 | private static final Logger log = LoggerFactory.getLogger(NewsListener.class);
15 |
16 | @KafkaListener(topics = "${spring.kafka.consumer.topic}", groupId = "${spring.kafka.consumer.group-id}")
17 | public void listen(@Payload NewsMessage newsMessage, ConsumerRecordMetadata metadata) {
18 | log.info("Received message\n---\nTOPIC: {}; PARTITION: {}; OFFSET: {};\nPAYLOAD: {}\n---",
19 | metadata.topic(), metadata.partition(), metadata.offset(), newsMessage);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-consumer-service/src/main/java/com/ivanfranchin/avro2consumerservice/news/NewsListenerConfig.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro2consumerservice.news;
2 |
3 | import com.ivanfranchin.commons.avroserialization.avro.NewsMessage;
4 | import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig;
5 | import io.confluent.kafka.serializers.KafkaAvroDeserializer;
6 | import io.confluent.kafka.serializers.KafkaAvroDeserializerConfig;
7 | import org.apache.kafka.clients.consumer.ConsumerConfig;
8 | import org.apache.kafka.common.serialization.StringDeserializer;
9 | import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.Configuration;
12 | import org.springframework.kafka.annotation.EnableKafka;
13 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
14 | import org.springframework.kafka.core.ConsumerFactory;
15 | import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
16 |
17 | import java.util.Map;
18 |
19 | @EnableKafka
20 | @Configuration
21 | public class NewsListenerConfig {
22 |
23 | private final KafkaProperties kafkaProperties;
24 |
25 | public NewsListenerConfig(KafkaProperties kafkaProperties) {
26 | this.kafkaProperties = kafkaProperties;
27 | }
28 |
29 | @Bean
30 | ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() {
31 | ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>();
32 | factory.setConsumerFactory(consumerFactory());
33 | factory.setConcurrency(kafkaProperties.getListener().getConcurrency());
34 | return factory;
35 | }
36 |
37 | @Bean
38 | ConsumerFactory consumerFactory() {
39 | Map props = kafkaProperties.buildConsumerProperties(null);
40 | props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
41 | props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, KafkaAvroDeserializer.class);
42 | props.put(ConsumerConfig.ALLOW_AUTO_CREATE_TOPICS_CONFIG, false);
43 |
44 | props.put(AbstractKafkaSchemaSerDeConfig.SCHEMA_REGISTRY_URL_CONFIG, kafkaProperties.getProperties().get("schema-registry-url"));
45 | props.put(KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG, true);
46 | return new DefaultKafkaConsumerFactory<>(props);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-consumer-service/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=9087
2 |
3 | spring.application.name=avro-2-consumer-service
4 |
5 | spring.kafka.bootstrap-servers=${KAFKA_HOST:localhost}:${KAFKA_PORT:29092}
6 | spring.kafka.properties.schema-registry-url=http://${SCHEMA_REGISTRY_HOST:localhost}:${SCHEMA_REGISTRY_PORT:8081}
7 | spring.kafka.consumer.group-id=avro-2-consumer-service-group
8 | spring.kafka.consumer.topic=avro-2-de-serialization-news
9 | spring.kafka.consumer.auto-offset-reset=earliest
10 | spring.kafka.listener.concurrency=2
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-consumer-service/src/main/resources/avro/news-message.avsc:
--------------------------------------------------------------------------------
1 | {
2 | "namespace": "com.ivanfranchin.commons.avroserialization.avro",
3 | "type": "record",
4 | "name": "NewsMessage",
5 | "fields": [
6 | {"name": "id", "type": "string"},
7 | {"name": "fromId", "type": "int"},
8 | {"name": "fromName", "type": "string"},
9 | {"name": "title", "type": "string"}
10 | ]
11 | }
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-consumer-service/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ____ _
2 | __ ___ ___ __ ___ |___ \ ___ ___ _ __ ___ _ _ _ __ ___ ___ _ __ ___ ___ _ ____ _(_) ___ ___
3 | / _` \ \ / / '__/ _ \ _____ __) |____ / __/ _ \| '_ \/ __| | | | '_ ` _ \ / _ \ '__|____/ __|/ _ \ '__\ \ / / |/ __/ _ \
4 | | (_| |\ V /| | | (_) |_____/ __/_____| (_| (_) | | | \__ \ |_| | | | | | | __/ | |_____\__ \ __/ | \ V /| | (_| __/
5 | \__,_| \_/ |_| \___/ |_____| \___\___/|_| |_|___/\__,_|_| |_| |_|\___|_| |___/\___|_| \_/ |_|\___\___|
6 | :: Spring Boot :: ${spring-boot.formatted-version}
7 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-consumer-service/src/test/java/com/ivanfranchin/avro2consumerservice/Avro2ConsumerServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro2consumerservice;
2 |
3 | import org.junit.jupiter.api.Disabled;
4 | import org.junit.jupiter.api.Test;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 |
7 | @Disabled
8 | @SpringBootTest
9 | class Avro2ConsumerServiceApplicationTests {
10 |
11 | @Test
12 | void contextLoads() {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-producer-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.ivanfranchin
7 | avro-2-de-serialization
8 | 1.0.0
9 | ../pom.xml
10 |
11 | avro-2-producer-service
12 | avro-2-producer-service
13 | Demo project for Spring Boot
14 |
15 |
16 | org.springframework.boot
17 | spring-boot-starter-web
18 |
19 |
20 | org.springframework.kafka
21 | spring-kafka
22 |
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-test
27 | test
28 |
29 |
30 | org.springframework.kafka
31 | spring-kafka-test
32 | test
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-producer-service/src/main/java/com/ivanfranchin/avro2producerservice/Avro2ProducerServiceApplication.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro2producerservice;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class Avro2ProducerServiceApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(Avro2ProducerServiceApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-producer-service/src/main/java/com/ivanfranchin/avro2producerservice/news/News.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro2producerservice.news;
2 |
3 | public record News(String id, Integer fromId, String fromName, String title) {
4 | }
5 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-producer-service/src/main/java/com/ivanfranchin/avro2producerservice/news/NewsEmitter.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro2producerservice.news;
2 |
3 | import com.ivanfranchin.commons.avroserialization.avro.NewsMessage;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
7 | import org.springframework.kafka.core.KafkaTemplate;
8 | import org.springframework.stereotype.Component;
9 |
10 | @Component
11 | public class NewsEmitter {
12 |
13 | private static final Logger log = LoggerFactory.getLogger(NewsEmitter.class);
14 |
15 | private final KafkaTemplate kafkaTemplate;
16 | private final KafkaProperties kafkaProperties;
17 |
18 | public NewsEmitter(KafkaTemplate kafkaTemplate, KafkaProperties kafkaProperties) {
19 | this.kafkaTemplate = kafkaTemplate;
20 | this.kafkaProperties = kafkaProperties;
21 | }
22 |
23 | public void send(NewsMessage newsMessage) {
24 | String kafkaTopic = kafkaProperties.getProducer().getProperties().get("topic");
25 | log.info("Sending News '{}' to topic '{}'", newsMessage, kafkaTopic);
26 | kafkaTemplate.send(kafkaTopic, String.valueOf(newsMessage.getFromId()), newsMessage);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-producer-service/src/main/java/com/ivanfranchin/avro2producerservice/news/NewsEmitterConfig.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro2producerservice.news;
2 |
3 | import com.ivanfranchin.commons.avroserialization.avro.NewsMessage;
4 | import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig;
5 | import io.confluent.kafka.serializers.KafkaAvroSerializer;
6 | import org.apache.kafka.clients.admin.AdminClientConfig;
7 | import org.apache.kafka.clients.admin.NewTopic;
8 | import org.apache.kafka.clients.producer.ProducerConfig;
9 | import org.apache.kafka.common.serialization.StringSerializer;
10 | import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
11 | import org.springframework.context.annotation.Bean;
12 | import org.springframework.context.annotation.Configuration;
13 | import org.springframework.kafka.core.DefaultKafkaProducerFactory;
14 | import org.springframework.kafka.core.KafkaAdmin;
15 | import org.springframework.kafka.core.KafkaTemplate;
16 | import org.springframework.kafka.core.ProducerFactory;
17 |
18 | import java.util.HashMap;
19 | import java.util.Map;
20 |
21 | @Configuration
22 | public class NewsEmitterConfig {
23 |
24 | private final KafkaProperties kafkaProperties;
25 |
26 | public NewsEmitterConfig(KafkaProperties kafkaProperties) {
27 | this.kafkaProperties = kafkaProperties;
28 | }
29 |
30 | @Bean
31 | KafkaTemplate kafkaTemplate() {
32 | return new KafkaTemplate<>(producerFactory());
33 | }
34 |
35 | @Bean
36 | ProducerFactory producerFactory() {
37 | Map props = kafkaProperties.buildProducerProperties(null);
38 | props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
39 | props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, KafkaAvroSerializer.class);
40 | props.put(AbstractKafkaSchemaSerDeConfig.SCHEMA_REGISTRY_URL_CONFIG, kafkaProperties.getProperties().get("schema-registry-url"));
41 | return new DefaultKafkaProducerFactory<>(props);
42 | }
43 |
44 | // As the application will create a topic in Kafka, it is advisable to update the BOOTSTRAP_SERVERS_CONFIG
45 | // property of KafkaAdmin with the configured bootstrap server URLs. Otherwise, it will default to 'localhost:9082'.
46 | @Bean
47 | KafkaAdmin kafkaAdmin() {
48 | Map configs = new HashMap<>();
49 | configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getBootstrapServers());
50 | return new KafkaAdmin(configs);
51 | }
52 |
53 | @Bean
54 | NewTopic newTopic() {
55 | Map producerProperties = kafkaProperties.getProducer().getProperties();
56 | return new NewTopic(producerProperties.get("topic"), Integer.parseInt(producerProperties.get("num-partitions")), (short) 1);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-producer-service/src/main/java/com/ivanfranchin/avro2producerservice/simulation/SimulationRunner.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro2producerservice.simulation;
2 |
3 | import com.ivanfranchin.avro2producerservice.news.News;
4 | import com.ivanfranchin.avro2producerservice.news.NewsEmitter;
5 | import com.ivanfranchin.commons.avroserialization.avro.NewsMessage;
6 | import org.springframework.boot.CommandLineRunner;
7 | import org.springframework.stereotype.Component;
8 |
9 | import java.util.UUID;
10 | import java.util.concurrent.Executors;
11 | import java.util.concurrent.TimeUnit;
12 |
13 | @Component
14 | public class SimulationRunner implements CommandLineRunner {
15 |
16 | private final NewsEmitter newsEmitter;
17 |
18 | public SimulationRunner(NewsEmitter newsEmitter) {
19 | this.newsEmitter = newsEmitter;
20 | }
21 |
22 | @Override
23 | public void run(String... args) {
24 | Executors.newSingleThreadScheduledExecutor()
25 | .scheduleAtFixedRate(this::generateAndSendNews, 0, 3, TimeUnit.SECONDS);
26 | }
27 |
28 | private void generateAndSendNews() {
29 | newsEmitter.send(toNewsMessage(generate()));
30 | }
31 |
32 | private NewsMessage toNewsMessage(News news) {
33 | return new NewsMessage(news.id(), news.fromId(), news.fromName(), news.title());
34 | }
35 |
36 | private News generate() {
37 | return new News(UUID.randomUUID().toString(), 1, "Channel", "Title");
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-producer-service/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=9086
2 |
3 | spring.application.name=avro-2-producer-service
4 |
5 | spring.kafka.bootstrap-servers=${KAFKA_HOST:localhost}:${KAFKA_PORT:29092}
6 | spring.kafka.properties.schema-registry-url=http://${SCHEMA_REGISTRY_HOST:localhost}:${SCHEMA_REGISTRY_PORT:8081}
7 | spring.kafka.producer.properties.topic=avro-2-de-serialization-news
8 | spring.kafka.producer.properties.num-partitions=4
9 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-producer-service/src/main/resources/avro/news-message.avsc:
--------------------------------------------------------------------------------
1 | {
2 | "namespace": "com.ivanfranchin.commons.avroserialization.avro",
3 | "type": "record",
4 | "name": "NewsMessage",
5 | "fields": [
6 | {"name": "id", "type": "string"},
7 | {"name": "fromId", "type": "int"},
8 | {"name": "fromName", "type": "string"},
9 | {"name": "title", "type": "string"}
10 | ]
11 | }
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-producer-service/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ____ _ _
2 | __ ___ ___ __ ___ |___ \ _ __ _ __ ___ __| |_ _ ___ ___ _ __ ___ ___ _ ____ _(_) ___ ___
3 | / _` \ \ / / '__/ _ \ _____ __) |____| '_ \| '__/ _ \ / _` | | | |/ __/ _ \ '__|____/ __|/ _ \ '__\ \ / / |/ __/ _ \
4 | | (_| |\ V /| | | (_) |_____/ __/_____| |_) | | | (_) | (_| | |_| | (_| __/ | |_____\__ \ __/ | \ V /| | (_| __/
5 | \__,_| \_/ |_| \___/ |_____| | .__/|_| \___/ \__,_|\__,_|\___\___|_| |___/\___|_| \_/ |_|\___\___|
6 | |_|
7 | :: Spring Boot :: ${spring-boot.formatted-version}
8 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/avro-2-producer-service/src/test/java/com/ivanfranchin/avro2producerservice/Avro2ProducerServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro2producerservice;
2 |
3 | import org.junit.jupiter.api.Disabled;
4 | import org.junit.jupiter.api.Test;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 |
7 | @Disabled
8 | @SpringBootTest
9 | class Avro2ProducerServiceApplicationTests {
10 |
11 | @Test
12 | void contextLoads() {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/avro-2-de-serialization/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.ivanfranchin
7 | spring-kafka-de-serialization-types
8 | 1.0.0
9 | ../pom.xml
10 |
11 | avro-2-de-serialization
12 | pom
13 | avro-2-de-serialization
14 | Demo project for Spring Boot
15 |
16 | 1.12.0
17 | 7.8.0
18 |
19 |
20 |
21 |
22 | org.apache.avro
23 | avro
24 | ${avro.version}
25 |
26 |
27 |
28 |
29 | io.confluent
30 | kafka-avro-serializer
31 | ${confluent-kafka-avro-serializer.version}
32 |
33 |
34 |
35 |
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-maven-plugin
40 |
41 |
42 | org.apache.avro
43 | avro-maven-plugin
44 | ${avro.version}
45 |
46 |
47 | generate-sources
48 |
49 | schema
50 |
51 |
52 | ${project.basedir}/src/main/resources/avro/
53 | ${project.basedir}/src/main/java
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | confluent
64 | https://packages.confluent.io/maven/
65 |
66 |
67 |
68 |
69 | avro-2-producer-service
70 | avro-2-consumer-service
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/avro-3-de-serialization/README.md:
--------------------------------------------------------------------------------
1 | # spring-kafka-de-serialization-types
2 | ## `> avro-3-de-serialization`
3 |
4 | 
5 |
6 | This sample demonstrates a **producer** that pushes `News` messages to a topic in `Kafka` and a **consumer** that listens those messages from `Kafka`:
7 | - **Producer** serializes the message `key` using `StringSerializer` and the message `value` using `KafkaAvroSerializer`;
8 | - **Consumer** deserializes message `key` using `StringSerializer` to the message `value` using `SpecificAvroWithSchemaDeserializer`;
9 | - This type of serialization/deserialization uses `Schema Registry`;
10 | - The Java class generated from the `Avro` schema **DOES NOT** need to have the same `name` and `package (or namespace)` in the producer and the consumer;
11 | - We needed to implement the `SpecificAvroWithSchemaDeserializer` class;
12 | - **Producer** creates the Kafka topics and **Consumer** doesn't.
13 |
14 | ## Start Environment
15 |
16 | Before starting producer and consumer, the services present in `docker-compose.yml` file must be up and running as explained in [Start Environment](https://github.com/ivangfr/spring-kafka-de-serialization-types#start-environment) section of the main README.
17 |
18 | ## Running applications using Maven
19 |
20 | > **Note**: run `avro-3-producer-service` first so that it can create the `Kafka` topics.
21 |
22 | - **avro-3-producer-service**
23 |
24 | - Open a terminal and navigate to the `spring-kafka-de-serialization-types` root folder;
25 | - Run application:
26 | ```
27 | ./mvnw clean spring-boot:run --projects avro-3-de-serialization/avro-3-producer-service
28 | ```
29 | > The Java class `com.ivanfranchin.avro3producerservice.avro.NewsMessage` is generated by the Avro file `news-message.avsc` present in `src/main/resources/avro` by running the command:
30 | > ```
31 | > ./mvnw generate-sources --projects avro-3-de-serialization/avro-3-producer-service
32 | > ```
33 | - As soon as the producer is up and running, it will start pushing automatically and randomly `News` messages to `Kafka` topic `avro-3-de-serialization-news`. The default `interval` between messages is `3 seconds`.
34 |
35 | - **avro-3-consumer-service**
36 |
37 | - Open another terminal and make sure you are in `spring-kafka-de-serialization-types` root folder;
38 | - Run application:
39 | ```
40 | ./mvnw clean spring-boot:run --projects avro-3-de-serialization/avro-3-consumer-service
41 | ```
42 | > The Java class `com.ivanfranchin.avro3consumerservice.avro.NewsMessage` is generated by the Avro file `news-message.avsc` present in `src/main/resources/avro` by running the command:
43 | > ```
44 | > ./mvnw generate-sources --projects avro-3-de-serialization/avro-3-consumer-service
45 | > ```
46 | - Once the consumer is up and running, it will start listening `News` messages from the `Kafka` topic `avro-3-de-serialization-news`.
47 |
48 | ## Running applications as Docker containers
49 |
50 | - ### Build Docker images
51 |
52 | In a terminal and, inside the `spring-kafka-de-serialization-types` root folder, run:
53 | ```
54 | ./build-docker-images.sh avro-3-de-serialization
55 | ```
56 |
57 | - ### Environment variables
58 |
59 | **avro-3-producer-service** and **avro-3-consumer-service**
60 |
61 | | Environment Variable | Description |
62 | |------------------------|-------------------------------------------------------------------------|
63 | | `KAFKA_HOST` | Specify host of the `Kafka` message broker to use (default `localhost`) |
64 | | `KAFKA_PORT` | Specify port of the `Kafka` message broker to use (default `29092`) |
65 | | `SCHEMA_REGISTRY_HOST` | Specify host of the `Schema Registry` to use (default `localhost`) |
66 | | `SCHEMA_REGISTRY_PORT` | Specify port of the `Schema Registry` to use (default `8081`) |
67 |
68 | - ### Run Docker containers
69 |
70 | > **Note**: run `avro-3-producer-service` first so that it can create the `Kafka` topics.
71 |
72 | - **avro-3-producer-service**
73 |
74 | In a terminal, run the following Docker command:
75 | ```
76 | docker run --rm --name avro-3-producer-service -p 9088:9088 \
77 | -e KAFKA_HOST=kafka -e KAFKA_PORT=9092 -e SCHEMA_REGISTRY_HOST=schema-registry \
78 | --network=spring-kafka-de-serialization-types_default \
79 | ivanfranchin/avro-3-producer-service:1.0.0
80 | ```
81 |
82 | - **avro-3-consumer-service**
83 |
84 | In another terminal, run the Docker command below:
85 | ```
86 | docker run --rm --name avro-3-consumer-service -p 9089:9089 \
87 | -e KAFKA_HOST=kafka -e KAFKA_PORT=9092 -e SCHEMA_REGISTRY_HOST=schema-registry \
88 | --network=spring-kafka-de-serialization-types_default \
89 | ivanfranchin/avro-3-consumer-service:1.0.0
90 | ```
91 |
92 | ## Shutdown
93 |
94 | - Go to the terminals where the applications are running and press `Ctrl+C`;
95 | - Stop the services present in `docker-compose.yml` as explained in [Shutdown](https://github.com/ivangfr/spring-kafka-de-serialization-types#shutdown) section of the main README.
96 |
97 | ## Cleanup
98 |
99 | To remove the Docker images created by this example, go to a terminal and, inside the `spring-kafka-de-serialization-types` root folder, run the following script:
100 | ```
101 | ./remove-docker-images.sh avro-3-de-serialization
102 | ```
103 |
--------------------------------------------------------------------------------
/avro-3-de-serialization/avro-3-consumer-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.ivanfranchin
7 | avro-3-de-serialization
8 | 1.0.0
9 | ../pom.xml
10 |
11 | avro-3-consumer-service
12 | avro-3-consumer-service
13 | Demo project for Spring Boot
14 |
15 |
16 | org.springframework.boot
17 | spring-boot-starter-web
18 |
19 |
20 | org.springframework.kafka
21 | spring-kafka
22 |
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-test
27 | test
28 |
29 |
30 | org.springframework.kafka
31 | spring-kafka-test
32 | test
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/avro-3-de-serialization/avro-3-consumer-service/src/main/java/com/ivanfranchin/avro3consumerservice/Avro3ConsumerServiceApplication.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro3consumerservice;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class Avro3ConsumerServiceApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(Avro3ConsumerServiceApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/avro-3-de-serialization/avro-3-consumer-service/src/main/java/com/ivanfranchin/avro3consumerservice/news/NewsListener.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro3consumerservice.news;
2 |
3 | import com.ivanfranchin.avro3consumerservice.avro.NewsMessage;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.kafka.annotation.KafkaListener;
7 | import org.springframework.kafka.listener.adapter.ConsumerRecordMetadata;
8 | import org.springframework.messaging.handler.annotation.Payload;
9 | import org.springframework.stereotype.Service;
10 |
11 | @Service
12 | public class NewsListener {
13 |
14 | private static final Logger log = LoggerFactory.getLogger(NewsListener.class);
15 |
16 | @KafkaListener(topics = "${spring.kafka.consumer.topic}", groupId = "${spring.kafka.consumer.group-id}")
17 | public void listen(@Payload NewsMessage newsMessage, ConsumerRecordMetadata metadata) {
18 | log.info("Received message\n---\nTOPIC: {}; PARTITION: {}; OFFSET: {};\nPAYLOAD: {}\n---",
19 | metadata.topic(), metadata.partition(), metadata.offset(), newsMessage);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/avro-3-de-serialization/avro-3-consumer-service/src/main/java/com/ivanfranchin/avro3consumerservice/news/NewsListenerConfig.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro3consumerservice.news;
2 |
3 | import com.ivanfranchin.avro3consumerservice.avro.NewsMessage;
4 | import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig;
5 | import io.confluent.kafka.serializers.KafkaAvroDeserializerConfig;
6 | import org.apache.kafka.clients.consumer.ConsumerConfig;
7 | import org.apache.kafka.common.serialization.StringDeserializer;
8 | import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 | import org.springframework.kafka.annotation.EnableKafka;
12 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
13 | import org.springframework.kafka.core.ConsumerFactory;
14 | import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
15 |
16 | import java.util.Map;
17 |
18 | @EnableKafka
19 | @Configuration
20 | public class NewsListenerConfig {
21 |
22 | private final KafkaProperties kafkaProperties;
23 |
24 | public NewsListenerConfig(KafkaProperties kafkaProperties) {
25 | this.kafkaProperties = kafkaProperties;
26 | }
27 |
28 | @Bean
29 | ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() {
30 | ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>();
31 | factory.setConsumerFactory(consumerFactory());
32 | factory.setConcurrency(kafkaProperties.getListener().getConcurrency());
33 | return factory;
34 | }
35 |
36 | @Bean
37 | ConsumerFactory consumerFactory() {
38 | Map props = kafkaProperties.buildConsumerProperties(null);
39 | props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
40 | props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, SpecificAvroWithSchemaDeserializer.class);
41 | props.put(ConsumerConfig.ALLOW_AUTO_CREATE_TOPICS_CONFIG, false);
42 |
43 | props.put(AbstractKafkaSchemaSerDeConfig.SCHEMA_REGISTRY_URL_CONFIG, kafkaProperties.getProperties().get("schema-registry-url"));
44 | props.put(KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG, true);
45 | props.put(SpecificAvroWithSchemaDeserializer.AVRO_VALUE_RECORD_TYPE, NewsMessage.class);
46 | return new DefaultKafkaConsumerFactory<>(props);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/avro-3-de-serialization/avro-3-consumer-service/src/main/java/com/ivanfranchin/avro3consumerservice/news/SpecificAvroWithSchemaDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.ivanfranchin.avro3consumerservice.news;
2 |
3 | import io.confluent.kafka.serializers.AbstractKafkaAvroDeserializer;
4 | import io.confluent.kafka.serializers.KafkaAvroDeserializerConfig;
5 | import org.apache.avro.Schema;
6 | import org.apache.kafka.common.serialization.Deserializer;
7 |
8 | import java.lang.reflect.Field;
9 | import java.util.Map;
10 |
11 | public class SpecificAvroWithSchemaDeserializer extends AbstractKafkaAvroDeserializer implements Deserializer