<?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: Manoj Sharma</title>
    <description>The latest articles on DEV Community by Manoj Sharma (@manojshr).</description>
    <link>https://dev.to/manojshr</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%2F481769%2F4709f92e-b3b2-4794-a39f-b64fc27bdf8c.jpeg</url>
      <title>DEV Community: Manoj Sharma</title>
      <link>https://dev.to/manojshr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manojshr"/>
    <language>en</language>
    <item>
      <title>The Engineering Guardrails We Need After AI Started Writing the Code</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Fri, 03 Apr 2026 18:34:52 +0000</pubDate>
      <link>https://dev.to/manojshr/the-engineering-guardrails-we-need-after-ai-started-writing-the-code-5dgm</link>
      <guid>https://dev.to/manojshr/the-engineering-guardrails-we-need-after-ai-started-writing-the-code-5dgm</guid>
      <description>&lt;p&gt;Today, AI removes the typing cost. You ship faster, tests are green, code reviews pass. But it also removes the &lt;strong&gt;natural pauses&lt;/strong&gt; where as an engineer you normally think through the hard parts — and this is where you should &lt;em&gt;not&lt;/em&gt; be on autopilot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retries&lt;/li&gt;
&lt;li&gt;idempotency 👑&lt;/li&gt;
&lt;li&gt;network timeouts&lt;/li&gt;
&lt;li&gt;concurrency&lt;/li&gt;
&lt;li&gt;rich suite of tests&lt;/li&gt;
&lt;li&gt;observability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is: &lt;code&gt;Reasoning Debt&lt;/code&gt; — and it keeps increasing.&lt;/p&gt;

&lt;p&gt;The code works. But nobody can explain &lt;em&gt;why&lt;/em&gt; it was written that way, and more importantly, nobody knows what it does when things go wrong.&lt;/p&gt;

&lt;p&gt;Quietly similar to technical debt, but different:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical debt&lt;/strong&gt; 👉 messy implementation&lt;br&gt;
&lt;strong&gt;Reasoning debt&lt;/strong&gt; 👉 unclear intent under failure&lt;/p&gt;

&lt;p&gt;In production you need reasoning — and one day it breaks, and you find yourself in an endless debugging session with 2 or 3 more engineers trying to understand &lt;strong&gt;why you wrote what you wrote.&lt;/strong&gt; This can silently kill your code reading and reasoning skills over time.&lt;/p&gt;

&lt;p&gt;But we can set up a good set of engineering guardrails. And honestly, AI is getting more capable every day — we may see it handling these concerns by default in the near future. Until then, let's talk about a few things worth focusing.&lt;/p&gt;


&lt;h2&gt;
  
  
  Guardrail #1 — Fully Covered Tests Become Code Reasoning Documentation
&lt;/h2&gt;

&lt;p&gt;AI can generate logic quickly, but intent is rarely obvious without tests. Consider this user eligibility 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="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;eligible&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;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;getBalance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&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;isPremium&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;Looks reasonable. But questions appear immediately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does &lt;code&gt;isPremium()&lt;/code&gt; bypass the balance check entirely?&lt;/li&gt;
&lt;li&gt;Does an inactive premium user get in?&lt;/li&gt;
&lt;li&gt;Was operator precedence here &lt;em&gt;intentional&lt;/em&gt; or accidental?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without tests this becomes reasoning hell later. The fix isn't just adding parentheses — this is a business rule encoded as an expression, and the expression is ambiguous. &lt;strong&gt;Make sure you instruct AI to generate intent-covering tests, not just happy path ones.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Added tests turn this into a code manual:&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;@Test&lt;/span&gt;
&lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Premium users are eligible regardless of balance"&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;premiumUserEligibleRegardlessOfBalance&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="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Inactive users are never eligible, even if premium"&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;inactiveUserNotEligible&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="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Active non-premium users need sufficient balance"&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;activeUserWithBalanceEligible&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;Now the logic &lt;em&gt;has&lt;/em&gt; to be unambiguous, because the tests force you to state every case explicitly. And when someone asks &lt;em&gt;"what was this supposed to do?"&lt;/em&gt; — the tests answer that faster than any comment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Guardrail #2 — AI Writes Happy Paths. Systems may fail Unexpectedly.
&lt;/h2&gt;

&lt;p&gt;AI naturally writes linear success flows:&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processOrder&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;orderId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;capture&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reserve&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;shipping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&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;Completely correct... until retries happen. Higher environments sometimes introduce retries that catch you off guard — and if not handled, you may end up with significant drift that's not easy to rollback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQS retries&lt;/li&gt;
&lt;li&gt;Kafka re-delivery&lt;/li&gt;
&lt;li&gt;HTTP timeouts&lt;/li&gt;
&lt;li&gt;Client retries after 502 or 409&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now imagine a failure mid-flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Attempt 1:
  payment.capture()   → SUCCESS ✅
  inventory.reserve() → SUCCESS ✅
  shipping.create()   → TIMEOUT ❌

Queue retries the message.

Attempt 2:
  payment.capture()   → CAPTURED AGAIN 💸
  inventory.reserve() → RESERVED AGAIN 📦
  shipping.create()   → SUCCESS ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;double charge incidents&lt;/li&gt;
&lt;li&gt;inventory drift&lt;/li&gt;
&lt;li&gt;duplicate shipments&lt;/li&gt;
&lt;li&gt;reconciliation nightmares&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The missing idea is usually &lt;code&gt;idempotency&lt;/code&gt; — not logic. &lt;strong&gt;You must protect the state, and this is something worth explicitly instructing AI to reason about.&lt;/strong&gt; A simple attempt:&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processOrder&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;orderId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderStateRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isProcessed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Order {} already processed, skipping"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAlreadyCaptured&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;capture&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isReserved&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reserve&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;shipping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exists&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;shipping&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;orderStateRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;markProcessed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&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;Honestly, this is subjective — some engineers naturally think about it and instruct upfront, others don't. But it should always be on your brain map.&lt;/p&gt;




&lt;h2&gt;
  
  
  Guardrail #3 — Instruct AI to Test System Behaviour, Not Just Code Interaction
&lt;/h2&gt;

&lt;p&gt;Without explicit instruction, AI tends to validate code interaction using mocks instead of actual system behaviour.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 1 — Mocking Infrastructure Clients (e.g. OpenSearch)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldIndexOrder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;OpenSearchClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OpenSearchClient&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="nc"&gt;SearchService&lt;/span&gt; &lt;span class="n"&gt;service&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;SearchService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order-123"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&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;Test proves:&lt;/strong&gt; Client method was called.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test does &lt;em&gt;not&lt;/em&gt; prove:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;index exists&lt;/li&gt;
&lt;li&gt;mapping is correct&lt;/li&gt;
&lt;li&gt;serialization works&lt;/li&gt;
&lt;li&gt;AWS config works&lt;/li&gt;
&lt;li&gt;search actually works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is testing Java interactions, not search behaviour.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 2 — Mocking DB Interaction (When You Have Liquibase)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderRepositoryTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mock&lt;/span&gt;
    &lt;span class="nc"&gt;OrderRepository&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldSaveOrder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;repo&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"123"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&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="s"&gt;"123"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;isPresent&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;Looks fine. Hidden problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Liquibase never executed&lt;/li&gt;
&lt;li&gt;schema never validated&lt;/li&gt;
&lt;li&gt;constraints never validated&lt;/li&gt;
&lt;li&gt;JSON columns may fail in production&lt;/li&gt;
&lt;li&gt;migrations may fail at startup&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Instruct AI to Write Real Integration Tests
&lt;/h3&gt;

&lt;p&gt;Point AI toward Testcontainers — it knows about it, it just won't reach for it unless you ask:&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;@Testcontainers&lt;/span&gt;
&lt;span class="nd"&gt;@SpringBootTest&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderSystemIT&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// spring.liquibase.change-log: classpath:db/changelog.xml&lt;/span&gt;
    &lt;span class="nd"&gt;@Container&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;PostgreSQLContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;postgres&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;PostgreSQLContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"postgres:15"&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;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;LocalStackContainer&lt;/span&gt; &lt;span class="n"&gt;localstack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LocalStackContainer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DockerImageName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"localstack/localstack"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withEnv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SERVICES"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"opensearch"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="n"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldCreateOrderAndSearch&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order-123"&lt;/span&gt;&lt;span class="o"&gt;);&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;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order-123"&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;results&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;hasSize&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="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;Now you're testing &lt;em&gt;persist and search behaviour&lt;/em&gt; — not Java mocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Guardrail #4 — Instruct AI to Log With Context, Not Just Confirmation
&lt;/h2&gt;

