<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jonathan</title>
    <description>The latest articles on DEV Community by Jonathan (@jhonifaber).</description>
    <link>https://dev.to/jhonifaber</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F348641%2F9b2aebe8-f9b9-4da0-894e-72a55383f977.jpg</url>
      <title>DEV Community: Jonathan</title>
      <link>https://dev.to/jhonifaber</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jhonifaber"/>
    <language>en</language>
    <item>
      <title>Java Collections: From Lists to Maps with Time Complexity in Mind</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Thu, 07 Aug 2025 09:38:37 +0000</pubDate>
      <link>https://dev.to/jhonifaber/choosing-the-right-java-collection-5750</link>
      <guid>https://dev.to/jhonifaber/choosing-the-right-java-collection-5750</guid>
      <description>&lt;p&gt;Java’s Collection Framework is powerful, but knowing when to use ArrayList, LinkedList, HashMap, Queue, or Deque can make a big difference in the performance and readability of your code. In this article, I’ll guide you through real world scenarios, time complexities, and examples to help you choose the right data structure depending on your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Large lists where random access is frequent. Fast index access? --&amp;gt; ArrayList
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time Complexity&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access by index: O(1)&lt;/li&gt;
&lt;li&gt;Insert/remove at end: O(1) - (except when capacity is exceeded)&lt;/li&gt;
&lt;li&gt;Insert/remove in middle or beginning: O(n)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Apple"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Banana"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Fast because we know the position of what we are looking for: "Banana"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Don't use&lt;/strong&gt; ArrayList for frequent insertions or removals at the beginning or middle, it needs to move subsequent elements and reindex them, which can degrade performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Frequent Insert/Remove at Beginning or End or modifying element during Iteration? --&amp;gt; LinkedList
&lt;/h2&gt;

&lt;p&gt;If your operations involve adding or removing elements at the beginning or end, LinkedList is more efficient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time Complexity:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add/remove at beginning/end: O(1)&lt;/li&gt;
&lt;li&gt;Access by index: O(n)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LinkedList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"first"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Zero"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// Fast&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addLast&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"last"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// Fast&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeFirst&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;        &lt;span class="c1"&gt;// Fast&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Don’t use&lt;/strong&gt; LinkedList for index-based access, it’s slow compared to ArrayList.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Key-based lookup? --&amp;gt; HashMap
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time Complexity:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get/put by key: O(1)&lt;/li&gt;
&lt;li&gt;Iteration over keys/values: O(n)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Fast lookup&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.1 HashMap vs TreeMap vs LinkedHashMap
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// HashMap: Fastest, no insertion ordering&lt;/span&gt;
&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hashMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// TreeMap: Sorted by keys, slower but natural ordering&lt;/span&gt;
&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;treeMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TreeMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Adding key-value pairs in random order&lt;/span&gt;
        &lt;span class="n"&gt;treeMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"zebra"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;treeMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apple"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;treeMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"monkey"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;treeMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"banana"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TreeMap: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;treeMap&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Output: {apple=2, banana=4, monkey=3, zebra=1} (always sorted by key!)&lt;/span&gt;

&lt;span class="c1"&gt;// LinkedHashMap: Maintains insertion order&lt;/span&gt;
&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;linkedHashMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LinkedHashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

        &lt;span class="n"&gt;linkedHashMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"first"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;linkedHashMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"second"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;linkedHashMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"third"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;linkedHashMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"second"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Updates existing key, maintains position&lt;/span&gt;
        &lt;span class="n"&gt;linkedHashMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fourth"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LinkedHashMap: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;linkedHashMap&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Output: {first=1, second=20, third=3, fourth=4} (insertion order preserved!)      &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Need Unique Elements Only? --&amp;gt; Set
&lt;/h2&gt;

&lt;p&gt;When you need to ensure no duplicates in your collection, use a Set.&lt;br&gt;
&lt;strong&gt;Time Complexity (HashSet):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add/remove/contains: O(1)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;uniqueEmails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;uniqueEmails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user@example.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;uniqueEmails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"admin@example.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;uniqueEmails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user@example.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Duplicate - won't be added&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Variants:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;HashSet&lt;/code&gt;: Fastest, no ordering&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TreeSet&lt;/code&gt;: Sorted unique elements&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LinkedHashSet&lt;/code&gt;: Unique + insertion order preserved&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Process Items In The Order They Arrived (FIFO) --&amp;gt; Queue
&lt;/h2&gt;

&lt;p&gt;Interface: &lt;code&gt;Queue&lt;/code&gt;&lt;br&gt;
Implementations: &lt;code&gt;LinkedList&lt;/code&gt;, &lt;code&gt;ArrayDeque&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time Complexity:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add (offer): O(1)&lt;/li&gt;
&lt;li&gt;Remove (poll): O(1)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LinkedList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;offer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Task1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;offer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Task2"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;poll&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "Task1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Double-Ended Queue --&amp;gt; Deque
&lt;/h2&gt;

&lt;p&gt;Interface: &lt;code&gt;Deque&lt;/code&gt;&lt;br&gt;
Implementations: &lt;code&gt;ArrayDeque&lt;/code&gt;, &lt;code&gt;LinkedList&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time Complexity:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add/remove from both ends: O(1)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Deque&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayDeque&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addFirst&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"First"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addLast&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Last"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeLast&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "Last"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>java</category>
      <category>algorithms</category>
      <category>performance</category>
    </item>
    <item>
      <title>Virtual Threads in Java: A Lightweight Concurrency Revolution</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Fri, 11 Jul 2025 10:31:00 +0000</pubDate>
      <link>https://dev.to/jhonifaber/virtual-threads-in-java-a-lightweight-concurrency-revolution-7hb</link>
      <guid>https://dev.to/jhonifaber/virtual-threads-in-java-a-lightweight-concurrency-revolution-7hb</guid>
      <description>&lt;p&gt;With the introduction of Virtual Threads in Java 21 as a preview feature (and stable in later versions), the way we think about concurrency in Java is changing dramatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Are Virtual Threads?
&lt;/h3&gt;

&lt;p&gt;In Java, when you want your program to do multiple things at the same time like handling lots of user requests, you typically use threads. But traditional threads (called platform threads) are expensive. Each one uses up a chunk of memory and is tied to a real thread in your computer's operating system (OS).&lt;/p&gt;

&lt;p&gt;If you try to create thousands of threads (like in a busy server), the system starts to struggle. That's why developers had to get clever, using tools like asynchronous code, callbacks, or reactive libraries like Reactor or WebFlux. These solutions work, but they’re harder to read, write, and debug.&lt;/p&gt;

&lt;p&gt;Virtual threads look and act like regular Java threads, but under the hood, they’re much lighter. Instead of being tied directly to OS threads, they’re managed by the JVM (Java Virtual Machine) itself. This means you can create millions of them without crashing your system.&lt;/p&gt;

&lt;p&gt;This is what a basic user service might look like using the classic, readable style:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/user/{id}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathVariable&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// blocking call&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is simple. It reads top-down, is easy to understand, and you can use try/catch or other flow control as expected.&lt;br&gt;
Below, we have the same code using Spring WebFlux and Project Reactor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Inside the userController class&lt;/span&gt;
&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/user/{id}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathVariable&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onErrorResume&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;just&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INTERNAL_SERVER_ERROR&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Inside the userService class&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;webClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;retrieve&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bodyToMono&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous example becomes harder because you’re no longer returning the result directly, you’re returning a Mono (a future-like wrapper). You need to chain callbacks (map, flatMap, onErrorResume, etc.) to handle logic and the Try/catch doesn’t work the same way, so error handling becomes more abstract.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Problem Do Virtual Threads Solve?
&lt;/h3&gt;

&lt;p&gt;Traditional Java threads can’t scale well when you need thousands of them.&lt;/p&gt;

&lt;p&gt;Let’s say you’re building a web server that handles one request per thread. With just a few hundred users, you're fine. But as traffic grows, the number of threads balloons, memory usage spikes, and performance drops. It’s just not sustainable.&lt;/p&gt;

&lt;p&gt;So developers switched to non-blocking, reactive code. This approach uses fewer threads and handles more work, but the code becomes harder to follow as we saw in the previous example.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Should You Use Virtual Threads?
&lt;/h3&gt;

&lt;p&gt;Virtual Threads shine when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to handle a &lt;strong&gt;high number of concurrent tasks&lt;/strong&gt; (one thread per request in a web server).&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;clean, readable synchronous style code&lt;/strong&gt; without reactive complexity.&lt;/li&gt;
&lt;li&gt;You're dealing with tasks that spend most of their time waiting on I/O (like database calls, API requests, or file operations).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Do Virtual Threads Replace WebFlux?
&lt;/h3&gt;

&lt;p&gt;Probably not entirely, but for many use cases, yes.&lt;/p&gt;

&lt;p&gt;Reactive programming (like Spring WebFlux or Reactor) became popular because traditional threads couldn’t handle high loads. But reactive code is harder to write and understand. With virtual threads, you can write simple, blocking code and still scale to thousands of requests.&lt;/p&gt;

&lt;p&gt;So if your app is mostly I/O-bound—like calling APIs, querying databases, or reading files, virtual threads can let you drop the complexity of reactive programming.&lt;/p&gt;

&lt;p&gt;Still, if you need fine grained control, backpressure, or advanced streaming, reactive might still make sense.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do Virtual Threads Eliminate Blocking?
&lt;/h3&gt;

&lt;p&gt;No — virtual threads do not magically make blocking go away. They just make it cheaper and more scalable.&lt;/p&gt;

