{"data":{"markdownRemark":{"id":"17783d38-67ad-5909-ad62-de6f2fc0e5d9","html":"<h2 id=\"overview\"><a href=\"#overview\" aria-label=\"overview permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Overview</h2>\n<p><a href=\"https://kafka.apache.org/\">Apache Kafka</a> is a distributed streaming platform which allows you to:</p>\n<ul>\n<li>Publish and subscribe to streams of records, like a message queue.</li>\n<li>Store stream of records.</li>\n<li>Process stream of records.</li>\n</ul>\n<p>This article will focus only on the first use-case, using Kafka as a message queue. We will go through producing messages and consuming messages. You can go to Apache Kafka’s <a href=\"https://kafka.apache.org/intro\">introduction</a> page for more details.</p>\n<h2 id=\"using-spring-for-apache-kafka\"><a href=\"#using-spring-for-apache-kafka\" aria-label=\"using spring for apache kafka permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Using Spring for Apache Kafka</h2>\n<p><a href=\"https://spring.io/projects/spring-kafka\">Spring for Apache Kafka</a> applies core Spring concepts to develop Kafka-based messaging solutions. It provides us with an abstraction over Kafka API’s so that we can focus on producing and consuming messages.</p>\n<p>There are other Spring-based Kafka solutions such as <a href=\"https://spring.io/projects/spring-integration\">Spring Integration</a> and <a href=\"https://spring.io/projects/spring-cloud-stream\">Spring Cloud Stream</a>, but we won’t need those for now.</p>\n<h2 id=\"installation-and-setup\"><a href=\"#installation-and-setup\" aria-label=\"installation and setup permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Installation and Setup</h2>\n<h3 id=\"kafka\"><a href=\"#kafka\" aria-label=\"kafka permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Kafka</h3>\n<p>This article assumes that you have installed Kafka and know how to start the server. If not, you can follow Kafka’s <a href=\"https://kafka.apache.org/quickstart#quickstart_download\">installation</a> guide. If you are on Mac OS and using <a href=\"https://brew.sh/\">Homebrew</a>, you can just do <code class=\"language-text\">brew install kafka</code> to install and then <code class=\"language-text\">brew services start kafka</code> to start the server.</p>\n<p>If you have the server running, create a topic (i.e. <code class=\"language-text\">person</code>). You can follow Kafka’s <a href=\"https://kafka.apache.org/quickstart#quickstart_createtopic\">topic creation</a> guide.</p>\n<h3 id=\"project-setup\"><a href=\"#project-setup\" aria-label=\"project setup permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Project Setup</h3>\n<p>Since we will be using Spring, we can get started by initialising a Spring Boot project with <a href=\"https://start.spring.io/\">Spring Initiliazr</a> with <em>Kafka messaging</em> as a dependency.</p>\n<p>In some cases we need to make sure that <em>spring-kafka, kafka-clients and Kafka installation (broker)</em> versions are compatible. Please use the compatibility table in the <a href=\"%20https://spring.io/projects/spring-kafka\">spring-kafka</a> project page if you encounter any problems.</p>\n<h2 id=\"sending-messages\"><a href=\"#sending-messages\" aria-label=\"sending messages permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Sending Messages</h2>\n<p>There are several ways you can produce messages using <em>spring-kafka</em>. The easiest way is to use <code class=\"language-text\">KafkaTemplate</code>. <em>spring-kafka</em> provides a default <code class=\"language-text\">KafkaTemplate</code> bean which uses <code class=\"language-text\">String</code> for the message key and <code class=\"language-text\">String</code> for the message itself. This may change depending on the <em>spring-kafka</em> version used, please refer to the appropriate <a href=\"https://spring.io/projects/spring-kafka#learn\">reference doc</a>.</p>\n<p>These are the bare minimum configurations we need to put into our <code class=\"language-text\">application.properties</code> or <code class=\"language-text\">application.yml</code> in order to use <code class=\"language-text\">KafkaTemplate:</code></p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">spring.kafka.bootstrap-servers=localhost:9092\nkafka.topics.person=person</code></pre></div>\n<p><code class=\"language-text\">spring.kafka.bootstrap-servers</code> is a <em>spring-kafka</em> property which configures our Kafka broker address. By default this is set to <code class=\"language-text\">localhost:9092</code>.</p>\n<p><code class=\"language-text\">kafka.topics.person</code> is our custom property for the topic which we created earlier. We will need to tell <code class=\"language-text\">KafkaTemplate</code> to which topic we should send our messages.</p>\n<p>We can test our application by making our main class implement <code class=\"language-text\">org.springframework.boot.CommandLineRunner</code> and using <code class=\"language-text\">KafkaTemplate</code> there.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@SpringBootApplication\npublic class SpringKafkaApplication implements CommandLineRunner {\n\n\t@Autowired\n\tprivate KafkaTemplate&lt;String, String&gt; kafkaTemplate;\n\n\t@Value(&quot;${kafka.topics.person}&quot;)\n\tprivate String topic;\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SpringKafkaApplication.class, args);\n\t}\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\tString message = &quot;{\\&quot;name\\&quot;: \\&quot;John Doe\\&quot;, \\&quot;age\\&quot;: 99}&quot;;\n\t\tkafkaTemplate.send(topic, message);\n\t}\n}</code></pre></div>\n<p>When we run the application you should see a log of the the producer configuration values. A shortened version looks like this:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">INFO --- [main] o.a.k.clients.producer.ProducerConfig: ProducerConfig values: \n\tacks = 1\n\tbatch.size = 16384\n\tbootstrap.servers = [localhost:9092]</code></pre></div>\n<p>If we want to set the message key ourselves, we can use the other <code class=\"language-text\">send</code> method which takes a message key: <code class=\"language-text\">send(String topic, String key, String data)</code>. The <code class=\"language-text\">send</code> method is an overloaded method, please refer to the appropriate <a href=\"https://spring.io/projects/spring-kafka#learn\">API doc</a> as needed.</p>\n<h2 id=\"consuming-messages\"><a href=\"#consuming-messages\" aria-label=\"consuming messages permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Consuming Messages</h2>\n<p>There are also several ways how we can consume messages. The easiest way is to use the <code class=\"language-text\">@KafkaListener</code> annotation on a method. For more information on how you can use <code class=\"language-text\">@KafkaListener</code>, please see the appropriate <a href=\"https://docs.spring.io/spring-kafka/docs/2.2.6.RELEASE/reference/html/#kafka-listener-annotation\">reference</a>.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Component\npublic class PersonEvents {\n\n    private static final Logger logger = LoggerFactory.getLogger(PersonEvents.class);\n\n    @KafkaListener(topics = &quot;${kafka.topics.person}&quot;)\n    public void handle(String message) {\n        logger.info(&quot;Received message: {}&quot;, message);\n    }\n}</code></pre></div>\n<p>The bare minimum information we need to give <code class=\"language-text\">@KafkaListener</code> is the topic it should subscribe or listen to. The <code class=\"language-text\">topics</code> attribute can be a <em>‘topic name’, ‘property-placeholder keys’</em> or <em>‘expressions’</em>. Our example uses a <em>property-placeholder key</em>.</p>\n<p><code class=\"language-text\">topics</code> is, actually, not the bare minimum we need for our <code class=\"language-text\">@KafkaListener</code> to work. Not seen in our example is the <code class=\"language-text\">groupId</code>. The <code class=\"language-text\">groupId</code> uniquely identifies the group of consumer processes to which our consumer belongs. Visit Kafka’s <a href=\"https://kafka.apache.org/intro\">introduction</a> for more information.</p>\n<p>We don’t see the <code class=\"language-text\">groupId</code> attribute here because we’ve set a default one for all of the listeners in our application in <code class=\"language-text\">application.properties</code> or <code class=\"language-text\">application.yml</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">spring.kafka.consumer.group-id=bobsantosjr\nspring.kafka.consumer.auto-offset-reset=earliest</code></pre></div>\n<p>If you want to override the default value set by <code class=\"language-text\">spring.kafka.consumer.group-id</code>, then you can set the <code class=\"language-text\">groupId</code> attribute of <code class=\"language-text\">@KafkaListener</code>.</p>\n<p>You might be wondering what <code class=\"language-text\">spring.kafka.consumer.auto-offset-reset</code> is. By default, a consumer is set to get the <code class=\"language-text\">latest</code> message from the topic. This means that a consumer won’t be able to read messages sent to a topic before it’s created and connected to the topic.</p>\n<p>In our example, we are sending the message using the <code class=\"language-text\">KafkaTemplate</code> and we are not sure if our consumer is ready when our message is sent. Setting the offset to <code class=\"language-text\">earliest</code> will make sure that our consumer will be able to read the message our <code class=\"language-text\">KafkaTemplate</code> produced. Just remember, you might not want to do this for your consumer group in a production environment.</p>\n<p>If there are no errors, you should see the log message we have in our listener:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">INFO --- [ntainer#0-0-C-1] c.bobsantosjr.springkafka.PersonEvents   : Received message: {&quot;name&quot;: &quot;John Doe&quot;, &quot;age&quot;: 99}</code></pre></div>\n<h2 id=\"converting-messages-to-pojos\"><a href=\"#converting-messages-to-pojos\" aria-label=\"converting messages to pojos permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Converting Messages to POJO’s</h2>\n<p>For non-trivial applications, you would want to consume messages and convert them to objects.</p>\n<p>And as always, <em>spring-kafka</em> provides us with several ways to easily convert our messages to objects.</p>\n<p>One of them is to use a deserializer called <code class=\"language-text\">JsonDeserializer</code>. However, this deserializer usually depends on message headers to infer the type conversion or you can create different consumer factory containers for each type you have. For more details on serialization and deserialization please see the <a href=\"https://docs.spring.io/spring-kafka/docs/2.2.6.RELEASE/reference/html/#serdes\">reference</a>.</p>\n<p>An easier way to do it is to create a <code class=\"language-text\">KafkaListenerContainerFactory</code> and set <code class=\"language-text\">StringJsonMessageConverter</code> as its converter.</p>\n<p>But first, we need to add the ever reliable <em>jackson</em> library as one of our dependencies for JSON processing:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">implementation &#39;com.fasterxml.jackson.core:jackson-databind:2.9.8&#39;</code></pre></div>\n<p>Let’s create a configuration class where we will override the default <code class=\"language-text\">KafkaListenerContainerFactory</code> bean:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Configuration\npublic class KafkaConfig {\n\n    @Bean\n    public KafkaListenerContainerFactory&lt;?&gt; kafkaListenerContainerFactory(KafkaProperties kafkaProperties) {\n        ConcurrentKafkaListenerContainerFactory&lt;String, String&gt; factory = new ConcurrentKafkaListenerContainerFactory&lt;&gt;();\n        factory.setConsumerFactory(consumerFactory(kafkaProperties));\n        factory.setMessageConverter(new StringJsonMessageConverter());\n\n        return factory;\n    }\n\n    private ConsumerFactory&lt;String, String&gt; consumerFactory(KafkaProperties kafkaProperties) {\n        return new DefaultKafkaConsumerFactory&lt;&gt;(kafkaProperties.buildConsumerProperties());\n    }\n}</code></pre></div>\n<p>If you don’t want to override the default <code class=\"language-text\">KafkaListenerContainerFactory</code> bean, you can create a new bean and then set the <code class=\"language-text\">containerFactory</code> attribute in your <code class=\"language-text\">@KafkaListener</code>.</p>\n<p>We need to create our POJO for the message:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">public class Person {\n    private String name;\n    private int age;\n\n   // getters and setters\n\n    @Override\n    public String toString() {\n        return &quot;Person{&quot; + &quot;name=&#39;&quot; + name + &#39;\\&#39;&#39; + &quot;, age=&quot; + age + &#39;}&#39;;\n    }\n}</code></pre></div>\n<p>And then we can replace our <code class=\"language-text\">handle</code> method’s parameter to be <code class=\"language-text\">Person</code> instead of <code class=\"language-text\">String</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@KafkaListener(topics = &quot;${kafka.topics.person}&quot;)\npublic void handle(Person person) {\n    logger.info(&quot;Received message: {}&quot;, person);\n}</code></pre></div>\n<p>Running our application will show us a log of the message like this:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">INFO --- [ntainer#0-0-C-1] c.bobsantosjr.springkafka.PersonEvents: Received message: Person{name=&#39;John Doe&#39;, age=99}</code></pre></div>\n<p>For more details on custom message conversion, you can check the <a href=\"https://docs.spring.io/spring-kafka/docs/2.2.6.RELEASE/reference/html/#spring-messaging-message-conversion\">reference</a>.</p>\n<h2 id=\"conclusion\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>There are a lot of ways how you can use <em>Kafka</em> in <em>Java</em>. Fortunately using <em>spring-kafka</em> gives us a very easy way to do messaging over <em>Kafka</em>. One of its main advantages is it’s very good reference and documentation. You can find the list of references and documentation <a href=\"https://spring.io/projects/spring-kafka#learn\">here</a>.</p>\n<p>You can also easily customise <em>spring-kafka</em> by adding or changing configuration through properties. If you find yourself searching for the correct property, just search for <code class=\"language-text\">spring.kafka</code> in this very helpful <a href=\"https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html\">appendix</a>.</p>\n<p>The code sample is available at my <a href=\"https://github.com/bobsantos/spring-kafka-demo\">GitHub</a>. The <code class=\"language-text\">master</code> branch has the simple string producer and consumer. The custom message conversion is in the <code class=\"language-text\">json-converter</code> branch.</p>","fields":{"slug":"introduction-to-spring-kafka","tagSlugs":["/tag/kafka/","/tag/spring/","/tag/spring-kafka/","/tag/simple-message/","/tag/pojo-based-message/"]},"frontmatter":{"date":"2019-05-30T18:20:30.841Z","description":"This is an introduction to Spring for Apache Kafka that tackles producing and consuming messages.","tags":["kafka","spring","spring-kafka","simple-message","pojo-based-message"],"title":"Introduction to Spring Kafka"}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"slug":"introduction-to-spring-kafka"}}