&lt;p&gt;AI generated logging looks completely reasonable on the surface:&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processPayment&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;orderId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processing payment for order {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Payment processed for order {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderId&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 we Ship it to production, hit a failure, open our log aggregator. What we find:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Processing payment for order 123
Processing payment for order 234
Processing payment for order 345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No error. No context. No idea which order failed, what amount was involved, what the gateway returned, or whether a retry is safe.&lt;/p&gt;

&lt;h3&gt;
  
  
  Instruct AI to write structured logs with failure context from the start:
&lt;/h3&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processPayment&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;orderId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Payment processing started"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"orderId"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"amount"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Payment captured"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"orderId"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"transactionId"&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="na"&gt;getTransactionId&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt;
            &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"duration"&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="na"&gt;getDuration&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;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CustomException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Payment capture failed"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"orderId"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"errorCode"&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;.&lt;/span&gt;&lt;span class="na"&gt;getErrorCode&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt;
            &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"retryable"&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;.&lt;/span&gt;&lt;span class="na"&gt;isRetryable&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;e&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;With structured logs, aggregator can answer "how many non-retryable payment failures in the last hour, by error code?".&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;None of these are new concepts. Idempotency, intent-driven tests, integration testing, structured observability — senior engineers have known these for years.&lt;br&gt;
With AI, The speed is real. Just don't let it replace the thinking.&lt;br&gt;
Write the guardrails into your prompts, your PR reviews, your definition of done. AI will follow — it just won't lead.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>software</category>
    </item>
    <item>
      <title>Be a Responsible Code Reviewer</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Sat, 22 Nov 2025 05:49:28 +0000</pubDate>
      <link>https://dev.to/manojshr/be-a-responsible-code-reviewer-46ni</link>
      <guid>https://dev.to/manojshr/be-a-responsible-code-reviewer-46ni</guid>
      <description>&lt;p&gt;When you work with different teams long enough, you start noticing something meaningful:&lt;br&gt;
&lt;strong&gt;Good code reviews don’t just improve the code—they strengthen teams, culture, and the way we write applications.&lt;/strong&gt; Think about it...&lt;/p&gt;

&lt;p&gt;That's where we actually teach each other new tricks / ways, &lt;strong&gt;share our best practices&lt;/strong&gt;, and make sure we're all building something awesome, maintainable and reliable.&lt;/p&gt;

&lt;p&gt;Let’s take a clear look... what a helpful, responsible code review really looks like. I am going to dig into the everyday's habits we fall into — &lt;strong&gt;the good ones&lt;/strong&gt; and &lt;strong&gt;the ones that slow us down&lt;/strong&gt; — and let's figure out better ways to handle them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Strong Engineering Teams 💪 Treat Code Reviews Seriously?
&lt;/h2&gt;

&lt;p&gt;Code reviews aren’t only about &lt;strong&gt;catching typos&lt;/strong&gt;. They protect the applications’s correctness, design, and future maintainers.&lt;/p&gt;

&lt;p&gt;Let’s analyze few of the reasons...&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Catching Hidden Logic or Edge-Case Bugs
&lt;/h3&gt;

&lt;p&gt;Sometimes the code looks fine, until someone else reads it carefully.&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="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&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;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Looks fine, but...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A reviewer notices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Allows balance to go negative&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No validation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Silent failures&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A thoughtful improvement:&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="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid withdrawal amount"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalStateException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Insufficient funds"&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;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;amount&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;So this one small review prevented a production nightmare 😰&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Improving Design and Readability
&lt;/h3&gt;

&lt;p&gt;Developers often optimize for &lt;strong&gt;&lt;em&gt;“it just works”&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
Reviewers can help guide towards &lt;strong&gt;&lt;em&gt;"it works and it makes sense here, they help reshape it before it becomes a problem later."&lt;/em&gt;&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="n"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But inside this method, total chaos! 🤯&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 200 lines of logic...&lt;/span&gt;
    &lt;span class="c1"&gt;// validation, transformations, ext calls...&lt;/span&gt;
    &lt;span class="c1"&gt;// Hard to read, hard to test, and even harder to change later.&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;even if it Works today, but becomes a headache for anyone reading it tomorrow.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A reviewer suggests breaking responsibilities:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;validateOrder(order)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;applyDiscount(order)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;reserveStock(order)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;notifyUser(order)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Reviews improve the design instincts — something no tool can automate.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Spotting Performance &amp;amp; Concurrency Pitfalls
&lt;/h3&gt;

&lt;p&gt;Performance issues often hide in plain sight:&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;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;User&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="kd"&gt;synchronized&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="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// heavy operations&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reviewer says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You’re &lt;strong&gt;locking the entire map&lt;/strong&gt;. That means only one thread can use it at a time.&lt;br&gt;
Use a &lt;strong&gt;ConcurrentHashMap&lt;/strong&gt; so multiple threads can work without blocking each other unnecessarily.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Small insight, big impact...but stay polite 🙌&lt;/p&gt;

&lt;h2&gt;
  
  
  How CI Helps Developers Trust Their Code?
&lt;/h2&gt;

&lt;p&gt;Modern CI should take care of the repetitive checks, freeing reviewers to focus on real logic and blunders.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI Handles What Humans Need not to
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Basic static analysis&lt;/li&gt;
&lt;li&gt;Null Pointers&lt;/li&gt;
&lt;li&gt;High Logical Complexity&lt;/li&gt;
&lt;li&gt;Code coverage&lt;/li&gt;
&lt;li&gt;Security scans&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your CI is configured well, Reviewers need not to comment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Indentation wrong.”&lt;br&gt;
“Rename this variable.”&lt;br&gt;
“Remove unused imports.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most importantly it will take care of highlighting Vulnerabilities or Security concerns found in your latest changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Learning Culture Through Code Reviews
&lt;/h2&gt;

&lt;p&gt;A team that genuinely invests in code reviews gets better over time — because reviews are opportunity to learn new patterns, better designs, and even by reading other people's review comments educate everyone that this is how mistakes can be avoided... not just approvals to merge.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Tech Review Sessions With the Team
&lt;/h3&gt;

&lt;p&gt;A simple habit strong engineering teams use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick a PR that has some interesting design decisions&lt;/li&gt;
&lt;li&gt;Walk everyone through what was done and why?&lt;/li&gt;
&lt;li&gt;Talk about other possible approaches and their trade-offs&lt;/li&gt;
&lt;li&gt;Note down anything useful for future work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This changes code review process from a private chat to something the whole team can learn from.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Knowledge Sharing Example
&lt;/h3&gt;

&lt;p&gt;Suppose a developer introduces following piece of code&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
             &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;COMPLETED&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
             &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sorted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Comparator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comparing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Order:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getDate&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
             &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And reviewer suggests:&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByStatusOrderByDateAsc&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;COMPLETED&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple discussion here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;teaches why filtering and sorting at the source is more efficient&lt;/li&gt;
&lt;li&gt;helps teammates recognize performance issues hidden in “harmless” code
Reviews become mini lessons wrapped inside real code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Language Modernization Through Reviews
&lt;/h3&gt;

&lt;p&gt;Developer writes:&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;Optional&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="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&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;isPresent&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Address&lt;/span&gt; &lt;span class="n"&gt;address&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;get&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAddress&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&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;address&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCity&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"anywhere"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reviewer suggests:&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;findUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;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;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;User:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getAddress&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="nl"&gt;Address:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getCity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"anywhere"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No lecture — just a small improvement that exposes them to modern Java style.&lt;br&gt;
This is how teams grow naturally.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to Be a Responsible Code Reviewer ⭐️
&lt;/h2&gt;

&lt;p&gt;Short, powerful, and practical.&lt;br&gt;
No philosophy — just actionable mindset...&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Understand The Context Before The Code
&lt;/h3&gt;

&lt;p&gt;Read First:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PR description&lt;/li&gt;
&lt;li&gt;Linked JIRA ticket&lt;/li&gt;
&lt;li&gt;Commit message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can’t review well unless you understand why the change exists.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Ask Questions, Don’t Command
&lt;/h3&gt;

&lt;p&gt;Bad:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Use Streams here.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Good:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Any reason Streams weren’t used here? they might simplify this block.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Questions create collaboration; Commands create tension.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Praise Good Code When You See It
&lt;/h3&gt;

&lt;p&gt;We often only comment when something is wrong.&lt;br&gt;
But acknowledging good work helps morale and encourages a positive environment.&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="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&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;HttpClient&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;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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;Good comment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Nice use of try-with-resources — clean and safe.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4. When You Reject Something, Reject the Code — Not the Dev
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;synchronized&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="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;timeConsumingOperation&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;A harsh comment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This is bad, Why would anyone write this?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Responsible reviewer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This might block more threads than needed. Can we lock only the shared part?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5. Be Fast. Be Respectful. Be Honest.
&lt;/h3&gt;

&lt;p&gt;Common anti-patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reviews slipping because of competing priorities.&lt;/li&gt;
&lt;li&gt;Reviewer approves without reading.&lt;/li&gt;
&lt;li&gt;Comments that are too short to be actionable (&lt;strong&gt;“Fix this”, “Why?”&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Responsible reviewer mindset:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review within a reasonable timeframe.&lt;/li&gt;
&lt;li&gt;Give actionable comments.&lt;/li&gt;
&lt;li&gt;Being honest while staying respectful&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Review the Scope — Not the Galaxy
&lt;/h3&gt;

&lt;p&gt;If a PR is about &lt;strong&gt;“Add Get Users API”&lt;/strong&gt;, don’t comment on unrelated parts like variable names in other unrelated methods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Focus on:&lt;/strong&gt; &lt;em&gt;Functional correctness || Edge cases || Complexity&lt;/em&gt;&lt;br&gt;
Don’t expand scope unless it’s truly necessary.&lt;/p&gt;
&lt;h3&gt;
  
  
  7. Don’t Just Point Out Problems — Propose Alternatives
&lt;/h3&gt;

&lt;p&gt;A bad review makes the author feel stuck.&lt;br&gt;
A good review helps them move forward faster.&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="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Status&lt;/span&gt; &lt;span class="n"&gt;status&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;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACTIVE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PENDING&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;Reviewer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Hardcoded checks”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Responsible reviewer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These rules will grow. Let the enum own its behavior instead of scattering logic.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&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;enum&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;ACTIVE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;PENDING&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;SUSPENDED&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;valid&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;valid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valid&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;boolean&lt;/span&gt; &lt;span class="nf"&gt;isValid&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;valid&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;One identifies the issue, The other one provides the solution as well...and allows dev to express their thoughts at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;That'it...&lt;br&gt;
Repeating myself, Good code review process don’t just create better applications, They create better teams.&lt;br&gt;
I’d love to hear from you people - What parts of the code review process frustrated you, and what changes made things better for you and your team? Share your thoughts 💭.&lt;/p&gt;

</description>
      <category>code</category>
      <category>java</category>
      <category>software</category>
      <category>codereview</category>
    </item>
    <item>
      <title>Virtual Threads - Comparative Analysis</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Sun, 09 Nov 2025 16:10:24 +0000</pubDate>
      <link>https://dev.to/manojshr/virtual-threads-comparitive-analysis-46</link>
      <guid>https://dev.to/manojshr/virtual-threads-comparitive-analysis-46</guid>
      <description>&lt;p&gt;If you’ve worked with &lt;strong&gt;Java&lt;/strong&gt; ☕️ long enough, you probably remember when thread management felt less like coding and more like careful resource budgeting.&lt;/p&gt;

&lt;p&gt;We had to size our thread pools just &lt;strong&gt;"right"&lt;/strong&gt;, because&lt;br&gt;
&lt;strong&gt;Too small -&amp;gt;&lt;/strong&gt; and requests would &lt;strong&gt;just pile up&lt;/strong&gt;, and waiting forever.&lt;br&gt;
&lt;strong&gt;Too large -&amp;gt;&lt;/strong&gt; and memory vanished quickly. as each thread reserved a big chunk for itself. Even worse, your CPU would spend all its time just switching between threads instead of doing actually work.&lt;/p&gt;

&lt;p&gt;And when &lt;strong&gt;I/O came into play&lt;/strong&gt; — like, &lt;strong&gt;blocking on a database call or waiting for a network response&lt;/strong&gt; — we either had to accept wasted threads or jump into async APIs, callbacks, and &lt;code&gt;CompletableFuture&lt;/code&gt; chains.&lt;/p&gt;

&lt;p&gt;We all made it work, of course. But it was a constant headache. We spent more time fighting with the concurrency model than we did building the actual feature.&lt;/p&gt;


&lt;h2&gt;
  
  
  Arrival of Virtual Threads 🚀
&lt;/h2&gt;

&lt;p&gt;Virtual threads, became a &lt;strong&gt;stable feature in JDK 21&lt;/strong&gt;.&lt;br&gt;
They just quietly solved a problem we’d been carrying for years — how to make sequential blocking style code scale without rewriting everything.&lt;/p&gt;

&lt;p&gt;Virtual Threads are not &lt;strong&gt;new thing&lt;/strong&gt; anymore; But it’s still worth pausing to think about how they’ve changed the way we approach concurrency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal is simple&lt;/strong&gt;&lt;br&gt;
Enable scalable concurrency without giving up the familiar, blocking programming model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the best part is?&lt;/strong&gt;&lt;br&gt;
They are still &lt;code&gt;java.lang.Thread&lt;/code&gt; instances, but instead of being bound to OS threads, they are managed by the JVM.&lt;/p&gt;


&lt;h2&gt;
  
  
  How to Create?
&lt;/h2&gt;

&lt;p&gt;Let’s see how virtual threads are created in Java, and how that differs from creating traditional platform threads&lt;/p&gt;
&lt;h3&gt;
  
  
  Platform Threads
&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;// Platform thread&lt;/span&gt;
&lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t&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;Thread&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="n"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="n"&gt;t&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="c1"&gt;// Executor with fixed pool&lt;/span&gt;
&lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shutdown&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Virtual Threads (JDK 21+)
&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;// Single virtual thread&lt;/span&gt;
&lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;virtualThread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&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="n"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Executor that creates a virtual thread per task&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;virtualThreadExecutor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;virtualThreadExecutor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;handleRequest&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;
  
  
  What’s Really Different Here?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  → Difference in Mechanics: Platform v/s Virtual
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Platform Thread&lt;/strong&gt; in Java is a one-to-one wrapper around an operating system thread.&lt;br&gt;
Each platform thread corresponds directly to an OS-managed thread, with scheduling, stack allocation, and blocking semantics handled by the operating system.&lt;/p&gt;

&lt;p&gt;Because of that one-to-one relationship, &lt;strong&gt;creating large numbers of platform threads consumes significant native memory&lt;/strong&gt; and kernel resources.&lt;/p&gt;

&lt;p&gt;When a platform thread performs a blocking I/O call, the underlying OS thread thread sits idle until the operation completes. meaning that system-level thread cannot execute other tasks during that period. That’s why traditional applications rely on &lt;strong&gt;"right"&lt;/strong&gt; fixed-size thread pools — to keep control over how many OS threads exist at once.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Virtual Thread&lt;/strong&gt;, changes only the &lt;strong&gt;implementation model — not the programming model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A virtual thread is still an instance of &lt;code&gt;java.lang.Thread&lt;/code&gt;, but instead of being tied to an OS thread, it is &lt;strong&gt;scheduled by the JVM&lt;/strong&gt; and &lt;strong&gt;runs on top of a small, fixed set of carrier threads&lt;/strong&gt; (which are regular platform threads).&lt;/p&gt;

&lt;p&gt;When a virtual thread performs a blocking operation, the &lt;strong&gt;JVM parks that virtual thread&lt;/strong&gt; and &lt;strong&gt;detaches it from its carrier&lt;/strong&gt;, freeing the carrier to &lt;strong&gt;run another virtual thread&lt;/strong&gt;.&lt;br&gt;
When the blocking operation completes, the virtual thread is resumed — possibly on the same or a different carrier thread.&lt;br&gt;
All of this happens transparently, without changing the semantics of the blocking APIs.&lt;/p&gt;
&lt;h3&gt;
  
  
  → Scheduling Responsibility
&lt;/h3&gt;

&lt;p&gt;The key &lt;strong&gt;distinction is who manages scheduling and blocking&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;platform threads&lt;/strong&gt;, it’s the operating system scheduler.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;virtual threads&lt;/strong&gt;, it’s the JVM runtime scheduler, implemented entirely in user space.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the JVM controls this scheduling, it can &lt;strong&gt;efficiently manage millions of virtual threads&lt;/strong&gt;, each with a small memory footprint and negligible creation cost compared to platform threads.&lt;br&gt;
This makes virtual threads ideal for I/O-bound, high-concurrency workloads — for example, servers handling thousands of simultaneous connections using blocking code.&lt;/p&gt;
&lt;h3&gt;
  
  
  → Important Consideration
&lt;/h3&gt;

&lt;p&gt;It’s really important to note that &lt;strong&gt;virtual threads don’t change CPU throughput&lt;/strong&gt;.&lt;br&gt;
For &lt;strong&gt;CPU-bound&lt;/strong&gt; workloads, where tasks actively use the processor rather than waiting, performance remains limited by available CPU cores.&lt;br&gt;
Virtual threads primarily optimize &lt;strong&gt;concurrency and scalability&lt;/strong&gt;, not computation speed. &lt;br&gt;
We will see this in example...&lt;/p&gt;


&lt;h2&gt;
  
  
  📈 Performance Comparison: Virtual vs Platform Threads
&lt;/h2&gt;

&lt;p&gt;To get a practical sense of how these differences play out, let’s look at two simple benchmarks - one I/O-bound and one CPU-bound.&lt;/p&gt;
&lt;h3&gt;
  
  
  I/O-Bound
&lt;/h3&gt;

&lt;p&gt;Testing how both models handle high concurrency with blocking operations.&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;VirtualVsPlatformIoBound&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="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;IO_TASKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10_000&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="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;IO_SLEEP_MS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&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;long&lt;/span&gt; &lt;span class="nf"&gt;measureIO&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;label&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&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;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;IO_TASKS&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&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="n"&gt;remoteApiCall&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shutdown&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;awaitTermination&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="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MINUTES&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;elapsed&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;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&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;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s finished in %d ms\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elapsed&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;elapsed&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;remoteApiCall&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;IO_SLEEP_MS&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Simulated blocking I/O&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;interrupt&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;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Test&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VirtualVsPlatformIoBoundTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;measureIO&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ioBound&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;VirtualVsPlatformIoBound&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;"==== I/O-Bound Workload ===="&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;ioPlatform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ioBound&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;measureIO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Platform Threads"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;ioVirtual&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ioBound&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;measureIO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Virtual Threads"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ioPlatform&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;ioVirtual&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;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Speedup(I/O-bound): %.2fx\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&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;h4&gt;
  
  
  I/O-Bound Result
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;====&lt;/span&gt; I/O-Bound Workload &lt;span class="o"&gt;====&lt;/span&gt;
Platform Threads finished &lt;span class="k"&gt;in &lt;/span&gt;2689 ms
Virtual Threads finished &lt;span class="k"&gt;in &lt;/span&gt;126 ms
Speedup&lt;span class="o"&gt;(&lt;/span&gt;I/O-bound&lt;span class="o"&gt;)&lt;/span&gt;: 21.34x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CPU-Bound
&lt;/h3&gt;

&lt;p&gt;Testing performance when tasks are purely computational.&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;VirtualVsPlatformCpuBound&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="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;CPU_TASK_COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50_000&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;long&lt;/span&gt; &lt;span class="nf"&gt;measureCPU&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;label&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&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;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;CPU_TASK_COUNT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&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="n"&gt;cpuIntensiveTask&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shutdown&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;awaitTermination&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="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MINUTES&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;elapsed&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;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&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;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s finished in %d ms\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elapsed&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;elapsed&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Burning CPU&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="nf"&gt;cpuIntensiveTask&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;sum&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="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2_00_000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;37L&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;11&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;sum&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;span class="c1"&gt;// Test&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VirtualVsPlatformCpuBoundTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;measureCPU&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cpuBound&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;VirtualVsPlatformCpuBound&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;"==== CPU-Bound Workload ===="&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;cpuPlatform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cpuBound&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;measureCPU&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Platform Threads"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;cpuVirtual&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cpuBound&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;measureCPU&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Virtual Threads"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;cpuPlatform&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;cpuVirtual&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;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Speedup(CPU-bound): %.2fx\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&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;h4&gt;
  
  
  CPU-Bound Result
&lt;/h4&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="no"&gt;CPU&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nc"&gt;Bound&lt;/span&gt; &lt;span class="nc"&gt;Workload&lt;/span&gt; &lt;span class="o"&gt;====&lt;/span&gt;
&lt;span class="nc"&gt;Platform&lt;/span&gt; &lt;span class="nc"&gt;Threads&lt;/span&gt; &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;433&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;
&lt;span class="nc"&gt;Virtual&lt;/span&gt; &lt;span class="nc"&gt;Threads&lt;/span&gt; &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;454&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;
&lt;span class="nf"&gt;Speedup&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CPU&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bound&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt; &lt;span class="mf"&gt;0.95&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 Yes, Results will vary depending on hardware and blocking time&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Observations on Results 🔎
&lt;/h4&gt;

&lt;p&gt;Virtual threads dramatically improve &lt;strong&gt;scalability in I/O-bound workloads&lt;/strong&gt; by releasing carriers during blocking operations, enabling thousands of concurrent tasks with minimal overhead.&lt;br&gt;
For &lt;strong&gt;CPU-bound tasks&lt;/strong&gt;, both perform nearly the same; as I mentioned earlier as well — because computation still competes for physical cores, not thread count.&lt;br&gt;
And Yes, I ran the test multiple times for getting the average/combined result.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧭 Wrapping Up
&lt;/h3&gt;

&lt;p&gt;Virtual threads don’t replace the fundamentals — they refine them.&lt;br&gt;
In upcoming posts, I’ll dive into &lt;strong&gt;Structured Concurrency&lt;/strong&gt; and other patterns that build on top of this model.&lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>softwareengineering</category>
      <category>performance</category>
    </item>
    <item>
      <title>Spring Boot Actuators: Custom Endpoint</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Sat, 05 Aug 2023 09:55:56 +0000</pubDate>
      <link>https://dev.to/manojshr/spring-actuators-custom-endpoint-3c9n</link>
      <guid>https://dev.to/manojshr/spring-actuators-custom-endpoint-3c9n</guid>
      <description>&lt;p&gt;In continuation to the blog series on Spring Actuators, In this post, Let's deep dive into more customization we can do with spring actuators.&lt;/p&gt;

&lt;p&gt;No doubt, By default, Spring Actuator exposes a wider set of pre-defined endpoints that can be accessed to gather information about your application's health, metrics, configuration, and more. But there are scenarios where you might want to create custom Actuator endpoints to extend the monitoring and management capabilities of your application. &lt;/p&gt;

&lt;p&gt;Here are some benefits and scenarios where custom endpoints can be useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Administrative Tasks:&lt;/strong&gt; You can use custom endpoints to perform administrative tasks on your application. For example, triggering a specific maintenance routine, clearing cache, or reloading configurations can be exposed through custom endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Health Checks:&lt;/strong&gt; While Actuator provides a default health check endpoint, And in the last Post we deep dived into customizing your health endpoint. But your application might have specific health checks that are beyond the scope of the built-in checks. Custom health check endpoints allow you to implement and expose these checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security and Access Control:&lt;/strong&gt; By creating custom endpoints, you have fine-grained control over who can access specific monitoring and management information. This allows you to restrict access to sensitive endpoints, ensuring that only authorized users or systems can interact with them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party Integrations:&lt;/strong&gt; If your application relies on external services or APIs, you can create custom endpoints to monitor the health and status of these integrations. This can be especially useful to quickly identify issues with external dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex Aggregations:&lt;/strong&gt; The default Actuator endpoints provide basic metrics, but in some cases, you might need to perform complex aggregations and calculations to derive meaningful insights.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building Custom Endpoint
&lt;/h2&gt;

&lt;p&gt;Now, Let's try to build our own custom HTTP actuator endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a class="mentioned-user" href="https://dev.to/endpoint"&gt;@endpoint&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/endpoint"&gt;@endpoint&lt;/a&gt;&lt;/strong&gt; annotation is a core component of Spring Actuators. Once you annotate your class with &lt;a class="mentioned-user" href="https://dev.to/endpoint"&gt;@endpoint&lt;/a&gt; annotation and provide &lt;code&gt;id&lt;/code&gt; field (mandatorily) as custom value, This class will now represent your custom endpoint.&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;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@Endpoint&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="s"&gt;"custom"&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;CustomActuatorEndpoint&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;blockquote&gt;
&lt;p&gt;Do not forget to make your endpoint class spring-managed component by defining @Component annoation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This will make following actuator endpoint available to be served: &lt;code&gt;http://your-example-web-app:2121/actuator/custom&lt;/code&gt;. Not let's define &lt;strong&gt;Operations&lt;/strong&gt; to add the definition for this custom endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Endpoint Operations
&lt;/h3&gt;

&lt;p&gt;Spring Boot Actuator endpoints support mainly 3 basic operations to interact with custom endpoints. You can define methods and annotate them with these annotations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;@ReadOperation:&lt;/strong&gt; @ReadOperation is used to handle HTTP GET requests. It is used to retrieve information from the Actuator endpoint. Typically, this operation is used to expose various metrics, health information, configurations, and other read-only data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;@WriteOperation:&lt;/strong&gt; This operation type is used to handle HTTP POST requests to modify the state of the application or perform actions that have side effects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;@DeleteOperation:&lt;/strong&gt; As it states, @DeleteOperation is used to handle HTTP DELETE requests to remove or delete resources from the application. It can be helpful when you want to provide an API for removing resources or performing specific cleanup tasks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;It is always recommended to secure your actuator endpoint with spring security while exposing sensitive information or performing write/delete operations that alters the state/config of your application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is quiet similar to defining an endpoint using Get/Post/Delete Mappings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Custom Endpoint
&lt;/h3&gt;

&lt;p&gt;Enough Theory 🤔, Let's write a custom actuator endpoint to manage your application release notes.&lt;/p&gt;

&lt;p&gt;This is how your &lt;code&gt;ReleaseNote&lt;/code&gt; data object looks like&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;ReleaseNote&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="n"&gt;version&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;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;date&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="n"&gt;changeLogData&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Constructors&lt;/span&gt;
    &lt;span class="c1"&gt;// Getters/Setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, Let's write &lt;code&gt;ReleaseNoteEndpoint&lt;/code&gt; class which uses &lt;code&gt;ReleaseNotesDataRepository&lt;/code&gt; to manage persistence of your &lt;code&gt;ReleaseNote&lt;/code&gt; object.&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;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@Endpoint&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="s"&gt;"releaseNotes"&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;ReleaseNotesEndpoint&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;ReleaseNotesDataRepository&lt;/span&gt; &lt;span class="n"&gt;releaseNotesDataRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@ReadOperation&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;ReleaseNote&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getReleaseNotes&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;releaseNotesDataRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getReleaseNoteList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@WriteOperation&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ReleaseNote&lt;/span&gt; &lt;span class="nf"&gt;addReleaseNote&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;version&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;changeLogData&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ReleaseNote&lt;/span&gt; &lt;span class="n"&gt;releaseNote&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;ReleaseNote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;changeLogData&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;releaseNotesDataRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addReleaseNote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;releaseNote&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@DeleteOperation&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;deleteReleaseNote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Selector&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;releaseNotesDataRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deleteReleaseNote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;version&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;blockquote&gt;
&lt;p&gt;Spring Actuator comes with &lt;strong&gt;@Selector&lt;/strong&gt; annotation that is used as an argument of an &lt;a class="mentioned-user" href="https://dev.to/endpoint"&gt;@endpoint&lt;/a&gt; method to indicate the path parameter for your endpoint&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's play with the new shiny actuator endpoint to manage release notes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Add new Release Note
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="s1"&gt;'http://localhost:2121/actuator/releaseNotes'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "version": "1.0",
    "changeLogData": "changeLog"
}'&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt;

&lt;span class="c"&gt;# Response&lt;/span&gt;
HTTP/1.1 200 
...
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"version"&lt;/span&gt;:&lt;span class="s2"&gt;"1.0"&lt;/span&gt;,&lt;span class="s2"&gt;"date"&lt;/span&gt;:&lt;span class="s2"&gt;"2023-08-05T15:01:37.456528"&lt;/span&gt;,&lt;span class="s2"&gt;"changeLogData"&lt;/span&gt;:&lt;span class="s2"&gt;"v1.0 changeLog"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  List all Release Notes
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="s1"&gt;'http://localhost:2121/actuator/releaseNotes'&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt;

&lt;span class="c"&gt;# Response&lt;/span&gt;
HTTP/1.1 200 
...
&lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;"version"&lt;/span&gt;:&lt;span class="s2"&gt;"1.0"&lt;/span&gt;,&lt;span class="s2"&gt;"date"&lt;/span&gt;:&lt;span class="s2"&gt;"2023-08-05T15:01:37.456528"&lt;/span&gt;,&lt;span class="s2"&gt;"changeLogData"&lt;/span&gt;:&lt;span class="s2"&gt;"v1.0 changeLog"&lt;/span&gt;&lt;span class="o"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Delete Release Note
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; DELETE &lt;span class="s1"&gt;'http://localhost:2121/actuator/releaseNotes/1.0'&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt;

&lt;span class="c"&gt;# Response&lt;/span&gt;
HTTP/1.1 204 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final Words
&lt;/h3&gt;

&lt;p&gt;Incorporating custom Actuator endpoints into your Spring Boot applications can be really helpful to fulfil your custom needs. These tailored endpoints empower your boot application to extract specific insights, enact administrative tasks, and dynamically adjust configurations. Would love to hear your experience and thoughts!&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>monitoring</category>
      <category>spring</category>
    </item>
    <item>
      <title>Spring Boot Actuators: Customise Health Endpoint</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Sat, 22 Jul 2023 11:38:30 +0000</pubDate>
      <link>https://dev.to/manojshr/customise-health-endpoint-2e1</link>
      <guid>https://dev.to/manojshr/customise-health-endpoint-2e1</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/manojshr/spring-boot-actuators-to-expose-operational-info-2aok"&gt;last post&lt;/a&gt;, I talked about configuring and leveraging spring boot actuators to configure your boot application to have production ready features.&lt;/p&gt;

&lt;p&gt;In this Post, let's customise &lt;strong&gt;Health&lt;/strong&gt; endpoint, which is one of the important actuator endpoint, It helps in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring Application Health&lt;/strong&gt;: The Health endpoint provides a simple and standardized way to monitor the health of your application. It allows you to quickly check whether your application is running correctly or encountering any issues. Monitoring the health status of your application helps you identify and respond to potential problems early, reducing downtime and ensuring a better user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proactive Issue Detection&lt;/strong&gt;: By regularly polling the Health endpoint, monitoring tools and systems can proactively detect any degradation or failure in your application's health. This enables your operations team to take immediate action before issues escalate and impact users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with Orchestration Tools&lt;/strong&gt;: In modern production environments, applications are often managed and orchestrated by tools like Kubernetes, Docker Swarm, or cloud platforms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational Insights&lt;/strong&gt;: The Health endpoint provides essential information about your application's internals. You can customize the endpoint to include details about database connections, external service status, resource availability, and more. These details are valuable for troubleshooting and gaining insights into your application's behavior during runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spring Actuators provide rich API support to customize health endpoint response.&lt;/p&gt;

&lt;p&gt;Let's first enable health endpoint from the configurations and allow it to show details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;management.endpoints.web.exposure.include&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;health&lt;/span&gt;
&lt;span class="py"&gt;management.endpoint.health.show-details&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;By default&lt;/strong&gt;, it exposes ping status and disk details:&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;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"components"&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;"diskSpace"&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="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&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;"ping"&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;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UP"&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;We can disable this default response by setting &lt;code&gt;management.health.defaults.enabled&lt;/code&gt; property to &lt;code&gt;false&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Customising Health endpoint by implementing HealthIndicator
&lt;/h3&gt;

&lt;p&gt;Implementing the HealthIndicator interface allows you to create custom health indicators to monitor specific aspects of your application.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;HealthIndicator&lt;/code&gt; (package: org.springframework.boot.actuate.health) interface is part of the Spring Boot Actuator module, and it provides a single method, &lt;code&gt;health()&lt;/code&gt;, that returns a &lt;code&gt;Health&lt;/code&gt; object representing the health status of your custom indicator. It provides several static methods to create instances of Health, as well as to add additional details and contextual information about the health check.&lt;/p&gt;

&lt;p&gt;Here are some commonly used static methods of the &lt;code&gt;Health&lt;/code&gt; class:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;up():&lt;/strong&gt; Creates a Health instance with an &lt;code&gt;UP&lt;/code&gt; status, indicating that the application is in a healthy state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;down():&lt;/strong&gt; Creates a Health instance with a &lt;code&gt;DOWN&lt;/code&gt; status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;unknown():&lt;/strong&gt; Creates a Health instance with an &lt;code&gt;UNKNOWN&lt;/code&gt; status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;status(Status status):&lt;/strong&gt; Creates a Health instance with a custom status. The Status enum represents the health status, and it can be &lt;code&gt;UP, DOWN, or UNKNOWN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;withDetail(String key, Object value):&lt;/strong&gt; Adds additional details to the Health instance. These details provide more information about the health status and can be useful for troubleshooting and monitoring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;withDetails(Map details):&lt;/strong&gt; Adds multiple details to the Health instance at once, using a Map of key-value pairs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's now write an implementation of the &lt;code&gt;HealthIndicator&lt;/code&gt; interface i.e. &lt;code&gt;ExternalServiceHealthIndicator.class&lt;/code&gt;. It's a typical example, where I am returning a Health object based on HTTP statusCode received from external service call.&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;@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;ExternalServiceHealthIndicator&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;HealthIndicator&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;Random&lt;/span&gt; &lt;span class="n"&gt;randomizer&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;Random&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;statusCodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;503&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;Health&lt;/span&gt; &lt;span class="nf"&gt;health&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="n"&gt;randomStatusCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;statusCodes&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;randomizer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;statusCodes&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="nc"&gt;Health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;healthBuilder&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;Health&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;randomStatusCode&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;healthBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;up&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withDetail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"External_Service"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Service is Up and Running ✅"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withDetail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;503&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;healthBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;down&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withDetail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"External_Service"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Service is Down 🔻"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withDetail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"alternative_url"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://alt-example.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;healthBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;withException&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;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received status: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;randomStatusCode&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="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;
  
  
  @ConditionalOnEnabledHealthIndicator annotation
&lt;/h3&gt;

&lt;p&gt;@ConditionalOnEnabledHealthIndicator is a meta-annotation in &lt;code&gt;org.springframework.boot.actuate.autoconfigure.health&lt;/code&gt; package to conditionally enable or disable the health check provided by that specific indicator and requires &lt;code&gt;indicatorName&lt;/code&gt; as a mandatory String argument which can be enabled with the externalised application configuration. Let's see an example in action.&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;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@ConditionalOnEnabledHealthIndicator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"external_service_health"&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;ExternalServiceHealthIndicator&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;HealthIndicator&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;Health&lt;/span&gt; &lt;span class="nf"&gt;health&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;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 Custom indicator can be enabled/disabled by setting &lt;code&gt;management.health.&amp;lt;custom-indicator&amp;gt;.enabled&lt;/code&gt; property true/false in the application's configuration. If the property is not present or set to false, the indicator will not be enabled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;management.health.external_service_health.enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final Words
&lt;/h3&gt;

&lt;p&gt;Health Endpoint is a really useful endpoint to Monitor your Application health, get Operational insights, health check your deployments. Please share your thoughts/opinions in the comments.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>spring</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Spring Boot Actuators: Expose Operational Info</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Sun, 10 Jul 2022 12:08:38 +0000</pubDate>
      <link>https://dev.to/manojshr/spring-boot-actuators-to-expose-operational-info-2aok</link>
      <guid>https://dev.to/manojshr/spring-boot-actuators-to-expose-operational-info-2aok</guid>
      <description>&lt;p&gt;Spring boot has gained a lot of popularity with time, because of its provided features. and now this framework offers solutions for a wide range of enterprise problems and patterns and fits best into every need, It is bundled with a large number of auto configurable libraries/modules to reduce the boiler plate and allow you to focus on your business logic.&lt;/p&gt;

&lt;p&gt;Spring boot Actuator is one of the popular feature of Spring Boot for creating production ready applications. Actuator exposes set of endpoints to monitor your application health, view metrics, secure them with spring security and many other features that are necessary for you to declare your application production ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features of Spring Boot Actuator
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Spring Boot Actuator module allows you to monitor your applications in 2 ways; either by leveraging HTTP endpoints or &lt;a href="https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/html/production-ready-jmx.html" rel="noopener noreferrer"&gt;JMX&lt;/a&gt; (Java Management Extension). Most of the applications leverage HTTP endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Endpoints:&lt;/strong&gt; Actuator module is bundled with a rich set of HTTP endpoints to monitor and interact with the application. You can even create custom endpoints to fulfil your needs, and also leverage spring-security to secure actuator endpoints.
Few examples are

&lt;ul&gt;
&lt;li&gt;info&lt;/li&gt;
&lt;li&gt;health&lt;/li&gt;
&lt;li&gt;metrics&lt;/li&gt;
&lt;li&gt;beans&lt;/li&gt;
&lt;li&gt;caches&lt;/li&gt;
&lt;li&gt;loggers&lt;/li&gt;
&lt;li&gt;mappings&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metrics:&lt;/strong&gt; Spring Boot Actuator provides support for a instrumentation library, called &lt;strong&gt;Micrometer&lt;/strong&gt;, which is a &lt;strong&gt;vendor neutral application metrics facade&lt;/strong&gt; that captures and exposes application metrics to different monitoring solutions such as Prometheus, Dynatrace, New Relic, DataDog and many more... It provides interfaces for &lt;strong&gt;timers, gauges, counters, distribution summaries, and long task timers&lt;/strong&gt; with a dimensional data model.&lt;/li&gt;
&lt;li&gt;Actuator module is highly (yet simply) configurable and you can utilise your application.[properties|yaml] file to meet most of your customised needs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's build a spring boot application and witness the magic of spring-boot-actuator in action...&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-Requisites:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Java installed on your system (JDK 17 recommended), Try &lt;a href="https://sdkman.io/install" rel="noopener noreferrer"&gt;SDKMAN&lt;/a&gt; to manage your JDK versions.&lt;/li&gt;
&lt;li&gt;Spring project with starter-web dependency.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-G&lt;/span&gt; https://start.spring.io/starter.zip &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gradle-project &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;java &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;packaging&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jar &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;javaVersion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;17 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;web &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;spring-boot-actuator-example &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;baseDir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;spring-boot-actuator-example &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-o&lt;/span&gt; starter.zip
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="c"&gt;# You can specify more options using -d option; like groupId, artifactId, packageName&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;unzip starter.zip
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="c"&gt;# Open project in your preferred IDE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding Spring Boot Actuator to your application
&lt;/h3&gt;

&lt;p&gt;Add 'spring-boot-starter-actuator' dependency in your build configuration file.&lt;br&gt;
For maven users:&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;dependency&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&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;spring-boot-starter-actuator&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For gradle users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.springframework.boot:spring-boot-starter-actuator'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As soon as you add starter-actuator dependency in your classpath and restart the application (after rebuilding), you can see actuator endpoints are enabled by spring boot. By default, &lt;strong&gt;'/actuator'&lt;/strong&gt; is a base-path for your all actuator endpoints.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO 9143 --- [           main] i.c.s.SpringbootActuatorsApplication     : No active profile set, falling back to 1 default profile: "default"
INFO 9143 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
INFO 9143 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
INFO 9143 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.64]
INFO 9143 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
INFO 9143 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 648 ms
INFO 9143 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 1 endpoint(s) beneath base path '/actuator'
INFO 9143 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
INFO 9143 --- [           main] i.c.s.SpringbootActuatorsApplication     : Started SpringbootActuatorsApplication in 1.271 seconds (JVM running for 1.818)
INFO 9143 --- [on(1)-127.0.0.1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
INFO 9143 --- [on(1)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
INFO 9143 --- [on(1)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application is started on port 8080, Let's hit &lt;strong&gt;'/actuator'&lt;/strong&gt; endpoint to see all the available actuator endpoints...&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%2Fuploads%2Farticles%2Fv32emkedz9mwisjoiypd.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%2Fv32emkedz9mwisjoiypd.png" alt="SpringBoot Actuator Endpoint" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can observe there is only &lt;strong&gt;'/actuator/health'&lt;/strong&gt; endpoint is exposed, By default all the other endpoints are disabled, because of security reasons, Since some of the actuator endpoints can expose sensitive data, So be careful...&lt;/p&gt;

&lt;p&gt;Let's enable all the endpoints...Update your 'application.properties' file by setting 'management.endpoints.web.exposure.include' property&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;management.endpoints.web.exposure.include&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;'*'&lt;/strong&gt; pattern will enable all the endpoints exposed by actuator module. But it is recommended to expose a specific set of endpoints (comma separated list) which is necessary for your operational requirement to avoid any security issues. &lt;br&gt;
NOTE: 'shutdown' endpoint will still be disabled since it is highly critical for your application. It is used to gracefully shutdown your application.&lt;br&gt;
Let's try by hitting '&lt;a href="http://localhost:8080/actuator" rel="noopener noreferrer"&gt;http://localhost:8080/actuator&lt;/a&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;"_links"&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;"beans"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/beans"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"caches"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/caches"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"caches-cache"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/caches/{cache}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;true&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;"conditions"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/conditions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"configprops"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/configprops"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"configprops-prefix"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/configprops/{prefix}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;true&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;"env"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/env"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"env-toMatch"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/env/{toMatch}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;true&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;"health"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"health-path"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/health/{*path}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;true&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;"heapdump"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/heapdump"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"info"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"loggers"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/loggers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"loggers-name"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/loggers/{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;"templated"&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="kc"&gt;true&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;"mappings"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/mappings"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"metrics"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/metrics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"metrics-requiredMetricName"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/metrics/{requiredMetricName}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;true&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;"scheduledtasks"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/scheduledtasks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"self"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;"threaddump"&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;"href"&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="s2"&gt;"http://localhost:8080/actuator/threaddump"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"templated"&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="kc"&gt;false&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;Take a look on this &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints" rel="noopener noreferrer"&gt;spring documentation&lt;/a&gt; for detailed explanation of each endpoint.&lt;/p&gt;

&lt;p&gt;*Some more configuration in your application.properties file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;#1. Update default port for actuator endpoints
&lt;/span&gt;&lt;span class="py"&gt;management.server.port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2121&lt;/span&gt;

&lt;span class="c"&gt;#2. Update base-path to use **'/manage'** instead of **'/actuator'**
&lt;/span&gt;&lt;span class="py"&gt;management.endpoints.web.base-path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/manage&lt;/span&gt;

&lt;span class="c"&gt;#3. Following will ensure include all actuator endpoints except 'mappings' and 'heapdump'
&lt;/span&gt;&lt;span class="py"&gt;management.endpoints.web.exposure.include&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;
&lt;span class="py"&gt;management.endpoints.web.exposure.exclude&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;mappings,heapdump&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Health Endpoint
&lt;/h3&gt;

&lt;p&gt;Health endpoint exposes your application's health to outside world (with useful data), This endpoint becomes more important in distributed systems, where liveness of your one service is dependent on another service like databases, queues or other applications.&lt;br&gt;
Now, Let's try &lt;strong&gt;'/actuator/health'&lt;/strong&gt; endpoint, and see the response&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%2Fuploads%2Farticles%2Fipr5q0ehf1knva4w8l1b.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%2Fipr5q0ehf1knva4w8l1b.png" alt="/actuator/health" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Right now the only information being returned by health endpoint is whether the application is up or not, by default health endpoint does not show all of the details. This can be enabled (or securely enabled) by setting value of health.show-details attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;management.endpoint.health.show-details&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;
&lt;span class="c"&gt;# Possible values for health.show-details can be one of the following
# never|always|when_authorized
# by default it is set to 'never', 
# 'always' will display all the details,
# 'when_autorized' will display details when requesting user is authorized.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output (health endpoint with status and diskspace):&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%2Fuploads%2Farticles%2F2z5k0fddyefkeifcpnk1.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%2F2z5k0fddyefkeifcpnk1.png" alt="Health Endpoint with show-details" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Please note Spring Boot Actuator module support configuration update for each endpoint individually by using following pattern.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# Pattern: management.endpoint.{endpoint-name}.{property}=value
# property attribute can vary according to endpoint
&lt;/span&gt;
&lt;span class="py"&gt;management.endpoint.configprops.enabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;management.endpoint.info.enabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;

&lt;span class="py"&gt;management.endpoint.beans.cache.time-to-live&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10s&lt;/span&gt;

&lt;span class="py"&gt;management.endpoint.logfile.external-file&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;~/app.log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Info Endpoint
&lt;/h3&gt;

&lt;p&gt;Let's try &lt;strong&gt;'/actuator/info'&lt;/strong&gt; endpoint now, and see what it returns.&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%2Fuploads%2Farticles%2Fs8cwuwsxu15psltmjiyw.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%2Fs8cwuwsxu15psltmjiyw.png" alt="/actuator/info" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, by default &lt;strong&gt;info&lt;/strong&gt; endpoint does not return any useful information, You can customise the response of info endpoint by updating build configurations, Let's walk through how you can configure the info endpoint in build.gradle file.&lt;br&gt;
Maven users can also follow this official &lt;a href="https://docs.spring.io/spring-boot/docs/1.2.0.RC1/reference/html/production-ready-endpoints.html#production-ready-application-info-automatic-expansion-maven" rel="noopener noreferrer"&gt;spring doc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For gradle users, let's first update the build.gradle file, Add buildInfo task, and update version value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Spring Boot Actuator Configuration App'&lt;/span&gt;
&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2.0.0'&lt;/span&gt;

&lt;span class="n"&gt;springBoot&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buildInfo&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;additional&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
                    &lt;span class="s1"&gt;'lastRelease'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'1.0.0'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;'description'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rootProject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&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;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apart from build info, You can also set additional information in application.properties file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;management.info.env.enabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;

&lt;span class="py"&gt;app.cusomInfo&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;This is Custom Info&lt;/span&gt;
&lt;span class="py"&gt;info.app.cusomInfo&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${app.cusomInfo}&lt;/span&gt;
&lt;span class="py"&gt;info.app.java-version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${java.version}&lt;/span&gt;
&lt;span class="py"&gt;info.app.java-vendor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${java.vendor}&lt;/span&gt;
&lt;span class="py"&gt;info.app.excluded-actuator-enpoints&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${management.endpoints.web.exposure.exclude}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's now see output of &lt;strong&gt;'/actuator/info'&lt;/strong&gt; endpoint:&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%2Fuploads%2Farticles%2Fgrvz0sdq6inxcgvb3yuk.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%2Fgrvz0sdq6inxcgvb3yuk.png" alt="/actuator/info additional info" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can observe all the configured information in response. The info endpoint can be extended further to expose git related info (like commit id, branch).&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Words:
&lt;/h3&gt;

&lt;p&gt;As we can observe just by leveraging the application.[properties|yaml] file, we can fully customise and configure our actuator endpoints to expose useful information. In subsequent posts we will see how we can create custom endpoints, and connect to different monitoring tools using micrometer.&lt;/p&gt;

&lt;p&gt;Source Code: &lt;a href="https://github.com/manojshr/springboot-actuators" rel="noopener noreferrer"&gt;manojshr/springboot-actuators&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please share your thoughts in the comments!&lt;/p&gt;

</description>
      <category>spring</category>
      <category>java</category>
      <category>springboot</category>
    </item>
    <item>
      <title>Ansible for Managing Configurations...</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Fri, 18 Mar 2022 15:27:02 +0000</pubDate>
      <link>https://dev.to/manojshr/ansible-for-managing-configurations-38p</link>
      <guid>https://dev.to/manojshr/ansible-for-managing-configurations-38p</guid>
      <description>&lt;h3&gt;
  
  
  So, What is Ansible?
&lt;/h3&gt;

&lt;p&gt;Ansible is simply an Automation Tool, which handles automation of your IT infrastructure, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ansible.com/use-cases/configuration-management" rel="noopener noreferrer"&gt;Configuration management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ansible.com/use-cases/orchestration" rel="noopener noreferrer"&gt;Multi-node orchestration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ansible.com/use-cases/application-deployment" rel="noopener noreferrer"&gt;Application deployment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html" rel="noopener noreferrer"&gt;Ad-hoc task execution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ansible.com/integrations/networks" rel="noopener noreferrer"&gt;Network automation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ansible.com/use-cases/provisioning" rel="noopener noreferrer"&gt;Provisioning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Few reasons that make Ansible my first choice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ansible is a &lt;strong&gt;Push-based&lt;/strong&gt; configuration management tool that makes it more powerful and different from other configuration management tools. It requires to setup a control node only, and you are good to push your configurations or deployments to any (or self) node configured in your inventory. sounds cleaner way to set up a node :)&lt;/li&gt;
&lt;li&gt;It is &lt;strong&gt;open source&lt;/strong&gt; and free to use.&lt;/li&gt;
&lt;li&gt;CentOS and Ubuntu Linux is one of the choices for application deployments, and by default, Ansible is packaged to support a number of modules that are commonly used for managing the virtual machines.&lt;/li&gt;
&lt;li&gt;Ansible is backed by a strong developer community, so no need to worry if you are stuck, you will get help easily.&lt;/li&gt;
&lt;li&gt;Ansible offers a very high and seamless integration with leading cloud providers (AWS, Azure, GCP), different automation tools (like StackStorm), and various 3rd Party services.&lt;/li&gt;
&lt;li&gt;It is highly customizable based on your workflow requirements, with the ability to easily create new modules/sub-modules and plugins.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  How to Setup?
&lt;/h3&gt;

&lt;p&gt;Ansible is an agentless automation tool that you install on a control node. From the control node, Ansible manages machines and other devices remotely (by default, over the SSH protocol).&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%2Fz8x53o1ksqsdw30ywj4c.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%2Fz8x53o1ksqsdw30ywj4c.png" alt="Ansible flow of Execution" width="661" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ansible is supported on the majority of general-purpose Operating systems. A few of them are Linux (RHEL, CentOS, Fedora, Ubuntu, Debian, Arch), macOS, Windows...&lt;/p&gt;

&lt;p&gt;There are several ways to install Ansible on your control node. If your OS supports a rich package manager that comes with Ansible binaries, go for it. If not, Ansible and its required binaries can be easily installed using python's widely used package management tool, &lt;code&gt;pip&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install pip on your control node (&lt;a href="https://pip.pypa.io/en/stable/installation/" rel="noopener noreferrer"&gt;https://pip.pypa.io/en/stable/installation/&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Install Ansible using pip
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--user&lt;/span&gt; ansible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How Ansible Works?
&lt;/h3&gt;

&lt;p&gt;Ansible works by connecting your control node to managed nodes and pushing out small programs, called "Ansible Modules" to them. Ansible then executes these modules (over SSH by default) and removes them when finished. The configuration of all the managed nodes can be done in the inventory file. Ansible even supports Jinja2 templating to enable dynamic expressions and access to variables and facts.&lt;/p&gt;

&lt;p&gt;So How do we tell Ansible to execute these modules?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Executing an ad-hoc command&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write the flow of your configurations in an Ansible playbook. Ansible Playbook is a YAML file, in which you write ordered instructions for pushing your configurations; these instructions are nothing but writing the modules, which will be executed on the remote hosts.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Let's see an example in action:
&lt;/h3&gt;

&lt;p&gt;Presumably, you have already installed Ansible on your control node, we will go through the process of running the Ansible playbooks step by step.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify Ansible setup on Control Node&lt;/li&gt;
&lt;li&gt;Create the Managed node and configure the SSH keys&lt;/li&gt;
&lt;li&gt;Setup the standard Ansible directory on control Node&lt;/li&gt;
&lt;li&gt;Write a playbook&lt;/li&gt;
&lt;li&gt;Running your playbook&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Verify Ansible setup on Control Node
&lt;/h3&gt;

&lt;p&gt;The Ansible 'ping' module is a simple but useful tool for testing connectivity with a remote host. The module will attempt to connect to the remote, validate a usable 'python', and return 'pong' if successful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ ➜ ansible localhost &lt;span class="nt"&gt;-m&lt;/span&gt; ping
localhost | SUCCESS &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"changed"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"ping"&lt;/span&gt;: &lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Create a managed node and set up the SSH keys
&lt;/h3&gt;

&lt;p&gt;We will bootstrap a minimal Ubuntu virtual machine, where we will setup the configurations using ansible. Additionally, we will setup the SSH keys to allow access to the managed node from your control node.&lt;/p&gt;

&lt;h4&gt;
  
  
  2.A Install multipass
&lt;/h4&gt;

&lt;p&gt;Multipass is a lightweight VM manager, and we can launch Ubuntu instances using the multipass cli.&lt;br&gt;
&lt;strong&gt;Installation Instructions&lt;/strong&gt;: &lt;a href="https://multipass.run" rel="noopener noreferrer"&gt;https://multipass.run&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2.B Launching Multipass instance
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ ➜ &lt;span class="c"&gt;#List available multipass instances&lt;/span&gt;
~ ➜ multipass find
Image                       Aliases           Version          Description
18.04                       bionic            20220310         Ubuntu 18.04 LTS
20.04                       focal,lts         20220308         Ubuntu 20.04 LTS
21.10                       impish            20220309         Ubuntu 21.10

~ ➜ &lt;span class="c"&gt;#Launch bionic instance with default configurations&lt;/span&gt;
~ ➜ multipass launch &lt;span class="nt"&gt;--name&lt;/span&gt; ubuntu-bionic bionic
Launched: ubuntu-bionic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  2.C Copy SSH keys to ubuntu VM
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ ➜ &lt;span class="c"&gt;#Generating SSH key pair&lt;/span&gt;
~ ➜ ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /tmp/ansiblekey &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; y
Generating public/private rsa key pair.
Your identification has been saved &lt;span class="k"&gt;in&lt;/span&gt; /tmp/ansiblekey
Your public key has been saved &lt;span class="k"&gt;in&lt;/span&gt; /tmp/ansiblekey.pub
The key fingerprint is:
SHA256: &amp;lt;random-chars&amp;gt; manojsh@192.168.54.24

~ ➜ &lt;span class="c"&gt;#Copying public key to multipass instance&lt;/span&gt;
~ ➜ &lt;span class="nb"&gt;cat&lt;/span&gt; /tmp/ansiblekey.pub | multipass &lt;span class="nb"&gt;exec &lt;/span&gt;ubuntu-bionic &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; .ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  2.D Verify SSH to multipass instance
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ ➜ &lt;span class="c"&gt;#List Multipass instances&lt;/span&gt;
➜  Installs multipass &lt;span class="nb"&gt;ls
&lt;/span&gt;Name                    State             IPv4             Image
ubuntu-bionic           Running           192.168.215.15    Ubuntu 18.04 LTS

~ ➜ &lt;span class="c"&gt;#SSH into multipass instance&lt;/span&gt;
➜  ssh &lt;span class="nt"&gt;-i&lt;/span&gt; /tmp/ansiblekey ubuntu@192.168.215.15
The authenticity of host &lt;span class="s1"&gt;'192.168.215.15 (192.168.215.15)'&lt;/span&gt; can not be established.
ED25519 key fingerprint is &amp;lt;random-chars&amp;gt;.
This key is not known by any other names
Are you sure you want to &lt;span class="k"&gt;continue &lt;/span&gt;connecting &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt;/no/[fingerprint]&lt;span class="o"&gt;)&lt;/span&gt;? &lt;span class="nb"&gt;yes

&lt;/span&gt;To run a &lt;span class="nb"&gt;command &lt;/span&gt;as administrator &lt;span class="o"&gt;(&lt;/span&gt;user &lt;span class="s2"&gt;"root"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, use &lt;span class="s2"&gt;"sudo &amp;lt;command&amp;gt;"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
See &lt;span class="s2"&gt;"man sudo_root"&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;details.

ubuntu@ubuntu-bionic:~&lt;span class="nv"&gt;$ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  3. Setup the standard Ansible directory on control Node
&lt;/h3&gt;
&lt;h4&gt;
  
  
  3.A Create an &lt;code&gt;AnsibleWorkspace&lt;/code&gt; directory
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ ➜ &lt;span class="c"&gt;#Create a directory where you can keep your playbooks, inventory and other required files.&lt;/span&gt;
~ ➜ &lt;span class="nb"&gt;mkdir &lt;/span&gt;AnsibleWorkspace
~ ➜ &lt;span class="nb"&gt;cd &lt;/span&gt;AnsibleWorkspace
AnsibleWorkspace ➜ &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt;  ..
AnsibleWorkspace ➜ 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  3.B Create &lt;code&gt;ansible.cfg&lt;/code&gt; file
&lt;/h4&gt;

&lt;p&gt;'ansible.cfg' is a main configuration file that governs the behavior of all interactions performed by the control node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ ➜ &lt;span class="c"&gt;#Generating default ansible config file with all properties disabled&lt;/span&gt;
AnsibleWorkspace ➜ ansible-config init &lt;span class="nt"&gt;--disabled&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ansible.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3.B Create inventory file
&lt;/h4&gt;

&lt;p&gt;Ansible works against managed hosts that are configured in your inventory file as a list or group of lists. The default location for inventory is &lt;code&gt;/etc/ansible/hosts&lt;/code&gt;, but we can override this by updating path value of &lt;code&gt;inventory&lt;/code&gt; field in &lt;code&gt;ansible.cfg&lt;/code&gt; file. Let's first create an inventory file for our multipass ubuntu instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;AnsibleWorkspace ➜ &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ./inventory &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOL&lt;/span&gt;&lt;span class="sh"&gt;
[webservers]
nginxserver ansible_host=192.168.215.15 ansible_user=ubuntu
&lt;/span&gt;&lt;span class="no"&gt;EOL
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ansible_host&lt;/code&gt; and &lt;code&gt;ansible_user&lt;/code&gt; values are nothing but the IPAddress and username of your configured multipass instance; using this info ansible will connect to the multipass instance via SSH.&lt;/p&gt;

&lt;p&gt;Please read this official &lt;a href="https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html" rel="noopener noreferrer"&gt;link&lt;/a&gt; to learn more about inventory file creation.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.C Update inventory and ssh-key file path in 'ansible.cfg' file
&lt;/h4&gt;

&lt;p&gt;Open the ansible.cfg file and set the following values under defaults section&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[defaults]&lt;/span&gt;
&lt;span class="py"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;./inventory&lt;/span&gt;
&lt;span class="py"&gt;private_key_file&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/tmp/ansiblekey&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3.D Verify the Ansible Configuration
&lt;/h4&gt;

&lt;p&gt;Since we have already configured inventory and private key path, we are good to verify connectivity with our multipass instance 'nginxserver'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  AnsibleWorkspace ansible nginxserver &lt;span class="nt"&gt;-m&lt;/span&gt; ping                                            
nginxserver | SUCCESS &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"ansible_facts"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"discovered_interpreter_python"&lt;/span&gt;: &lt;span class="s2"&gt;"/usr/bin/python3"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="s2"&gt;"changed"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"ping"&lt;/span&gt;: &lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Write a playbook
&lt;/h3&gt;

&lt;p&gt;Playbooks are the language by which Ansible orchestrates, configures, administers, or deploys systems. &lt;br&gt;
Let's write a playbook to setup an Nginx server.&lt;br&gt;
Create &lt;code&gt;nginx-setup.yml&lt;/code&gt; file in your &lt;code&gt;AnsibleWorkspace&lt;/code&gt; directory with tasks to install and start an Nginx server.&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="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginxserver&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;
  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&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;Install nginx latest version on host&lt;/span&gt;
      &lt;span class="na"&gt;apt&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;nginx&lt;/span&gt; 
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&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;Start nginx service&lt;/span&gt;
      &lt;span class="na"&gt;service&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;nginx&lt;/span&gt;
          &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;started&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a look at each and every part of your playbook file:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;hosts:&lt;/strong&gt; The name of the node or node-group configured in your inventory.&lt;br&gt;
&lt;strong&gt;become:&lt;/strong&gt; The become flag instructs ansible to connect as a root user.&lt;br&gt;
&lt;strong&gt;tasks:&lt;/strong&gt; tasks is a list of modules that we wish to run on the managed node in a specific order. Every task will include a 'name' field as well as a'module' with configurable arguments.&lt;br&gt;
&lt;strong&gt;apt&lt;/strong&gt; The &lt;a href="https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html" rel="noopener noreferrer"&gt;apt&lt;/a&gt; module will install the newest version of Nginx using the standard Ubuntu apt package manager.&lt;br&gt;
&lt;strong&gt;service&lt;/strong&gt; &lt;a href="https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_module.html" rel="noopener noreferrer"&gt;service&lt;/a&gt; module controls services on managed node.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Running your playbook
&lt;/h3&gt;

&lt;p&gt;Ansible is packaged with a set of binaries, We can run an ansible playbook using the &lt;code&gt;ansible-playbook&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;AnsibleWorkspace ➜ ansible-playbook nginx-setup.yaml                                                        

PLAY &lt;span class="o"&gt;[&lt;/span&gt;nginxserver] &lt;span class="k"&gt;**************************************************************&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Gathering Facts] &lt;span class="k"&gt;**************************************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;nginxserver]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Install nginx latest version on host] &lt;span class="k"&gt;**************************************************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;nginxserver]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Start nginx service] &lt;span class="k"&gt;**************************************************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;nginxserver]