&lt;p&gt;For example, if a virtual thread calls a blocking database operation or waits for a slow file read, that thread is still blocked. The difference is that the JVM can easily pause and resume virtual threads, so it can handle many more of them without exhausting OS resources. But the actual blocking, like waiting for a database response, still happens. To avoid blocking, you can use for example &lt;code&gt;CompletableFuture&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run tasks asynchronously without blocking the main thread.&lt;/li&gt;
&lt;li&gt;Chain operations (thenApply, thenCompose, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're not blocking on the result — you react when it's ready:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;future&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Simulate long-running task&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callApiOrDb&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenAccept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Got result: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Virtual threads are lightweight threads managed by the JVM, not the OS.&lt;/li&gt;
&lt;li&gt;They let you write blocking, synchronous code, without the overhead of traditional threads.&lt;/li&gt;
&lt;li&gt;Great for high concurrency, I/O-heavy applications.&lt;/li&gt;
&lt;li&gt;Makes complex reactive code unnecessary in many cases.&lt;/li&gt;
&lt;li&gt;A big step forward in making Java simpler and more powerful.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>From JVM to Native Compilation with Spring Boot: What It Means and Why It Matters</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Wed, 04 Jun 2025 23:09:46 +0000</pubDate>
      <link>https://dev.to/jhonifaber/from-jvm-to-native-compilation-with-spring-boot-what-it-means-and-why-it-matters-3nk5</link>
      <guid>https://dev.to/jhonifaber/from-jvm-to-native-compilation-with-spring-boot-what-it-means-and-why-it-matters-3nk5</guid>
      <description>&lt;p&gt;Traditionally, Java developers have followed the same standard flow: write Java code, compile it to &lt;strong&gt;bytecode&lt;/strong&gt;, and run it on the Java &lt;strong&gt;Virtual Machine (JVM)&lt;/strong&gt;. While this has worked well, it comes with trade-offs: slow startup, high memory usage, and a dependency on the JVM at runtime.&lt;/p&gt;

&lt;p&gt;Now, thanks to tools like &lt;strong&gt;Spring Native and GraalVM&lt;/strong&gt;, we can compile Spring Boot applications into native executables, binaries that start in milliseconds and consume a fraction of the memory. This lets Spring Boot apps run as fast and light as &lt;strong&gt;Quarkus&lt;/strong&gt;, without having to change to a different framework.&lt;/p&gt;

&lt;p&gt;In this article, I’ll explain what native compilation means, how it works, and why it makes a big difference for modern applications like microservices and serverless functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Traditional Java Compilation (JVM-Based)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Here’s how a traditional Java app works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You write Java code.&lt;/li&gt;
&lt;li&gt;The javac compiler turns it into bytecode (&lt;code&gt;.class&lt;/code&gt; files).&lt;/li&gt;
&lt;li&gt;You package everything into a &lt;code&gt;.jar&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You run it with the JVM: &lt;code&gt;java -jar myapp.jar&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At runtime, the JVM translates bytecode into machine code by either interpreting it or compiling it on the fly using just-in-time (JIT) compilation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slow startup (seconds)&lt;/li&gt;
&lt;li&gt;Higher memory usage&lt;/li&gt;
&lt;li&gt;Requires a JVM installed on the host machine&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Native Compilation: What’s New?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;With GraalVM Native Image, you can take your Java code and compile it into a native binary (like a .exe or Linux ELF file) that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs without the JVM&lt;/li&gt;
&lt;li&gt;Starts in milliseconds&lt;/li&gt;
&lt;li&gt;Uses significantly less memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is called ahead-of-time (AOT) compilation, the code is compiled to native machine instructions before it's run, not during runtime like with the JVM.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Spring Boot + Native Support&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Starting with Spring Boot 3.x, Spring officially supports AOT + native image compilation through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring AOT engine&lt;/li&gt;
&lt;li&gt;Spring Native (based on GraalVM)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means you can take your Spring Boot app and compile it into a self contained binary.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;JVM vs Native: Key Differences&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;JVM-based Spring Boot&lt;/th&gt;
&lt;th&gt;Native Spring Boot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Requires JVM&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup time&lt;/td&gt;
&lt;td&gt;Slow (seconds)&lt;/td&gt;
&lt;td&gt;Fast (milliseconds)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory usage&lt;/td&gt;
&lt;td&gt;High (100MB+)&lt;/td&gt;
&lt;td&gt;Low (20–40MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Packaging&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.jar&lt;/code&gt; file&lt;/td&gt;
&lt;td&gt;Native executable (&lt;code&gt;.exe&lt;/code&gt;, ELF)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ideal for&lt;/td&gt;
&lt;td&gt;Monoliths, legacy apps&lt;/td&gt;
&lt;td&gt;Microservices, serverless, CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;When Should You Use Native Compilation?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microservices&lt;/li&gt;
&lt;li&gt;Serverless functions (e.g., AWS Lambda, Cloud Run)&lt;/li&gt;
&lt;li&gt;Applications with short lifecycle and high scalability demands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Not ideal for&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Highly dynamic apps using a lot of runtime reflection (though Spring AOT is improving fast)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Native compilation brings a new level of performance and efficiency to Spring Boot applications. For the first time, you can write your app in Java and deploy it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;With zero JVM dependency&lt;/li&gt;
&lt;li&gt;With instant startup&lt;/li&gt;
&lt;li&gt;Using less memory&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Java is no longer just "write once, run anywhere", now it’s also &lt;strong&gt;fast, lightweight, and cloud-ready&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>performance</category>
      <category>graalvm</category>
    </item>
    <item>
      <title>How to Handle Millions of Rows in SQL Without Killing Performance</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Tue, 03 Jun 2025 15:39:09 +0000</pubDate>
      <link>https://dev.to/jhonifaber/how-to-handle-millions-of-rows-in-sql-without-killing-performance-57e0</link>
      <guid>https://dev.to/jhonifaber/how-to-handle-millions-of-rows-in-sql-without-killing-performance-57e0</guid>
      <description>&lt;p&gt;When working with massive datasets, an inefficient SQL query can significantly degrade database performance. One common mistake? Using a giant &lt;code&gt;IN (...)&lt;/code&gt; clause to filter a large set of values.&lt;/p&gt;

&lt;p&gt;This post shows you why &lt;strong&gt;JOIN&lt;/strong&gt; with a &lt;strong&gt;temporary table&lt;/strong&gt; is a smarter, faster alternative and how to apply it in a real use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Problem: IN with Too Many Values&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Imagine you have a huge table &lt;code&gt;transactions&lt;/code&gt; with more than 5 billion rows and you're trying to retrieve all the transactions for 10,000 specific users.&lt;/p&gt;

&lt;p&gt;The first and easy way that comes to our mind would be doing something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;102&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;103&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It may look simple, but it can lead to serious performance issues.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The DB might scan the entire table&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;IN&lt;/code&gt; list might not be optimized well&lt;/li&gt;
&lt;li&gt;Performance degrades fast as the list grows&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Solution: JOIN with a Temp Table&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Instead of passing a huge list, use a temporary table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TEMP&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;temp_user_ids&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that Temporary tables &lt;strong&gt;exist only for the duration of the session or transaction&lt;/strong&gt;, depending on the database.&lt;br&gt;
Now, insert your 10,000 user IDs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;temp_user_ids&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;102&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;103&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;temp_user_ids&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why is this better?&lt;/strong&gt;&lt;br&gt;
The database can use an index on transactions.user_id&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's easier to parallelize.&lt;/li&gt;
&lt;li&gt;It avoids large memory buffers and complex query plans.&lt;/li&gt;
&lt;li&gt;It's faster and more predictable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If your SQL query is slow and you're using a massive &lt;code&gt;IN (...)&lt;/code&gt; list, switch to a &lt;code&gt;JOIN&lt;/code&gt; with a &lt;code&gt;temp&lt;/code&gt; table. It’s faster, cleaner, and lets your database do what it does best: &lt;strong&gt;optimize joins using indexes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using a temporary table instead of a long &lt;code&gt;IN (...)&lt;/code&gt; list makes your SQL query faster and easier for the database to handle. When you use &lt;code&gt;IN&lt;/code&gt; with thousands of values, the database may get slow because it has to check each value one by one and might not use indexes properly. But with a temporary table, you can store all the values in one place, add an index, and let the database use a faster join method to find matches. This makes the query run quicker, use less memory, and work better with large amounts of data.&lt;/p&gt;

</description>
      <category>database</category>
      <category>sql</category>
      <category>performance</category>
    </item>
    <item>
      <title>Apache Kafka: Topics, Partitions, Brokers</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Tue, 22 Apr 2025 22:46:23 +0000</pubDate>
      <link>https://dev.to/jhonifaber/understanding-apache-kafka-topics-partitions-brokers-2182</link>
      <guid>https://dev.to/jhonifaber/understanding-apache-kafka-topics-partitions-brokers-2182</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In this post, we're going to take a deeper dive into Apache Kafka. If you'd like an introduction to Event-Driven Architectures, feel free to check out my &lt;a href="https://dev.to/jhonifaber/introduction-to-event-driven-architecture-eda-3ioj"&gt;previous article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Kafka is a powerful stream processing tool. It's like a super efficient digital post office for real time data. Instead of sending single letters, it handles streams of messages (like a continuous flow of packages) between different applications or systems. It's designed to be incredibly fast, reliable, and can manage huge amounts of data, making it perfect for things like tracking user activity on a website, processing financial transactions, or collecting data from sensors.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Producer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sends data or publishes messages to Kafka.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consumer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reads or subscribes to data from Kafka to process it. Multiple consumers can subscribe to the same data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Topic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;a specific channel or a category where different kinds of data are organized(like a queue). It's like having different mailboxes in a post office, each labeled for a particular type of mail. Producers send their messages to a specific topic, and consumers who are interested in that type of data will subscribe to that particular topic to receive the messages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Partition&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A physical division of a Topic. Messages within a Topic are split into Partitions for scalability and parallel processing. This division allows Kafka to handle more data and process it faster because different parts of the data can be processed at the same time.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Broker&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A Kafka server responsible for storing topic partitions and handling read and write requests from producers and consumers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cluster&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A group of Kafka brokers working together to provide fault tolerance and high availability.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Zookeeper&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A centralized service used for coordinating the Kafka cluster (configuration, synchronization, and group services; optional in newer versions). Kafka newer versions (2.8+) started moving away from Zookeeper, they introduced KRaft Mode, meaning Kafka can now manage itself without needing Zookeeper.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example of topic and partition to understand it better.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;topic&lt;/strong&gt; is like a book (it’s about a single subject — "Orders").&lt;br&gt;
&lt;strong&gt;Partitions&lt;/strong&gt; are chapters of the same book, breaking the content into smaller pieces so people can read/write different parts at the same time.&lt;br&gt;
Multiple topics would be different books ("Orders", "Payments", "Shipments").  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhoyvlgv3gehz250xddg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhoyvlgv3gehz250xddg.png" alt=" " width="800" height="824"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Why Partitions Matter?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; More partitions = more parallelism = faster reading/writing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordering:&lt;/strong&gt; Kafka guarantees message order within a single partition. If you use a key (like a user ID), all events with the same key are sent to the same partition, ensuring they are processed in order. While multiple user IDs can share the same partition, Kafka still maintains the correct order for each individual key. However, Kafka does not guarantee ordering across different partitions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistance:&lt;/strong&gt; Messages are kept for a configured time, even after being read.
&lt;strong&gt;What happens when the events have been consumed in Kafka? Are they removed from the topic?&lt;/strong&gt;
No, Kafka’s Model: Log-Based, Not Queue-Based. Events remain in the topic for a fixed period,even after being consumed. That means: &lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Events are written to a topic (which is like a log file). &lt;/li&gt;
&lt;li&gt;Consumers read from the log and track their own offset. &lt;strong&gt;The offset&lt;/strong&gt; is a pointer to the last message they successfully read.&lt;/li&gt;
&lt;li&gt;Events stay in the topic for a fixed duration (based on the retention time), even after they’ve been consumed.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fault tolerance:&lt;/strong&gt; Kafka replicates each partition, copies are made and stored on other brokers (servers). How? Each partition has a &lt;strong&gt;leader broker&lt;/strong&gt; that handles writes/reads. Another broker acts as a follower (replica) to back up the partition.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdzo6d9pdnlpsyirb4eh4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdzo6d9pdnlpsyirb4eh4.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Kafka Consumer Groups&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A consumer group is a set of consumers that collaboratively consume messages from Kafka topics. Typically, these are &lt;strong&gt;multiple instances of the same application&lt;/strong&gt; running in parallel, like three instances of a microservice deployed for load balancing. Inside a consumer group, each partition is assigned to only one consumer, so every message from a partition is processed by just one instance. This helps spread the workload evenly across the consumers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Does It Work?&lt;/strong&gt;&lt;br&gt;
Let’s say you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Kafka topic with 3 partitions (P0, P1, P2).&lt;/li&gt;
&lt;li&gt;A consumer group with 2 consumers/instances(EC2): C1 and C2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kafka will assign partitions to consumers in the group:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;C1 might read from P0 and P1.&lt;/li&gt;
&lt;li&gt;C2 reads from P2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each partition is read by only one consumer in the group at a time.&lt;br&gt;
But the same topic can be consumed by multiple different consumer groups independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Matters / What’s the Goal?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The goal is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Distribute the load between multiple service instances.&lt;/li&gt;
&lt;li&gt;Scale horizontally — more partitions = more consumers = more throughput.&lt;/li&gt;
&lt;li&gt;Make your system fault-tolerant, if one EC2 instance fails, Kafka can reassign its partition to the other instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Possible Scenario: One Instance Fails&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your Kafka topic has 2 partitions.&lt;/li&gt;
&lt;li&gt;You have 2 EC2 instances running your microservice (both are consumers in the same group).&lt;/li&gt;
&lt;li&gt;Instance 1 (Consumer A) → handles Partition 0&lt;/li&gt;
&lt;li&gt;Instance 2 (Consumer B) → handles Partition 1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suddenly, Instance 1 crashes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Kafka Does Automatically&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1.Detects the Failure&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kafka uses heartbeats to check if consumers are alive.&lt;/li&gt;
&lt;li&gt;If a consumer stops sending heartbeats (default timeout is ~10 seconds), Kafka marks it as dead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2.Triggers a Rebalance&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kafka reassigns the partitions that the dead consumer was handling.&lt;/li&gt;
&lt;li&gt;Now, Instance 2 (Consumer B) gets both Partition 0 and Partition 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3.Continues from Last Offset&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kafka tracks the offsets for each partition in the consumer group.&lt;/li&gt;
&lt;li&gt;Consumer B resumes from the last committed offset of Partition 0.&lt;/li&gt;
&lt;li&gt;No messages are lost or reprocessed unless your app is configured to do so.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What Happens When Instance 1 Comes Back?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It rejoins the consumer group.&lt;/li&gt;
&lt;li&gt;Kafka rebalances again.&lt;/li&gt;
&lt;li&gt;The workload (partitions) may be redistributed:&lt;/li&gt;
&lt;li&gt;Instance 1 may take back one of the partitions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Kafka Retention Time&lt;/strong&gt; &lt;code&gt;cleanup.policy=delete&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Means how long Kafka keeps a message in a topic, regardless of whether it's been read or not. The purpose is to allow consumers to re-read messages for a certain period of time (for recovery, auditing, or analytics).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does it work?&lt;/strong&gt;&lt;br&gt;
Set via topic configuration:&lt;br&gt;
retention.ms (in milliseconds): retention.ms = 604800000 → 7 days&lt;/p&gt;

&lt;p&gt;Kafka will delete old messages (per partition) after they reach this age and the disk space is available for new data.&lt;/p&gt;

&lt;p&gt;Note: You can also configure by size, using retention.bytes, but time based is more common.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Kafka Log Compaction&lt;/strong&gt; &lt;code&gt;cleanup.policy=compact&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Compaction is a process that ensures only the latest value for each key is retained in a topic. Useful for state stores, configurations, or changelogs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does it work?&lt;/strong&gt;&lt;br&gt;
Compaction is enabled by setting &lt;code&gt;cleanup.policy=compact&lt;/code&gt; (the default is &lt;code&gt;delete&lt;/code&gt;). You can also combine both policies by setting &lt;code&gt;cleanup.policy=compact,delete&lt;/code&gt;. In this case, Kafka will &lt;strong&gt;compact messages&lt;/strong&gt; to keep only the latest value per key, while &lt;strong&gt;also deleting older segments&lt;/strong&gt; based on the configured retention time or size.&lt;/p&gt;

&lt;p&gt;Kafka will keep the most recent message per key and remove older ones. Take into account that compaction is asynchronous, it runs in the background and is not instant. &lt;strong&gt;Kafka compaction is perfect&lt;/strong&gt; when each message represents an update to a specific key, and &lt;strong&gt;you only care about the most recent value&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine you write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;key1&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;value1&lt;/span&gt;
&lt;span class="n"&gt;key2&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;value2&lt;/span&gt;
&lt;span class="n"&gt;key1&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;value3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;key2&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;value2&lt;/span&gt;
&lt;span class="n"&gt;key1&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;value3&lt;/span&gt;   &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Serialization and Deserialization in Kafka&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Serialization:&lt;/strong&gt; converting data (an object, a record, or a message) into a &lt;strong&gt;byte stream&lt;/strong&gt;. Kafka requires all messages to be in a byte format, so producers must serialize data before sending it to Kafka.&lt;br&gt;
&lt;strong&gt;Deserialization:&lt;/strong&gt; reverse process, converting the byte stream back into the original data format.&lt;/p&gt;

&lt;p&gt;Kafka is &lt;strong&gt;format agnostic&lt;/strong&gt;, it doesn’t care what format your data is in, as long as it’s a &lt;strong&gt;byte array&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;producer&lt;/strong&gt; serializes the message into bytes.&lt;/li&gt;
&lt;li&gt;Kafka stores it.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;consumer&lt;/strong&gt; deserializes the message into a usable format (JSON, Avro, etc).&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Avro + Schema Registry Is the Preferred Choice&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Avro + Schema Registry is currently the most widely adopted serialization strategy in large scale systems with many microservices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Points&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compactness&lt;/strong&gt;:Avro serializes data in a compact binary format, which significantly reduces message size compared to JSON&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema validation&lt;/strong&gt;: Avro enforces a schema, which means producers and consumers both agree on the structure of the data. The schema itself isn't embedded in each message, only a small schema ID is sent — reducing payload size and allowing strong data contracts between services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema evolution&lt;/strong&gt;: Avro is designed to support changes over time, add optional fields, remove unused fields, change default values. This is crucial in microservices, where one team might update a service without breaking another.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At small scale, JSON is easier. But at enterprise or production scale, Avro makes data governance, backward compatibility, and performance manageable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Producer Side (Serialization)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a producer sends a message, it:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Serializes the object using the Avro schema.&lt;/li&gt;
&lt;li&gt;Registers the schema (if new) in the Schema Registry.&lt;/li&gt;
&lt;li&gt;Includes the schema ID in the message payload (usually as a small header or prefix).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Consumer Side (Deserialization)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the consumer receives a message, it:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Reads the schema ID from the message.&lt;/li&gt;
&lt;li&gt;Fetches the schema from the Schema Registry using that ID.&lt;/li&gt;
&lt;li&gt;Deserializes the message using the schema (to a GenericRecord or specific java class).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mod7rls3bwbfy1d6uhy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mod7rls3bwbfy1d6uhy.png" alt=" " width="800" height="295"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Let's see some code
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Avro serialization/deserialization using Confluent Schema Registry.&lt;/li&gt;
&lt;li&gt;Producer and consumer of a &lt;code&gt;User&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;Automatic generation of Java classes from .avsc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Avro Schema: src/main/avro/User.avsc&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"record"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"namespace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"com.example.kafka.avro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"null"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Kafka Configuration: application.yml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kafka&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;bootstrap-servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost:9092&lt;/span&gt; &lt;span class="c1"&gt;# where the Kafka broker(s) are running.&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;schema.registry.url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://localhost:8081&lt;/span&gt; &lt;span class="c1"&gt;# where the Confluent Schema Registry is running &lt;/span&gt;
    &lt;span class="na"&gt;producer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;key-serializer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org.apache.kafka.common.serialization.StringSerializer&lt;/span&gt;
      &lt;span class="na"&gt;value-serializer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;io.confluent.kafka.serializers.KafkaAvroSerializer&lt;/span&gt; &lt;span class="c1"&gt;# Converts the value (like an Avro User object) into binary Avro format, with metadata that links to its schema stored in Schema Registry&lt;/span&gt;
    &lt;span class="na"&gt;consumer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;key-deserializer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org.apache.kafka.common.serialization.StringDeserializer&lt;/span&gt;
      &lt;span class="na"&gt;value-deserializer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;io.confluent.kafka.serializers.KafkaAvroDeserializer&lt;/span&gt; &lt;span class="c1"&gt;# Converts the binary Avro back into a usable Java object, using the schema from Schema Registry.&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;specific.avro.reader&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Kafka uses the generated Avro class, which gives you compile-time type safety. If false, you'd get a GenericRecord&lt;/span&gt;
    &lt;span class="na"&gt;listener&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;missing-topics-fatal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;# it will not fail if the topic doesn’t exist yet — useful during development or if topics are created dynamically&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;KafkaProducer.java&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.example.kafka.avro.User&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.kafka.core.KafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.stereotype.Service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaProducer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;KafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;kafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;KafkaProducer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;kafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kafkaTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;kafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user-topic"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Produced User: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;KafkaConsumer.java&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.example.kafka.avro.User&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.kafka.annotation.KafkaListener&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.stereotype.Service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaConsumer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@KafkaListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"user-topic"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;groupId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"user-group"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;consume&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Consumed User: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;KafkaAvroApplication.java&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SpringBootApplication&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaAvroApplication&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CommandLineRunner&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;KafkaProducer&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KafkaAvroApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"u1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jhoni"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"jhoni@example.com"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kafka</category>
      <category>eventdriven</category>
      <category>architecture</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Understanding concepts in Event Driven Architectures (EDA)</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Wed, 02 Apr 2025 10:54:14 +0000</pubDate>
      <link>https://dev.to/jhonifaber/introduction-to-event-driven-architecture-eda-3ioj</link>
      <guid>https://dev.to/jhonifaber/introduction-to-event-driven-architecture-eda-3ioj</guid>
      <description>&lt;p&gt;Event Driven Architecture has become a very popular choice in recent times for developing highly scalable distributed systems. Is a way of designing software where different parts of the system communicate by sending and reacting to events.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;event&lt;/strong&gt; is something that happens, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user signs up&lt;/li&gt;
&lt;li&gt;A user uploads a photo&lt;/li&gt;
&lt;li&gt;A payment is completed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of making direct requests to each other, different parts of the system listen for these events and react when needed(asynchronously).&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;The Payment Service&lt;/em&gt; is completed and emits an event: "payment done".&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;The Inventory Service&lt;/em&gt; listens for that event and updates the stock for the new product that has been bought.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;The Email Service&lt;/em&gt; listens and sends a confirmation email.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's see a very simple diagram of the components in Event Driven Architecture &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Key Components&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7nvc22aj7zc04n5p8ql9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7nvc22aj7zc04n5p8ql9.png" alt=" " width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Event Producer/Publisher&lt;/strong&gt;&lt;br&gt;
The system or service that creates and emits events when something happens.&lt;br&gt;
Example: A User Service sends an event "User Registered" when a new user signs up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Message Broker&lt;/strong&gt;&lt;br&gt;
A message broker is a middleware that acts as an intermediary between event producers and event consumers. Its primary role is to receive, store, and route events efficiently, ensuring that the events are delivered to the correct consumer services.&lt;/p&gt;

&lt;p&gt;In this context, there is a crucial concept inside message brokers called &lt;strong&gt;Channels&lt;/strong&gt;. These channels act as communication routes that orchestrate the flow of events from producers to the right consumers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;Kafka&lt;/strong&gt;, these channels are called &lt;strong&gt;Topics&lt;/strong&gt;. It supports &lt;strong&gt;multi subscriber models&lt;/strong&gt;, allowing multiple consumers to listen to the same publisher.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;RabbitMQ&lt;/strong&gt;, these channels are called &lt;strong&gt;Queues&lt;/strong&gt;. RabbitMQ is typically &lt;strong&gt;point-to-point&lt;/strong&gt; for queues, meaning that only one consumer can process a message from a queue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example technologies: Kafka, RabbitMQ, AWS SNS/SQS, Google Pub/Sub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Event Consumer/Subscriber&lt;/strong&gt;&lt;br&gt;
The service that listens to events and reacts to them.&lt;br&gt;
Example: A Notification Service listens for "User Registered" and sends a welcome email.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Event&lt;/strong&gt;&lt;br&gt;
The actual message that describes what happened. It usually contains structured data (JSON, XML).&lt;br&gt;
Example event message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"event-123456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user.event.registered"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025-04-01T12:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"usr-98765"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"surname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Broker Exchanges&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In message brokers, an exchange is a routing mechanism that determines how messages are delivered to queues. Different types of exchanges provide different message distribution patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Direct Exchange (1:1 Routing)&lt;/strong&gt;&lt;br&gt;
Routes messages to queues based on an exact match between a routing key and a queue &lt;strong&gt;binding key&lt;/strong&gt; (RabbitMQ).&lt;br&gt;
How it works?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The producer sends a message with a routing key.&lt;/li&gt;
&lt;li&gt;The exchange forwards the message only to queues with a matching binding key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
A message with routing key = &lt;code&gt;"order.created"&lt;/code&gt; goes only to the queue bound with &lt;code&gt;"order.created"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pra4kdkq5gi6t7nxa49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pra4kdkq5gi6t7nxa49.png" alt=" " width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fanout Exchange (Broadcast)&lt;/strong&gt;&lt;br&gt;
Sends messages to all bound queues, &lt;strong&gt;ignoring the routing key&lt;/strong&gt; &lt;br&gt;
 (RabbitMQ-Fanout Exchange | Kafka-multiple consumers per topic).&lt;/p&gt;

&lt;p&gt;How it works?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The producer sends a message.&lt;/li&gt;
&lt;li&gt;The exchange copies the message to all queues bound to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
A notification event is broadcasted to multiple services (email, SMS, push notifications).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiuh8eqc9p7pmnv6h17qx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiuh8eqc9p7pmnv6h17qx.png" alt=" " width="800" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Topic Exchange (Pattern Matching)&lt;/strong&gt;&lt;br&gt;
Routes messages based on wildcard patterns in routing keys. Supports &lt;code&gt;*&lt;/code&gt;, matches one word and &lt;code&gt;#&lt;/code&gt;, matches multiple words. (RabbitMQ-Topic Exchange | Kafka-topics with partition keys).&lt;br&gt;
How it works?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;.&lt;/code&gt; to separate words in routing keys (&lt;code&gt;"order.payment.failed"&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
A queue bound to &lt;code&gt;"order.*"&lt;/code&gt; receives &lt;code&gt;"order.created"&lt;/code&gt; and &lt;code&gt;"order.cancelled"&lt;/code&gt;, but not &lt;code&gt;"user.created"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm14p35ghlut5yv4ssza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm14p35ghlut5yv4ssza.png" alt=" " width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Advantages of EDA&lt;/strong&gt; - &lt;a href="https://www.reactivemanifesto.org" rel="noopener noreferrer"&gt;Reactive Manifesto&lt;/a&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: decoupled services can scale independently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: easy to add new event consumers without modifying existing services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Processing&lt;/strong&gt;: enables real-time data streaming and quick responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilience&lt;/strong&gt;: failures in one service don’t impact the entire system as long as events and subscriptions are managed properly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loose Coupling&lt;/strong&gt;: components interact through events, reducing dependencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Disadvantages of EDA&lt;/strong&gt;:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Eventual consistency&lt;/strong&gt;: different parts of the system might temporarily have outdated information until all events are processed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex Debugging&lt;/strong&gt;: harder to trace issues across multiple async events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased Latency&lt;/strong&gt;: some events may take longer to be processed due to async nature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Duplications&lt;/strong&gt;: requires idempotency to avoid duplicate processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution when publishing?&lt;/strong&gt;&lt;br&gt;
For example, kafka has Idempotent Producer to prevent duplicate writes from retries. You can enable it in the configuration setup for your Kafka producer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"enable.idempotence"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Event Ordering Issues&lt;/strong&gt;: some brokers don’t guarantee message order (RabbitMQ).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning Curve&lt;/strong&gt;: requires expertise in event-driven design patterns.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you are thinking of implementing a distributed, real-time and highly scalable system, you should definitely consider implementing an event-driven architecture to take advantage of all the benefits it offers.&lt;/p&gt;

</description>
      <category>eventdriven</category>
      <category>architecture</category>
      <category>java</category>
      <category>springboot</category>
    </item>
    <item>
      <title>Domain Driven Design(DDD) - Understanding Main Concepts</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Tue, 18 Mar 2025 23:43:08 +0000</pubDate>
      <link>https://dev.to/jhonifaber/domain-driven-designddd-understanding-main-concepts-11p3</link>
      <guid>https://dev.to/jhonifaber/domain-driven-designddd-understanding-main-concepts-11p3</guid>
      <description>&lt;p&gt;Domain Driven Design(DDD) is a form of software design that focuses on understanding and reflecting the business in code. Clean Architectures in general work really well with DDD. This happens because of layered separation, where the domain is at the center, meaning the domain layer does not depend on anything external.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk04kx78m2nfct6qtdfwa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk04kx78m2nfct6qtdfwa.png" alt=" " width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Main Concepts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Domain&lt;/strong&gt;&lt;br&gt;
Is the business problem we are solving. A good domain model captures the essential business rules and behaviours while staying independent of infrastructure concerns. That's why it's important to use the same language as the domain/business team, ensuring that developers (technical) and domain experts (non technical) stay aligned. This is what its called, &lt;strong&gt;ubiquitous language&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Entities and Value Objects&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Entities are &lt;strong&gt;defined by their unique identity&lt;/strong&gt; and not by their attributes. Even if their properties change, they are still the same entity. &lt;br&gt;
For example, a &lt;code&gt;Customer&lt;/code&gt; is an entity because it has a unique identity (customer ID or email address) that distinguishes it from other customers. Even if the customer’s name, or other details change, the customer remains the same as long as the identity (ID or email) stays the same.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Value objects(VO), on the other hand, are &lt;strong&gt;defined by their attributes&lt;/strong&gt; and have no unique identity. Two value objects that have the same attributes are considered identical.&lt;br&gt;
For example, &lt;code&gt;Address&lt;/code&gt; can be a VO, two identical addresses (same street, same city, same postal code) are interchangeable and don't hold any unique identity beyond their attributes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In an organization, the structure can be composed of multiple entities, each with its corresponding value objects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg3a2ujwc7om703e41qn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg3a2ujwc7om703e41qn.png" alt=" " width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Aggregates and Aggregate Roots&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An aggregate is a group of related domain objects that should be treated as a single unit (have a look at the image below for a better understanding). This ensures consistency and encapsulate business rules.&lt;/li&gt;
&lt;li&gt;The aggregate root is the &lt;strong&gt;primary entity&lt;/strong&gt; that controls access to other objects within the aggregate. &lt;strong&gt;The aggregate root is always an entity and never a value object.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1mot52bsde9knvuindnu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1mot52bsde9knvuindnu.png" alt=" " width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aggregates communicate primarily through domain events. When something happens within one aggregate that needs to affect another aggregate, the first aggregate sends an event, and other aggregates are listening and react to that event.&lt;/p&gt;

&lt;p&gt;A more real life example of aggregates. In a library system, a library can manage multiple books, each with its own attributes such as title, author, and location within the library.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2hj5spkzypxocoftlyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2hj5spkzypxocoftlyt.png" alt=" " width="800" height="836"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Library (Aggregate Root)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Library is an entity because it has a unique identity (libraryId) and it represents the collection of books within the system.&lt;br&gt;
It is also the aggregate root, meaning it controls access to the other entities within the aggregate (the Book entities in this case).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Book (Entity)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Book is an entity because it also has a unique identity (the isbn) and it represents a specific book in the library collection.&lt;br&gt;
It is part of the Library aggregate, and its properties are managed through the Library.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;BookDetails and Location (VO)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are value objects because they don’t have an identity and are defined only by their attributes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Domain Services&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes, business logic does not naturally belong to an entity or value object. In such cases, we use domain services to encapsulate that logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Domain Events&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Domain events capture important occurrences within the business domain. For example, when a payment is completed, an event like PaymentCompleted can be published, triggering related actions such as sending an email notification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Bounded Contexts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This concept is a bit abstract. Bounded contexts, represents subdomains with its own models and logic. It's like a "boundary" that separates one part of a system from others. For example, in an online store, you might have one bounded context for order management and another for payment processing, each with its own models and logic.&lt;br&gt;
Don't mix aggregates and bounded contexts, aggregates are smaller groups and exist inside a bounded context, but bounded contexts help separate different business areas within the whole system&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;DDD is not just about structuring code, it’s a mindset shift that emphasizes deep collaboration with domain experts and models business logic in a way that is both clear and maintainable.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>java</category>
      <category>design</category>
      <category>domain</category>
    </item>
    <item>
      <title>Microservices vs. Monoliths: How to Choose the Right Architecture for Your Project</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Mon, 10 Mar 2025 11:18:22 +0000</pubDate>
      <link>https://dev.to/jhonifaber/microservices-vs-monoliths-how-to-choose-the-right-architecture-for-your-project-2bep</link>
      <guid>https://dev.to/jhonifaber/microservices-vs-monoliths-how-to-choose-the-right-architecture-for-your-project-2bep</guid>
      <description>&lt;p&gt;When designing a software system, one of the most crucial decisions is choosing the right architectural style. Should you build a monolithic application or adopt a microservices architecture? Both approaches have their advantages and drawbacks, and the best choice depends on factors like scalability, complexity, and team structure. In this post, we’ll break down the key differences, benefits, and when to use each approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is a Monolithic Architecture?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A monolithic application is built as a single unified unit where all components (UI, business logic, database operations, etc.) are tightly integrated and deployed together.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Advantages of Monoliths&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Easier to Develop and Deploy&lt;/strong&gt;: Everything is in one place. Easier to build, test, and deploy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Performance&lt;/strong&gt;: No request calls between different services (less latency).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier Debugging&lt;/strong&gt;: Having everything in one place makes fixing problems easier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less Maintenance Overhead&lt;/strong&gt;: No need for complex service management (load balancing, distributed tracing,...).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ &lt;strong&gt;Challenges of Monoliths&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Limited Scalability&lt;/strong&gt;: Scaling a monolithic application often means replicating the entire system, which can be inefficient and may not provide the same level of flexibility as scaling individual services in a microservices architecture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slower Development in Large Teams&lt;/strong&gt;: As the codebase grows, conflicts between teams can increase, and the development process can slow down due to bottlenecks, especially during merges and integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technology Lock-In&lt;/strong&gt;: The entire system is usually built with a single technology stack, limiting flexibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficult Continuous Deployment&lt;/strong&gt;: Any change requires redeploying the whole application, increasing the risk of failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40q25uvivsrqtedhs6m1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40q25uvivsrqtedhs6m1.png" alt=" " width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is a Microservices Architecture?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A microservices architecture breaks down an application into smaller, loosely coupled services that can be developed, deployed, and scaled independently. Each microservice is responsible for a specific business functionality and communicates with others via APIs.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Advantages of Microservices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Independent Scalability&lt;/strong&gt;: Scale only the services that need more resources instead of scaling the entire system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Development and Deployment&lt;/strong&gt;: Teams can work on different services independently, accelerating the development process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technology Flexibility&lt;/strong&gt;: Each service can use the most suitable technology stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Fault Isolation&lt;/strong&gt;: A failure in one service does not necessarily bring down the entire system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ &lt;strong&gt;Challenges of Microservices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Increased Complexity&lt;/strong&gt;: Managing multiple services, databases, and APIs requires more knowledge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Higher Operational Overhead&lt;/strong&gt;: Requires orchestration tools, monitoring solutions, service discovery, and API gateways.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network Latency&lt;/strong&gt;: Services communication over the network can introduce latency and performance issues, but tools like API Gateways and strategies like asynchronous communication (using message queues, for example) can help mitigate this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed Data Management&lt;/strong&gt;: Maintaining data consistency across services is more challenging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64h189o1byma68fvq56n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64h189o1byma68fvq56n.png" alt=" " width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;SAGA Pattern&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Is a commonly used pattern in microservices architecture to manage distributed transactions. Ensures data consistency using a series of local transactions, each with a compensating(rollback) action in case of failure.&lt;/p&gt;

&lt;p&gt;Simple Example: E-commerce Order&lt;br&gt;
You have 3 services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order Service: Creates an order.&lt;/li&gt;
&lt;li&gt;Payment Service: Charges the customer.&lt;/li&gt;
&lt;li&gt;Inventory Service: Reserves the product.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Success Scenario:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Order → OK&lt;/li&gt;
&lt;li&gt;Charge Payment → OK&lt;/li&gt;
&lt;li&gt;Reserve Inventory → OK
All done, order successful.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Failure Scenario (Inventory fails):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Order → OK&lt;/li&gt;
&lt;li&gt;Charge Payment → OK&lt;/li&gt;
&lt;li&gt;Reserve Inventory → fails&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Trigger compensating actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refund Payment&lt;/li&gt;
&lt;li&gt;Cancel Order&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Two Saga Types:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Choreography (event-based)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Services listen for events and react.&lt;/li&gt;
&lt;li&gt;No central orchestrator.&lt;/li&gt;
&lt;li&gt;Good for simple workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Orchestration (command-based)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One central orchestrator service tells others what to do.&lt;/li&gt;
&lt;li&gt;Easier to manage complex flows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Choosing between a monolithic or microservices architecture really comes down to what your application needs, the size of your team, and your long-term goals. Monolithic apps are simpler to start with, but as your project grows, they can become harder to manage. Microservices give you more flexibility and scalability, but they come with more complexity and maintenance. By understanding the pros and cons of each approach, you’ll be in a better position to pick the right one for your project.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>java</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>Designing a Scalable Architecture - with Some Spring Boot Examples</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Wed, 05 Mar 2025 22:55:33 +0000</pubDate>
      <link>https://dev.to/jhonifaber/designing-a-scalable-architecture-with-some-spring-boot-examples-340o</link>
      <guid>https://dev.to/jhonifaber/designing-a-scalable-architecture-with-some-spring-boot-examples-340o</guid>
      <description>&lt;p&gt;Scalability is a critical factor when designing modern backend systems. A well-structured &lt;strong&gt;Spring Boot&lt;/strong&gt; application should be able to handle increasing loads efficiently, ensuring reliability and performance. In this article, we’ll explore the best practices for building a &lt;strong&gt;scalable&lt;/strong&gt; architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Makes an Architecture Scalable?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A scalable system can handle increasing workloads by either &lt;strong&gt;scaling up (vertical scaling)&lt;/strong&gt; or &lt;strong&gt;scaling down (horizontal scaling)&lt;/strong&gt; while maintaining performance. The key factors that contribute to scalability include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Efficient resource management&lt;/li&gt;
&lt;li&gt;Stateless microservices&lt;/li&gt;
&lt;li&gt;Proper database scaling strategies&lt;/li&gt;
&lt;li&gt;Asynchronous processing&lt;/li&gt;
&lt;li&gt;Load balancing and caching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Scaling Approaches&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scaling Up (Vertical Scaling)&lt;/strong&gt; – Increasing the power of a single machine by adding more CPU, RAM, or storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scaling Down (Horizontal Scaling)&lt;/strong&gt; – Adding more machines (nodes/instances) to distribute the load.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Key Components of a Scalable Architecture&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Adopting a Microservices Architecture&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Instead of a monolithic approach, designing a &lt;strong&gt;microservices-based&lt;/strong&gt; system allows independent scaling of each service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Break the application into smaller, independent microservices.&lt;/li&gt;
&lt;li&gt;Centralized configuration: use &lt;strong&gt;Spring Cloud Config&lt;/strong&gt; for  configuration management. This helps update configurations dynamically without redeploying services.&lt;/li&gt;
&lt;li&gt;Deploy services independently (&lt;strong&gt;dockerize&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service discovery&lt;/strong&gt; for automatically locating and connecting microservices without hardcoding their network locations, enabling dynamic scaling and resilience in distributed systems (EKS or ECS)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Stateless and Horizontally Scalable Services&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In a stateless architecture, the service doesn't store session data between requests. Each request is treated as an independent transaction. Instead, any necessary state information is passed with each request, typically through parameters, headers, or tokens.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JWT&lt;/strong&gt;. It enables stateless authentication by embedding user info within the token itself.
How does JWT Work in a Stateless API?&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Client logs in → The authentication server issues a JWT upon successful login.&lt;/li&gt;
&lt;li&gt;Client includes JWT in requests → The token is passed in the Authorization header
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nl"&gt;Authorization:&lt;/span&gt; &lt;span class="nc"&gt;Bearer&lt;/span&gt; &lt;span class="n"&gt;xxxxx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Service verifies JWT → The backend validates the token using a secret key or public key.&lt;/li&gt;
&lt;li&gt;Request is processed → If valid, the request is processed without needing session lookups.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Database Scaling Strategies&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A single database can become a bottleneck as traffic grows. Consider the following approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database Partitioning (Sharding)&lt;/strong&gt; – Splitting large datasets into smaller, manageable parts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read Replicas&lt;/strong&gt; – Creating read-only database replicas to reduce the load on the primary database.The primary database only handles writes, while multiple read replicas handle read operations, improving performance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NoSQL Databases&lt;/strong&gt; – Using MongoDB, Cassandra, or DynamoDB for high scalability needs. However, it's important to note that NoSQL databases may favor availability and partition tolerance over strong consistency. The choice between NoSQL and relational databases should depend on your application's needs, whether you prioritize consistent data for critical transactions or need high availability and fault tolerance for large-scale, distributed applications.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Asynchronous Processing with Message Queues&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Asynchronous services are often preferred over synchronous ones in scalable architectures because of their efficiency, scalability, and ability to handle high traffic volumes without blocking processes. Spring Boot integrates well with popular message brokers like Kafka, RabbitMQ and Amazon SQS. Synchronous requests block the execution until a task is completed (higher latency), so it can be more appropriate when immediate responses are needed, or when the task being performed is lightweight and doesn’t involve waiting on external resources.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@Async&lt;/code&gt;, Spring Boot allows methods to be executed asynchronously using this annotation. Spring will run the method in a separate thread, allowing the main thread to continue without waiting for the method to complete.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Async&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;emailAddress&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Simulate sending an email...&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test@gmail.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// The main thread continues without waiting for the email to be sent&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;5. Load Balancing and API Gateway&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Distribute traffic efficiently across multiple instances to prevent overloading a single service and ensure high availability.&lt;/p&gt;

&lt;p&gt;API Gateway basically acts as a single entry point for all client requests. Lets see some of the main features.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routing &amp;amp; Load Balancing – Directs requests to the correct microservice based on URL paths.&lt;/li&gt;
&lt;li&gt;Authentication &amp;amp; Security – Implements OAuth, JWT, API keys, and rate limiting.&lt;/li&gt;
&lt;li&gt;Request Transformation – Modifies request headers, parameters, or payloads before forwarding.&lt;/li&gt;
&lt;li&gt;Caching &amp;amp; Compression – Improves performance by reducing redundant API calls.&lt;/li&gt;
&lt;li&gt;Circuit Breaker &amp;amp; Retry Mechanism – Prevents cascading failures and enhances fault tolerance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using both, Load Balancers and API Gateways ensures a resilient, scalable, and secure architecture&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Clients --&amp;gt;  API Gateway --&amp;gt; Load Balancer(through EKS) --&amp;gt; service A/service B....&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6. Caching for Performance Optimization&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Reduce database queries by caching frequently accessed data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redis, Amazon ElastiCache, Spring cache Abstraction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spring Cache Abstraction allows you to define caching behavior declaratively using annotations. This removes the need to write low-level caching logic manually. Most commonly:&lt;br&gt;
&lt;code&gt;@Cacheable&lt;/code&gt;: Caches the result of a method based on the method parameters. If the same method is called again with the same parameters, the cached result is returned instead of executing the method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Cacheable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"users"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 'users' is the cache name and the method params the key&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;getUserById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@CachePut&lt;/code&gt;: Updates the cache with the result of a method, but &lt;strong&gt;always executes&lt;/strong&gt; the method, unlike &lt;code&gt;@Cacheable&lt;/code&gt;, which may skip execution if the result is cached.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CachePut&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"users"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#user.id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@CacheEvict&lt;/code&gt;: Removes entries from the cache. It can be used to clear the cache based on conditions or manually evict data when it’s no longer needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CacheEvict&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"users"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deleteById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The previous points are some of the key considerations when designing scalable architectures. However, other important factors, such as logging, security, monitoring, error handling, retry mechanisms, etc etc.., should also be considered. Incorporating these aspects ensures that your application remains robust, secure, and easy to maintain as it grows and evolves.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>microservices</category>
      <category>java</category>
      <category>springboot</category>
    </item>
    <item>
      <title>Hexagonal Architecture in Spring Boot: A Practical Guide</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Wed, 12 Feb 2025 12:33:36 +0000</pubDate>
      <link>https://dev.to/jhonifaber/hexagonal-architecture-or-port-adapters-23ed</link>
      <guid>https://dev.to/jhonifaber/hexagonal-architecture-or-port-adapters-23ed</guid>
      <description>&lt;p&gt;Hexagonal Architecture, also known as Ports and Adapters, was introduced by Alistair Cockburn in 2005. Cockburn developed this concept to solve the problem of tight coupling between application logic and external dependencies (like databases, UI frameworks, and APIs). His main goal was to make systems more maintainable, testable, and adaptable by clearly separating core business logic from infrastructure concerns.&lt;br&gt;
Hexagonal Architecture shares similarities with other architectural patterns designed to promote separation of concerns and modularity.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Layered Architecture (N-Tier Architecture)&lt;/li&gt;
&lt;li&gt;Clean Architecture (by Robert C. Martin - Uncle Bob)&lt;/li&gt;
&lt;li&gt;Onion Architecture (by Jeffrey Palermo)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why is it Called Hexagonal Architecture?&lt;/strong&gt;&lt;br&gt;
The term Hexagonal Architecture comes from the hexagon shape used to visually represent the core system and its interactions with the external world.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why a Hexagon?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The hexagon shape is a metaphor to visually represent the system’s core and its interactions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unlike a rectangle or circle, a hexagon does not imply a hierarchical structure (like traditional N-tier architecture).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It has multiple connection points (ports) where you can easily plug in different adapters, like a UI, database, or external APIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The number six isn't important, it simply provides enough sides for a clean and organized representation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6nw0whalwfoa7ha0l5ak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6nw0whalwfoa7ha0l5ak.png" alt=" " width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ports: The Entry Points to Your Business Logic&lt;/strong&gt;&lt;br&gt;
In Hexagonal Architecture, ports represent interfaces that define the use cases or functionalities of the system. They specify what the application can do (e.g., add a product to the cart, remove a product, calculate the total), but not how it's done. Ports are the entry points to your core business logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;CartService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;removeProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;calculateTotal&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="nf"&gt;getCart&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;CartService&lt;/code&gt; is a primary port that defines the use cases for managing a shopping cart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adapters: Bridging Your Core Logic and the Outside World&lt;/strong&gt;&lt;br&gt;
Adapters are the implementations that interact with external systems and convert data between the outside world and the core business logic. There are two types of adapters in Hexagonal Architecture:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Primary Adapters:&lt;/strong&gt; These handle input from external sources, such as user requests, UI, or API calls. They interact with the primary ports (use cases) of the system. For example, a REST controller that receives HTTP requests and delegates the actions to a service (like &lt;code&gt;CartServiceImpl&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Example of a primary adapter (controller)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/cart"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CartController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;CartService&lt;/span&gt; &lt;span class="n"&gt;cartService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CartController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CartService&lt;/span&gt; &lt;span class="n"&gt;cartService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cartService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cartService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/add"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cartService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;CartController&lt;/code&gt; acts as a primary adapter because it handles HTTP requests (external input) and delegates them to the CartService (the primary port).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secondary Adapters:&lt;/strong&gt; These handle output to external systems, such as databases, message queues, or APIs. They implement the secondary ports, which are interfaces for data persistence or external integrations.&lt;/p&gt;

&lt;p&gt;Example of a secondary adapter (repository)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InMemoryCartRepository&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CartRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Primary Adapters&lt;/strong&gt; ➡ Think of them as input handlers (Controllers, CLI, API Gateways) that take external requests and pass them into the system.&lt;br&gt;
&lt;strong&gt;Secondary Adapters&lt;/strong&gt; ➡ Think of them as output handlers (Repositories, API clients, message brokers) that take results from the system and pass them to the outside world.&lt;/p&gt;

&lt;p&gt;An Example Package Structure in Java&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;CartRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;CartException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;CartService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;infrastructure&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;adapters&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;primary&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;CartController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;ControllerExceptionHandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;ErrorResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;CartRequestDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;CartResponseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;CartMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;secondary&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="c1"&gt;// Adapters that **provide** infrastructure (e.g., persistence, external APIs)&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;InMemoryCartRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;CartServiceConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="nc"&gt;CartApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How Do These Layers Interact?&lt;/strong&gt;&lt;br&gt;
When we need to interact with an infrastructure service from an application service, we follow the Dependency Inversion Principle. This principle suggests that rather than directly depending on concrete implementations, we inject the necessary dependencies through the constructor of the class. This approach promotes loose coupling and makes the system more flexible and easier to test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ports vs. Adapters: Understanding the Difference&lt;/strong&gt;&lt;br&gt;
Ports are interfaces that define what the system should do. They represent the use cases of the application (e.g., &lt;code&gt;CartService&lt;/code&gt;).&lt;br&gt;
Adapters are the implementations of those ports, responsible for managing the interaction with the outside world (like HTTP requests in the case of primary adapters, or database interactions in the case of secondary adapters).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the Implementation of a Primary Port Need to Be a Primary Adapter?&lt;/strong&gt;&lt;br&gt;
No. The implementation of a primary port (such as &lt;code&gt;CartServiceImpl&lt;/code&gt;) does not have to be a primary adapter. While primary ports define the use cases, their implementation is simply the business logic that satisfies those use cases. The primary adapter (like a controller) is the one that handles the external interaction (e.g., receiving requests, calling the service methods).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CartService&lt;/code&gt; is a primary port (interface).&lt;br&gt;
&lt;code&gt;CartServiceImpl&lt;/code&gt; is the implementation of the primary port, but it is not an adapter.&lt;br&gt;
&lt;code&gt;CartController&lt;/code&gt; is a primary adapter, as it handles HTTP requests and delegates to the CartService (the primary port).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
In Hexagonal Architecture, ports define what the system does (use cases), while adapters define how the system interacts with the outside world. The implementation of a port does not have to be an adapter itself; rather, it's the business logic that fulfills the requirements set by the port. Adapters, on the other hand, are responsible for connecting the external world to the core logic via the ports.&lt;/p&gt;

&lt;p&gt;This separation makes the system easier to maintain, test, and adapt to different external technologies.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>java</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Building, testing and publishing your Java project with Github actions.</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Sat, 31 Oct 2020 12:11:41 +0000</pubDate>
      <link>https://dev.to/jhonifaber/building-testing-and-publishing-your-java-project-with-github-actions-3j17</link>
      <guid>https://dev.to/jhonifaber/building-testing-and-publishing-your-java-project-with-github-actions-3j17</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I'm going to create a continuous integration (CI) workflow to build, test and publish the project in Github Packages.&lt;/p&gt;

&lt;p&gt;The project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Spring boot with maven&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Postgres database with a table &lt;em&gt;users&lt;/em&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3c9qgfpfxbshwka9x3zm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3c9qgfpfxbshwka9x3zm.png" alt="Alt Text" width="796" height="502"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One endpoint &lt;em&gt;/users&lt;/em&gt; that returns a list of users. In the example, I just have the user &lt;em&gt;jonathan&lt;/em&gt; with ID &lt;em&gt;1&lt;/em&gt;. My integration test will check /users returns a list of size 1.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webEnvironment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WebEnvironment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANDOM_PORT&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@TestInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TestInstance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Lifecycle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PER_CLASS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserEndpointIT&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;TestRestTemplate&lt;/span&gt; &lt;span class="n"&gt;restTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;DatabaseService&lt;/span&gt; &lt;span class="n"&gt;databaseService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@LocalServerPort&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@BeforeAll&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initDatabase&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;databaseService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;user_endpoint_should_return_all_users&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;HttpHeaders&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;HttpEntity&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;restTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;createUrlWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ParameterizedTypeReference&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;EXPECTED_USERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;EXPECTED_USERS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBody&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;createUrlWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Flyway as a database migration tool. (checkout my &lt;a href="https://dev.to/jhonifaber/flyway-with-spring-boot-database-migration-tool-3k0h"&gt;post&lt;/a&gt; about flyway if you don't know about it)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The following Maven plugin (docker-maven-plugin) in my pom.xml to run a postgres docker container for my integration tests.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;...
&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.fabric8&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;docker-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${docker-maven-plugin.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;images&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;image&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;${it.postgresql.image}&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;run&amp;gt;&lt;/span&gt;
               &lt;span class="nt"&gt;&amp;lt;ports&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;port&amp;gt;&lt;/span&gt;${it.postgresql.port}:5432&lt;span class="nt"&gt;&amp;lt;/port&amp;gt;&lt;/span&gt;
               &lt;span class="nt"&gt;&amp;lt;/ports&amp;gt;&lt;/span&gt;
               &lt;span class="nt"&gt;&amp;lt;env&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;POSTGRES_USER&amp;gt;&lt;/span&gt;${it.postgresql.username}&lt;span class="nt"&gt;&amp;lt;/POSTGRES_USER&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;POSTGRES_PASSWORD&amp;gt;&lt;/span&gt;${it.postgresql.password}&lt;span class="nt"&gt;&amp;lt;/POSTGRES_PASSWORD&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;POSTGRES_DB&amp;gt;&lt;/span&gt;${it.postgresql.db}&lt;span class="nt"&gt;&amp;lt;/POSTGRES_DB&amp;gt;&lt;/span&gt;
               &lt;span class="nt"&gt;&amp;lt;/env&amp;gt;&lt;/span&gt;
               &lt;span class="nt"&gt;&amp;lt;wait&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;log&amp;gt;&lt;/span&gt;database system is ready to accept connections&lt;span class="nt"&gt;&amp;lt;/log&amp;gt;&lt;/span&gt;
               &lt;span class="nt"&gt;&amp;lt;/wait&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/run&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;/image&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/images&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;start&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;pre-integration-test&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;start&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;stop&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;post-integration-test&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;stop&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Github actions allow us Continuous Integration (CI) and Continuous Deployment (CD) from our Github repositories.&lt;br&gt;
How does it work? An event triggers a &lt;strong&gt;workflow&lt;/strong&gt;, for example a push to master branch or a pull request, and that workflow could have different &lt;strong&gt;jobs&lt;/strong&gt;. We can have a job to run our tests and another job to deploy the app. Each job uses &lt;strong&gt;steps&lt;/strong&gt; that has different tasks or better known as &lt;strong&gt;actions&lt;/strong&gt;. We can create our own actions or use the ones created by the community. We are also allowed to name each action and give a brief description about what it does by using &lt;strong&gt;name&lt;/strong&gt; key. It's important to note that by default, jobs will run in parallel unless we configure them to run sequentially (maybe any job depends on another). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7qyxx3kgw86uum9o230v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7qyxx3kgw86uum9o230v.png" alt="Alt Text" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating the workflow
&lt;/h2&gt;

&lt;p&gt;First of all, we need to create the workflow file in the .github/workflows directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fav1w84bee42cv7varcp5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fav1w84bee42cv7varcp5.png" alt="Alt Text" width="402" height="394"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my first workflow for a java project&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;master&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;
          &lt;span class="na"&gt;settings-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.m2/"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.m2/repository&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-${{ hashFiles('**/pom.xml') }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mvn $MAVEN_CLI_OPTS clean deploy&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;MAVEN_CLI_OPTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-s&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;.m2/settings.xml&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--batch-mode"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Copying target jar&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;mkdir myTarget&lt;/span&gt;
          &lt;span class="s"&gt;cp target/*.jar myTarget&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Uploading jar&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myPackage&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myTarget&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We begin by adding a name for our workflow and setting the event that will trigger it. In this case, the event is a &lt;em&gt;push&lt;/em&gt; to my master branch. Now, we need to set the jobs for the workflow. &lt;strong&gt;The &lt;em&gt;runs-on&lt;/em&gt; configures the job to run on a virtual machine hosted by Github, to be more precise an Ubuntu Linux runner&lt;/strong&gt; (read more &lt;a href="https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on" rel="noopener noreferrer"&gt;here&lt;/a&gt;). In the above example, I just have one job called &lt;em&gt;publish&lt;/em&gt; that performs the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The checkout action downloads a copy of our repository on the runner.&lt;/li&gt;
&lt;li&gt;The setup action configures the Java environment. The &lt;em&gt;with&lt;/em&gt; key allow us to specify the variables that will be available to the action. In the example, we set up the JDK version and with &lt;em&gt;settings-path&lt;/em&gt;, we specify the location for the settings.xml file.&lt;/li&gt;
&lt;li&gt;Considering jobs on hosted GitHub runners start in a clean virtual environment, we want to save time so that dependencies don't need to be downloaded each time a job is ran. In the example, I'm caching all the dependency jars. It's important to set a &lt;strong&gt;key&lt;/strong&gt; so that the action will try to restore the cache files based on that key. To create the key, I'm using the &lt;strong&gt;runner.os&lt;/strong&gt; that gives me where the job is currently running, and the &lt;strong&gt;hashfile&lt;/strong&gt; function that returns a hash for the given files (read more &lt;a href="https://github.com/actions/cache" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Im going to publish my project to Github Packages, that's why you see I run &lt;strong&gt;mvn clean deploy&lt;/strong&gt;. At this point, is important to know that the action &lt;strong&gt;actions/setup-java@v1&lt;/strong&gt; used previously, is going to set up &lt;strong&gt;automatically a Maven settings.xml file&lt;/strong&gt;  generating the authentication for the server like the shown below. To use the GITHUB_TOKEN secret, we must reference it in our workflow file, as you see in my workflow file, I'm passing the token as an input to the action &lt;em&gt;Publish package&lt;/em&gt;. If we don't do this, we can see an error in the logs (401 Unauthorized).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;servers&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;server&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;github&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;username&amp;gt;&lt;/span&gt;${{ secrets.GITHUB_ACTOR }}&lt;span class="nt"&gt;&amp;lt;/username&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;password&amp;gt;&lt;/span&gt;${{ secrets.GITHUB_TOKEN }}&lt;span class="nt"&gt;&amp;lt;/password&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/server&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/servers&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server created will have an id of github, GITHUB_ACTOR environment variable is our username and GITHUB_TOKEN environment variable is our password (these env. variables exist in our github repository by default). In my pom.xml, I I just need to add the repository configuration where the package will be uploaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;...
&lt;span class="nt"&gt;&amp;lt;distributionManagement&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;repository&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;github&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;github packages&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://maven.pkg.github.com//[your_github_username]/[your_repository_name]&lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/repository&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/distributionManagement&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we make a push, on the right side of our repository, we can find our package.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5y1ormdzx5urk5fbfunq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5y1ormdzx5urk5fbfunq.png" alt="Alt Text" width="740" height="1162"&gt;&lt;/a&gt;&lt;br&gt;
If we click on it, we can see the dependency.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu335f2t4v8ekrzoeh9qs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu335f2t4v8ekrzoeh9qs.png" alt="Alt Text" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One of the last steps is to upload the artifact. Remember that an artifact is file or a collection of files produced during a workflow run. First, what I do is to create &lt;em&gt;myTarget&lt;/em&gt; folder and copy the jar. The last actions used is &lt;strong&gt;upload-artifact@v2&lt;/strong&gt; that receives two inputs, the name of the artifact and the files that will be uploaded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdphp1hdy1or3mtu7ndj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdphp1hdy1or3mtu7ndj3.png" alt="Alt Text" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we download &lt;em&gt;myPackage&lt;/em&gt; and unzip it, we can see the jar.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvksnb7q42jxqgrt27cnl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvksnb7q42jxqgrt27cnl.png" alt="Alt Text" width="442" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we make a push to the repository, in the &lt;em&gt;Actions&lt;/em&gt; tab we can see the workflow running. If everything is fine, we'll see a green tick.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fml5kkqdw8yyi1xukouja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fml5kkqdw8yyi1xukouja.png" alt="Alt Text" width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we click on the workflow, we can see a detailed list of the jobs and their steps. In my example, I just have the &lt;em&gt;publish&lt;/em&gt; job.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6sse9vl2gte1hem9ie1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6sse9vl2gte1hem9ie1c.png" alt="Alt Text" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we check the log of the &lt;em&gt;publish package action&lt;/em&gt;, we can see how my database container is running, the spring context is up, flyway migrations are okay, and the tests passed successfully&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2zj7y7zhs6pmrj0xmd23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2zj7y7zhs6pmrj0xmd23.png" alt="Alt Text" width="800" height="216"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp4u5hbkcm7j48m4wps5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp4u5hbkcm7j48m4wps5l.png" alt="Alt Text" width="800" height="331"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2o214q46qltpx61pst70.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2o214q46qltpx61pst70.png" alt="Alt Text" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Github packages
&lt;/h2&gt;

&lt;p&gt;GitHub Packages is a hosting service that allows us to host our packages privately or publicly and use them as dependencies in our projects. As we saw in the previous section, we have uploaded the project as a dependency to Github Packages. But how can I install a maven dependency stored in github packages registry? apart from adding the dependency in the pom.xml, we must follow the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In our pom.xml, we need to point to the repository where the dependency we want to install is located.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;...
&lt;span class="nt"&gt;&amp;lt;repositories&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;repository&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;github&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://maven.pkg.github.com/[github_username]/[repository_name]&lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/repository&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/repositories&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The github package registry is available through the GitHub api and needs authorization, so we need to add our github credentials in the settings.xml. In my case I have added them to my global settings (~ / .m2 / settings.xml)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;settings&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/SETTINGS/1.0.0"&lt;/span&gt;
          &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;
          &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/SETTINGS/1.0.0
                          https://maven.apache.org/xsd/settings-1.0.0.xsd"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;servers&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;server&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;github&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;username&amp;gt;&lt;/span&gt;[your_github_username]&lt;span class="nt"&gt;&amp;lt;/username&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;password&amp;gt;&lt;/span&gt;[your_github_token]&lt;span class="nt"&gt;&amp;lt;/password&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/server&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/servers&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/settings&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create a token, we should go to our github &lt;em&gt;Settings &amp;gt; Developer Settings &amp;gt; Personal access tokens&lt;/em&gt; and enable the &lt;em&gt;read: packages&lt;/em&gt; permission.&lt;/p&gt;

&lt;p&gt;Once these steps have been followed and if everything has gone well, the dependency will be installed correctly 😃.&lt;/p&gt;

</description>
      <category>java</category>
      <category>testing</category>
      <category>github</category>
      <category>devops</category>
    </item>
    <item>
      <title>Testcontainers - dockerize your integration tests in java</title>
      <dc:creator>Jonathan</dc:creator>
      <pubDate>Tue, 07 Jul 2020 17:54:04 +0000</pubDate>
      <link>https://dev.to/jhonifaber/testcontainers-dockerize-your-integration-tests-in-java-42o3</link>
      <guid>https://dev.to/jhonifaber/testcontainers-dockerize-your-integration-tests-in-java-42o3</guid>
      <description>&lt;p&gt;Using an in-memory database like H2 in Java have some downsides because the tests could depend on features that in-memory databases can't reproduce and some tests that have passed locally may fail in production. This affects our tests reliability because we won't cover 100% the same scenarios as in our real environment. &lt;br&gt;
&lt;a href="https://www.testcontainers.org/" rel="noopener noreferrer"&gt;Testcontainers&lt;/a&gt; comes to the rescue so that we can &lt;strong&gt;dockerize our tests&lt;/strong&gt;. It's a Java library that allows to create any docker instances and manipulate them.&lt;/p&gt;

&lt;p&gt;I'm going to be using JUnit5, but if you use JUnit4 is perfectly fine too. Let's start by adding the dependency in the pom.xml. We can add the generic dependency or a more specific one (to have a preconfigured container). When using databases, remember to add their drivers (Testcontainers will not add it for you). Take a look at the list of preconfigured containers in &lt;a href="https://mvnrepository.com/search?q=org.testcontainers&amp;amp;p=1" rel="noopener noreferrer"&gt;maven repository&lt;/a&gt;. You can find for mongoDB, postgresql, cassandra, elasticsearch, rabbitmq, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Generic dependency&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;testcontainers&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;testcontainers&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mf"&gt;1.14&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Specific dependency for mysql&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;testcontainers&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mf"&gt;1.14&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;//driver&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;connector&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How does Testcontainers work?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It starts a container with the specific docker image (in my example, I'm using a mysql image).&lt;/li&gt;
&lt;li&gt;Another container called Ryuk will also be started and it's main task is to manage the startup and stop of the container.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyk76de0303o71ipbwifg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyk76de0303o71ipbwifg.png" alt="Alt Text" width="800" height="61"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the good things about this library is its integration with JUnit. To be able to use the next annotations, we need to add this &lt;a href="https://mvnrepository.com/artifact/org.testcontainers/junit-jupiter" rel="noopener noreferrer"&gt;dependency&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;testcontainers&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;junit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;jupiter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mf"&gt;1.14&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;@Testcontainers:&lt;/strong&gt; is a JUnit Jupiter extension to activate automatic startup and stop of containers used in a test case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;@Container:&lt;/strong&gt; is used in conjunction with the @Testcontainers annotation to mark containers that should be managed by the Testcontainers extension.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating a generic container
&lt;/h2&gt;

&lt;p&gt;We can create a generic container from any public docker image or a docker-compose. Since this is a generic approach, we need to configure more things than if we already had a preconfigured container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt; &lt;span class="nd"&gt;@Container&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;GenericContainer&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GenericContainer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"image_name"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withExposedPorts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_number&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;withExposedPorts(port)&lt;/em&gt;, we expose the default internal port (in mysql for example is 3306) from the container that will be mapped to a random port. To retrieve that random port at runtime, we can use the getMappedPort(original_port) or just getFirstMappedPort() method. If we don't expose the port, we'll get en error saying 'Container doesn't expose any ports'. We can also add environment variables to the container with .withEnv(), execute command inside a container (like docker exec), manage our own waiting and startup strategies, etc. Have a look at the &lt;a href="https://www.testcontainers.org/features/creating_container/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for deeper information. &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a mysql container
&lt;/h2&gt;

&lt;p&gt;As I said before, we have many preconfigured containers with some out-of-the-box configuration that makes our lives easier. I'm going to use a mysql container for my tests.&lt;br&gt;
We can decide whether we want to start and stop the container once per tests class or once per tests method (we'll see later how to create a singleton container)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Once per test class&lt;/span&gt;
 &lt;span class="nd"&gt;@Container&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;MySQLContainer&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MySQLContainer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mysql:latest"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Once per test method&lt;/span&gt;
 &lt;span class="nd"&gt;@Container&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;MySQLContainer&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MySQLContainer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mysql:latest"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: If you are using JUnit4, you can use @Rule and @ClassRule annotations.&lt;/p&gt;

&lt;p&gt;The following example starts a mysql container and then runs my HelloEndpointIT class. I'm using &lt;em&gt;static final&lt;/em&gt; in the container instance, so the container will be shared between all tests methods. The mysql container give me some methods to configure a specific database name, username and password. If we don't specify this, we will use default values (database name: test, password: test, username: test)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webEnvironment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WebEnvironment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANDOM_PORT&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@ActiveProfiles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@TestInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TestInstance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Lifecycle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PER_CLASS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Testcontainers&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloEndpointIT&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;TestRestTemplate&lt;/span&gt; &lt;span class="n"&gt;restTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@LocalServerPort&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Container&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;MySQLContainer&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MySQLContainer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mysql:latest"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withDatabaseName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"demo_db_name"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withUsername&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"any_username"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"any_passw"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@BeforeAll&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initDatabaseProperties&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.url"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getJdbcUrl&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.username"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.password"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;hello_endpoint_should_return_hello_world&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;HttpHeaders&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;HttpEntity&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;restTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;createUrlWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatusCode&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;equalTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;OK&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBody&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;equalTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello world"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;createUrlWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the container is ready, I need to set my datasource configuration. We can get the url with its mapped port using the &lt;em&gt;getJdbcUrl()&lt;/em&gt; method, as well as the &lt;em&gt;getUsername()&lt;/em&gt; and &lt;em&gt;getPassword()&lt;/em&gt;. I'm setting this configuration before running my tests using the @BeforeAll annotation provided by JUnit5. In JUnit4 is @BeforeClass.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwk41mfi66v40934a8dkh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwk41mfi66v40934a8dkh.png" alt="Alt Text" width="800" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a singleton container
&lt;/h2&gt;

&lt;p&gt;So far we have seen how to run our container once per test class or method, but I would like to just create an instance for all my tests classes. So, let's see how to run a singleton container before running all our integration tests.&lt;/p&gt;

&lt;p&gt;We are going to use &lt;em&gt;static Initializers&lt;/em&gt; to initialize the container only once. We need to do it in an abstract class and extend all our IT classes. We also need to manually start the container in our initializer block and when the tests finish, the Ryuk container will take care of stopping it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webEnvironment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WebEnvironment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANDOM_PORT&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@ActiveProfiles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DemoEndpointIT&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;TestRestTemplate&lt;/span&gt; &lt;span class="n"&gt;restTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@LocalServerPort&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;MySQLContainer&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;mysql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MySQLContainer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mysql:latest"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.url"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getJdbcUrl&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.username"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.password"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;createUrlWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;TestRestTemplate&lt;/span&gt; &lt;span class="nf"&gt;getRestTemplate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;restTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you saw in the examples, having a mysql container ready for my integrations tests were super easy and almost no configuration was necessary.&lt;/p&gt;

</description>
      <category>java</category>
      <category>testing</category>
      <category>docker</category>
      <category>springboot</category>
    </item>
  </channel>
</rss>