PLAY RECAP &lt;span class="k"&gt;**************************************************************&lt;/span&gt;
nginxserver                : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;skipped&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;rescued&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Playbook executed without any error, and we can see it has installed and started nginx service. Now, let's verify the output, go to &lt;a href="http://192.168.215.15" rel="noopener noreferrer"&gt;http://192.168.215.15&lt;/a&gt; (multipass instance ip, default port 80) in your browser.&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%2Fp4full8bidibalepgzuu.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%2Fp4full8bidibalepgzuu.png" alt="Output" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Words
&lt;/h3&gt;

&lt;p&gt;Ansible is a straightforward yet powerful automation solution for automating your IT infrastructure. It can manage modest to large-scale systems. We can use ad-hoc commands to meet simple demands or construct complicated playbooks to set up a multi-node orchestration.&lt;br&gt;
Resources to learn more about ansible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ansible.com/overview/how-ansible-works" rel="noopener noreferrer"&gt;https://www.ansible.com/overview/how-ansible-works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.ansible.com/ansible/latest/user_guide/intro_getting_started.html" rel="noopener noreferrer"&gt;https://docs.ansible.com/ansible/latest/user_guide/intro_getting_started.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/ZAdJ7CdN7DY" rel="noopener noreferrer"&gt;https://youtu.be/ZAdJ7CdN7DY&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spacelift.io/blog/ansible-tutorial" rel="noopener noreferrer"&gt;https://spacelift.io/blog/ansible-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ansible</category>
      <category>automation</category>
      <category>ubuntu</category>
      <category>multipass</category>
    </item>
    <item>
      <title>JDK 18: Simple Web Server</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Sat, 22 Jan 2022 10:00:01 +0000</pubDate>
      <link>https://dev.to/manojshr/jdk-18-simple-web-server-4dka</link>
      <guid>https://dev.to/manojshr/jdk-18-simple-web-server-4dka</guid>
      <description>&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%2F5deeds2qu02ciardid0e.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%2F5deeds2qu02ciardid0e.png" alt="JDK" width="253" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;JDK 18 version is all set to release in &lt;strong&gt;March 2022&lt;/strong&gt; and will be coming with 9 new features (with some enhancement features from the previous versions).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;400: UTF-8 by Default&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;408: Simple Web Server&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;413: Code Snippets in Java API Documentation&lt;/li&gt;
&lt;li&gt;416: Reimplement Core Reflection with Method Handles&lt;/li&gt;
&lt;li&gt;417: Vector API (Third Incubator)&lt;/li&gt;
&lt;li&gt;418: Internet-Address Resolution SPI&lt;/li&gt;
&lt;li&gt;419: Foreign Function &amp;amp; Memory API (Second Incubator)&lt;/li&gt;
&lt;li&gt;420: Pattern Matching for switch (Second Preview)&lt;/li&gt;
&lt;li&gt;421: Deprecate Finalization for Removal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;JDK 18 will be packaged with a &lt;strong&gt;NEW&lt;/strong&gt; command line (i.e. &lt;strong&gt;jwebserver&lt;/strong&gt;) tool to start a minimal web server that serves static files only. As of now (even no confirmations about future plans), there is No CGI or servlet-like functionality available with &lt;strong&gt;jwebserver&lt;/strong&gt;. This tool will be useful for prototyping, ad-hoc coding, and testing purposes, particularly in educational contexts.&lt;/p&gt;

&lt;p&gt;The Simple Web Server is a minimal HTTP server for serving a single directory hierarchy and can be used via the dedicated command-line tool &lt;strong&gt;jwebserver&lt;/strong&gt; or programmatically via its API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation of JDK 18 EA builds (as of now only EA builds are available):
&lt;/h3&gt;

&lt;p&gt;One can download the JDK 18 Early-Access Builds from &lt;a href="https://jdk.java.net/18/" rel="noopener noreferrer"&gt;jdk.java.net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or Another way to manage the JDK versions would be using &lt;a href="https://sdkman.io/install" rel="noopener noreferrer"&gt;SDKMAN&lt;/a&gt;. Take a look at the &lt;a href="https://sdkman.io/usage" rel="noopener noreferrer"&gt;usage page&lt;/a&gt; to setup desired java version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://get.sdkman.io"&lt;/span&gt; | bash
&lt;span class="nv"&gt;$ &lt;/span&gt;sdk &lt;span class="nb"&gt;install &lt;/span&gt;java 18.ea.31-open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A. Using &lt;strong&gt;&lt;em&gt;jwebserver&lt;/em&gt;&lt;/strong&gt; Command Line:
&lt;/h3&gt;

&lt;p&gt;After installing JDK 18 we are set to use jwebserver command line utility. &lt;br&gt;
By default, the server runs in the foreground and binds to the loopback address and port 8000. Also, if the directory (-d option) is not specified, files are served from the current directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;jwebserver &lt;span class="nt"&gt;--help&lt;/span&gt;
Usage: jwebserver &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="nb"&gt;bind &lt;/span&gt;address] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-p&lt;/span&gt; port] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-d&lt;/span&gt; directory]
                  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-o&lt;/span&gt; none|info|verbose] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-h&lt;/span&gt; to show options]
                  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-version&lt;/span&gt; to show version information]
Options:
&lt;span class="nt"&gt;-b&lt;/span&gt;, &lt;span class="nt"&gt;--bind-address&lt;/span&gt;    - Address to &lt;span class="nb"&gt;bind &lt;/span&gt;to. Default: 127.0.0.1 &lt;span class="o"&gt;(&lt;/span&gt;loopback&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
                        For all interfaces use &lt;span class="s2"&gt;"-b 0.0.0.0"&lt;/span&gt; or &lt;span class="s2"&gt;"-b ::"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nt"&gt;-d&lt;/span&gt;, &lt;span class="nt"&gt;--directory&lt;/span&gt;       - Directory to serve. Default: current directory.
&lt;span class="nt"&gt;-o&lt;/span&gt;, &lt;span class="nt"&gt;--output&lt;/span&gt;          - Output format. none|info|verbose. Default: info.
&lt;span class="nt"&gt;-p&lt;/span&gt;, &lt;span class="nt"&gt;--port&lt;/span&gt;            - Port to listen on. Default: 8000.
&lt;span class="nt"&gt;-h&lt;/span&gt;, -?, &lt;span class="nt"&gt;--help&lt;/span&gt;        - Prints this &lt;span class="nb"&gt;help &lt;/span&gt;message and exits.
&lt;span class="nt"&gt;-version&lt;/span&gt;, &lt;span class="nt"&gt;--version&lt;/span&gt;   - Prints version information and exits.
To stop the server, press Ctrl + C.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s serve a directory containing HTML content using jwebserver, and see how this utility made it easier.&lt;/p&gt;

&lt;p&gt;1) Create a directory and add an index.html file in the directory with some html content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;jdk18-webserver
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;jdk18-webserver
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;h1&amp;gt;Hello World from JWebServer&amp;lt;/h1&amp;gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) Run the jwebserver&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;jwebserver &lt;span class="nt"&gt;-p&lt;/span&gt; 8080 &lt;span class="nt"&gt;-d&lt;/span&gt; /Users/home/jdk18-webserver

Binding to loopback by default. For all interfaces use &lt;span class="s2"&gt;"-b 0.0.0.0"&lt;/span&gt; or &lt;span class="s2"&gt;"-b ::"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Serving /Users/home/jdk18-jwebserver and subdirectories on 127.0.0.1 port 8080
URL http://127.0.0.1:8080/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  B. Using APIs:
&lt;/h3&gt;

&lt;p&gt;While the command-line tool is useful, what if one wants to use the components of the Simple Web Server (i.e. server, handler, and filter) with existing code, or further customize the behavior of the handler?&lt;/p&gt;

&lt;p&gt;This Simple Webserver API is based on the web server implementation in the &lt;code&gt;com.sun.net.httpserver&lt;/code&gt; package that has been included in the JDK since &lt;code&gt;2006&lt;/code&gt;. The package is officially supported and extended with APIs to simplify server creation and enhance request handling.&lt;/p&gt;

&lt;p&gt;The SimpleFileServer class supports the creation of a file server, a file-server handler, and an output filter:&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;package&lt;/span&gt; &lt;span class="nn"&gt;com.sun.net.httpserver&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleFileServer&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="nc"&gt;HttpServer&lt;/span&gt; &lt;span class="nf"&gt;createFileServer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InetSocketAddress&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                              &lt;span class="nc"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;rootDirectory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                              &lt;span class="nc"&gt;OutputLevel&lt;/span&gt; &lt;span class="n"&gt;outputLevel&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="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;HttpHandler&lt;/span&gt; &lt;span class="nf"&gt;createFileHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;rootDirectory&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="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Filter&lt;/span&gt; &lt;span class="nf"&gt;createOutputFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OutputStream&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                            &lt;span class="nc"&gt;OutputLevel&lt;/span&gt; &lt;span class="n"&gt;outputLevel&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;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's create a server instance using jshell.&lt;br&gt;
1) Define the server configurations.&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;jshell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.sun.net.httpserver.SimpleFileServer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;jshell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/Users/home/jdk18-webserver"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;jshell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="no"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;jshell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SimpleFileServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createFileServer&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;InetSocketAddress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;SimpleFileServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;OutputLevel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VERBOSE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) Starting the web server: static method &lt;code&gt;SimpleFileServer.createFileServer()&lt;/code&gt; returns the instance of &lt;code&gt;com.sun.net.httpserver.HttpServer&lt;/code&gt; which can be used to start or stop the server.&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;jshell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;server&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logs generated on hitting the URL (&lt;a href="http://127.0.0.1:8080" rel="noopener noreferrer"&gt;http://127.0.0.1:8080&lt;/a&gt;) -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jshell&amp;gt; 127.0.0.1 - - "GET / HTTP/1.1" 200 -
Resource requested: /Users/home/jdk18-jwebserver
&amp;gt; Accept-encoding: gzip, deflate, br
&amp;gt; Accept: text/html,application/...
&amp;gt; Sec-fetch-dest: document
&amp;gt; Sec-fetch-user: ?1
&amp;gt; Connection: keep-alive
&amp;gt; Sec-fetch-site: none
&amp;gt; Host: 127.0.0.1:8080
&amp;gt; Accept-language: en-GB,en;q=0.9,en-US;q=0.8
...
...
...
&amp;lt; Content-type: text/html
&amp;lt; Content-length: 36
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3) Stopping the server: The HttpServer instance has stop method which accepts delay in seconds as Integer argument. The method will then block until all current exchange handlers have completed or else when approximately delay seconds have elapsed (whichever happens sooner).&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;// server.stop(delay: Integer)&lt;/span&gt;
&lt;span class="n"&gt;jshell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stop&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Thoughts
&lt;/h3&gt;

&lt;p&gt;As Intended, The Simple Web Server is not so feature-rich, but it is an appropriate tool to get your static contents served without handling the hassles of writing a huge chunk of code for such a small work to be done. To learn more about jwebserver, check out the official &lt;a href="https://openjdk.java.net/jeps/408" rel="noopener noreferrer"&gt;JEP 408&lt;/a&gt; document...&lt;/p&gt;

&lt;p&gt;Please share your thoughts in the comments!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
