<?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: esteban389</title>
    <description>The latest articles on DEV Community by esteban389 (@esteban389).</description>
    <link>https://dev.to/esteban389</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2955113%2F3f9a16f7-c856-4fe6-a162-0a648686f085.png</url>
      <title>DEV Community: esteban389</title>
      <link>https://dev.to/esteban389</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/esteban389"/>
    <language>en</language>
    <item>
      <title>Why Our Next.js Deployments Took 30 Minutes</title>
      <dc:creator>esteban389</dc:creator>
      <pubDate>Fri, 28 Aug 2026 20:03:04 +0000</pubDate>
      <link>https://dev.to/esteban389/why-our-nextjs-deployments-took-30-minutes-4ha6</link>
      <guid>https://dev.to/esteban389/why-our-nextjs-deployments-took-30-minutes-4ha6</guid>
      <description>&lt;p&gt;Frontend deployments could take anywhere from 18 to 30 minutes. Eventually, I&lt;br&gt;
started letting changes accumulate so the wait felt more justified.&lt;/p&gt;

&lt;p&gt;Sometimes that was fine. Sometimes it meant a change sat longer than it should&lt;br&gt;
have. The same delay was harder to accept when the change was a critical fix. I&lt;br&gt;
started to dread deploying the frontend, and the wait began influencing when I&lt;br&gt;
chose to ship changes.&lt;/p&gt;

&lt;p&gt;I did not write the Dockerfile behind those deployments. It was already in the&lt;br&gt;
repository when I joined as a junior, and I did not have an opinion about it then.&lt;br&gt;
For local development and builds, I usually ran Node.js directly. The Dockerfile&lt;br&gt;
stayed mostly outside my field of view until I had more experience and was allowed&lt;br&gt;
to perform deployments myself.&lt;/p&gt;

&lt;p&gt;Once the cost became part of my own workflow, I investigated why the frontend job&lt;br&gt;
took so much longer than two backend jobs in the same pipeline. Inspecting the&lt;br&gt;
deployment path made the shipped artifact the next object to measure.&lt;/p&gt;
&lt;h2&gt;
  
  
  The deployment moved the whole image
&lt;/h2&gt;

&lt;p&gt;The inspected deployment job did not pull the frontend image from a registry. It&lt;br&gt;
used a command shaped like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker save &amp;lt;image&amp;gt; | ssh &amp;lt;server&amp;gt; docker load
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this incident, the job streamed the complete image to the server and loaded it&lt;br&gt;
there. A larger image meant more bytes for that path to transfer and load.&lt;/p&gt;

&lt;p&gt;This was also why the two backend services were useful clues. They used the same&lt;br&gt;
broad deployment mechanism but shipped a JRE base plus one application JAR. Their&lt;br&gt;
jobs completed much sooner. The frontend image used Node.js and Next.js; different&lt;br&gt;
runtime stacks need not produce equal image sizes. The comparison only gave us a&lt;br&gt;
specific place to investigate.&lt;/p&gt;

&lt;p&gt;This does not prove that image transfer consumed every minute of the observed&lt;br&gt;
18-30 minute duration. Compilation, network throughput, remote disk performance,&lt;br&gt;
image loading, container replacement, and health checks can all contribute. It&lt;br&gt;
does establish that this job moved the entire artifact, making its contents part&lt;br&gt;
of deployment performance.&lt;/p&gt;

&lt;p&gt;Other pipelines may behave differently. A registry can reuse layers and changes&lt;br&gt;
the transfer model. The diagnosis here belongs to the inspected full-image&lt;br&gt;
transfer job, not to every slow Docker deploy.&lt;/p&gt;
&lt;h2&gt;
  
  
  The runtime image still contained the build workspace
&lt;/h2&gt;

&lt;p&gt;The frontend Dockerfile already used multiple stages, but the final stage copied&lt;br&gt;
far more than the application needed at runtime. Structurally, it looked like the&lt;br&gt;
following example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Simplified, anonymized skeleton — not the production Dockerfile&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:&amp;lt;full-version&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:&amp;lt;full-version&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;runtime&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/node_modules ./node_modules&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/.next ./.next&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/public ./public&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/package.json ./package.json&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multi-stage syntax did not make the runtime image small by itself. The final&lt;br&gt;
&lt;code&gt;COPY&lt;/code&gt; instructions still selected the complete dependency directory and the&lt;br&gt;
complete Next.js build directory. That included development dependencies and build&lt;br&gt;
output that the running server did not need.&lt;/p&gt;

&lt;p&gt;We built and inspected the existing image rather than guessing from the&lt;br&gt;
Dockerfile. It measured 9.48 GB. The &lt;code&gt;.next&lt;/code&gt; directory accounted for 6.55 GB, and&lt;br&gt;
&lt;code&gt;node_modules&lt;/code&gt; accounted for another 1.78 GB. In this build, &lt;code&gt;.next&lt;/code&gt; included the&lt;br&gt;
persistent webpack cache along with runtime output.&lt;/p&gt;

&lt;p&gt;Those numbers showed that the build workspace had become the runtime contract.&lt;/p&gt;
&lt;h2&gt;
  
  
  Make the runtime boundary explicit
&lt;/h2&gt;

&lt;p&gt;Next.js standalone mode generated the &lt;code&gt;.next/standalone&lt;/code&gt; output used by the final&lt;br&gt;
stage. We enabled it in the Next.js configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simplified configuration excerpt — not the production file&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That output gave the runtime stage a narrower set of files to copy. The replacement&lt;br&gt;
structure looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Simplified, anonymized skeleton — not the production Dockerfile&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:&amp;lt;slim-version&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;runtime&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; NODE_ENV=production&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/.next/standalone ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/.next/static ./.next/static&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/public ./public&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "server.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The copy boundary changed. The runtime stage receives the &lt;code&gt;.next/standalone&lt;/code&gt;&lt;br&gt;
output, static assets, and public files instead of the full &lt;code&gt;node_modules&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;.next&lt;/code&gt; directories. It also uses a slim Node base and runs as a non-root user.&lt;/p&gt;

&lt;p&gt;Built from the same source, the resulting images landed in the approximate&lt;br&gt;
350-380 MB range. That is about one twenty-fifth of the original size, or roughly&lt;br&gt;
96% smaller.&lt;/p&gt;

&lt;p&gt;Size alone was not enough to call the change complete. A narrow copy can omit a&lt;br&gt;
file resolved at runtime. Changing the runtime user can expose a permission&lt;br&gt;
mistake. The smaller artifact had to run the application, not merely finish&lt;br&gt;
&lt;code&gt;docker build&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A smaller image still has to run
&lt;/h2&gt;

&lt;p&gt;We started the standalone container locally against live user and academic&lt;br&gt;
services plus the identity service. Then we completed a real login and navigated&lt;br&gt;
through an authenticated part of the application.&lt;/p&gt;

&lt;p&gt;That path exercised more than a public health endpoint. It required the frontend&lt;br&gt;
server to start, reach its dependencies, complete authentication, serve its&lt;br&gt;
assets, and handle an authenticated route. During that validation we saw no&lt;br&gt;
runtime errors, missing-file failures, or permission problems.&lt;/p&gt;

&lt;p&gt;This test supports a specific conclusion: the reduced image contained what that&lt;br&gt;
authenticated application path needed. It does not prove that every route is&lt;br&gt;
covered, and it does not measure how long the image will take to reach the target&lt;br&gt;
server.&lt;/p&gt;

&lt;p&gt;These checks answer different questions. Artifact size answers “How much are we&lt;br&gt;
shipping?” A real application flow answers “Did we keep enough for this runtime&lt;br&gt;
behavior?” Neither result substitutes for the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I kept the deployment workflow out of scope
&lt;/h2&gt;

&lt;p&gt;Changing the deployment workflow was technically possible. I chose not to start&lt;br&gt;
there. We deploy per tenant, and some tenants use a different workflow because of&lt;br&gt;
internal organizational decisions. Redesigning those paths would have widened the&lt;br&gt;
scope beyond the problem I was trying to solve.&lt;/p&gt;

&lt;p&gt;The image was shared across those paths, and it was the largest bottleneck we had&lt;br&gt;
identified. Improving that artifact let us address the common transfer cost&lt;br&gt;
without first changing the tenant-specific workflows.&lt;/p&gt;

&lt;p&gt;After rollout, the workflow that had taken roughly 18-30 minutes came down to&lt;br&gt;
approximately 5-6 minutes. A second workflow was already faster at roughly 5-10&lt;br&gt;
minutes; with the smaller image, its deployments ranged from a few seconds to&lt;br&gt;
approximately 2 minutes.&lt;/p&gt;

&lt;p&gt;These are operational observations, not controlled benchmarks. The tenant&lt;br&gt;
workflows and their conditions differ, so the two ranges should not be compared as&lt;br&gt;
if only one variable changed. Both improved enough to confirm that the image had&lt;br&gt;
been a material cost in each deployment path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspect, minimize, test
&lt;/h2&gt;

&lt;p&gt;I inherited a Dockerfile that I barely interacted with, then later inherited the&lt;br&gt;
operational cost of what it shipped. Batching changes made the wait feel more&lt;br&gt;
reasonable, but it did not make delivery faster. Looking inside the artifact gave&lt;br&gt;
us a concrete source of transfer work to address.&lt;/p&gt;

&lt;p&gt;This case supports three checks for an inherited runtime image:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inspect the actual runtime image and measure its largest contents.&lt;/li&gt;
&lt;li&gt;Minimize the final-stage copy boundary to what the application needs at runtime.&lt;/li&gt;
&lt;li&gt;Test a real application path that can expose missing files, permissions, and
dependency assumptions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For this case, the first two steps reduced the image to about one twenty-fifth of&lt;br&gt;
its previous size. The third showed that a real authenticated flow still worked.&lt;br&gt;
The rollout then reduced one deployment path from roughly 18-30 minutes to 5-6&lt;br&gt;
minutes and another from roughly 5-10 minutes to between a few seconds and 2&lt;br&gt;
minutes. Future measurements can show whether another pipeline stage becomes the&lt;br&gt;
next dominant cost.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>docker</category>
      <category>devops</category>
    </item>
    <item>
      <title>What Duplicate Users Taught Me About Outbox and Idempotency</title>
      <dc:creator>esteban389</dc:creator>
      <pubDate>Thu, 27 Aug 2026 21:44:46 +0000</pubDate>
      <link>https://dev.to/esteban389/what-duplicate-users-taught-me-about-outbox-and-idempotency-4a7</link>
      <guid>https://dev.to/esteban389/what-duplicate-users-taught-me-about-outbox-and-idempotency-4a7</guid>
      <description>&lt;p&gt;After enough support tickets involving students who couldn't log in, I stopped&lt;br&gt;
seeing each case as an isolated data problem. Staff operations were failing too,&lt;br&gt;
and I kept returning to the same boundary between two services.&lt;/p&gt;

&lt;p&gt;For this post, I'll call those services Student and Users. The names are simplified,&lt;br&gt;
but the requirement is one we had at work: creating a student in Student also&lt;br&gt;
required an application-user record in Users.&lt;/p&gt;

&lt;p&gt;On paper, the flow was short. Student asked Users to create the user, received a&lt;br&gt;
&lt;code&gt;userId&lt;/code&gt;, and then saved the student. The difficult part was everything the network&lt;br&gt;
could leave unanswered between those two local transactions. Student might not&lt;br&gt;
receive a response even though Users committed its work. Retrying could recover the&lt;br&gt;
operation, or repeat an effect that had already happened.&lt;/p&gt;

&lt;p&gt;Transactional outbox, idempotency, and inbox each address part of that problem. The&lt;br&gt;
outbox preserves the work Student still needs done. An idempotency key gives&lt;br&gt;
repeated attempts the same identity. The inbox remembers what Users already did and&lt;br&gt;
what it returned. I'll add them in that order, starting with why the direct call&lt;br&gt;
seemed reasonable.&lt;/p&gt;

&lt;p&gt;I first worked on this path when I was a junior. We knew that one service's&lt;br&gt;
transaction did not magically include the other service. The direct call was a&lt;br&gt;
conscious tradeoff for a one-to-one interaction, not an attempt to pretend the&lt;br&gt;
boundary did not exist.&lt;/p&gt;

&lt;p&gt;Its appeal was easy to see on the happy path. Student called Users, took the returned&lt;br&gt;
ID, and finished saving the student. The code could read almost like the requirement.&lt;/p&gt;

&lt;p&gt;The support cases made the limit harder to ignore. One student's login reached the&lt;br&gt;
application-user lookup and failed there. When we inspected the data, we found three&lt;br&gt;
enabled user records sharing the same document number. Other cases involved students&lt;br&gt;
who couldn't log in or staff operations that failed because the expected student/user&lt;br&gt;
relationship was missing or inconsistent.&lt;/p&gt;

&lt;p&gt;The symptoms varied, but I kept ending up at the same boundary. Student expected one&lt;br&gt;
usable Users record for the student. When that relationship was missing or&lt;br&gt;
ambiguous, an operation that looked like a student problem could fail in Users&lt;br&gt;
instead.&lt;/p&gt;

&lt;p&gt;My reaction was not particularly sophisticated: this is absurd. I knew I could&lt;br&gt;
control the requests to Users better, yet I was still spending time repairing the&lt;br&gt;
consequences when that boundary went wrong.&lt;/p&gt;

&lt;p&gt;I still do not know which historical operation created those three records. A&lt;br&gt;
repeated request is possible, but other sequences are possible too. I can explain&lt;br&gt;
the failure at the service boundary without pretending that it proves the cause of&lt;br&gt;
that incident.&lt;/p&gt;
&lt;h2&gt;
  
  
  The direct call still contains two transactions
&lt;/h2&gt;

&lt;p&gt;At the business level, creating a student and its application user sounds like one&lt;br&gt;
action. The state is still split. Student owns the student record, while Users owns&lt;br&gt;
the user record.&lt;/p&gt;

&lt;p&gt;User creation is part of student creation. Student needs the returned &lt;code&gt;userId&lt;/code&gt; to&lt;br&gt;
connect the records and finish its work. Losing that result leaves the business&lt;br&gt;
operation unfinished from Student's perspective, even if Users has already done its&lt;br&gt;
part.&lt;/p&gt;

&lt;p&gt;Each service can make its own changes atomic. What the call cannot do is merge those&lt;br&gt;
local transactions into a single commit or rollback across both services.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;br&gt;
Once Users commits, Student cannot undo that transaction as if both changes belonged&lt;br&gt;
to one database.&lt;/p&gt;

&lt;p&gt;The direct request also makes Student wait for Users. A failure before Users commits&lt;br&gt;
can stop student creation. A failure after Users commits is more awkward because the&lt;br&gt;
user may exist even though Student did not finish its side.&lt;/p&gt;

&lt;p&gt;Suppose Users creates the user and returns a &lt;code&gt;userId&lt;/code&gt;, but the response never reaches&lt;br&gt;
Student. Student knows that the answer is missing. It does not know whether Users&lt;br&gt;
completed the request. Sending the request again may recover the operation, or it&lt;br&gt;
may repeat the effect unless Users can recognize the attempt.&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;A timeout says that the answer did not arrive. It does not say what Users committed.&lt;/p&gt;
&lt;h2&gt;
  
  
  The outbox preserves Student's intent
&lt;/h2&gt;

&lt;p&gt;I first reached for an outbox after dealing with notifications that had not been&lt;br&gt;
delivered. What bothered me was not only that they failed. Once the original&lt;br&gt;
request was gone, we had little durable state to help us send them again.&lt;/p&gt;

&lt;p&gt;While designing that flow, I started looking at other service boundaries where the&lt;br&gt;
same idea could help. Student and Users was one of them.&lt;/p&gt;

&lt;p&gt;Here, the problem was no longer only that the call could fail. Student's need to&lt;br&gt;
create a user lived inside that one request, and once the request was gone, Student&lt;br&gt;
had no durable record it could return to.&lt;/p&gt;

&lt;p&gt;An outbox gives Student that record. Student saves its own change and a create-user&lt;br&gt;
intent in the same local transaction. If the transaction commits, both are stored.&lt;br&gt;
If it rolls back, neither is stored. A separate sender can process the intent&lt;br&gt;
afterward.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;That was the part I had been missing on the Student side. The request could end&lt;br&gt;
without taking the required work with it. The outbox row would still say which&lt;br&gt;
operation needed to happen and which student it belonged to.&lt;/p&gt;

&lt;p&gt;But keeping the intent available also means a sender may deliver it more than once.&lt;br&gt;
Suppose Users creates the user and returns the result, but Student does not record&lt;br&gt;
that success. The outbox row still looks unfinished, so sending it again is&lt;br&gt;
reasonable from Student's side. Users, meanwhile, may have completed the work&lt;br&gt;
already.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Student now has a way to recover the intent. Users needs a way to recognize that the&lt;br&gt;
next delivery belongs to the same operation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Repeated delivery introduces idempotency
&lt;/h2&gt;

&lt;p&gt;This is where idempotency enters the design. Student assigns one &lt;code&gt;idempotencyKey&lt;/code&gt; to&lt;br&gt;
the create-user operation and reuses it every time the outbox sender delivers that&lt;br&gt;
operation. A fresh key on each attempt would make those attempts look like separate&lt;br&gt;
operations to Users.&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Student can still retry. The key gives Users a stable identity for understanding&lt;br&gt;
that those attempts belong to the same piece of work.&lt;/p&gt;

&lt;p&gt;The terminology can make this sound more abstract than the Student-side code needs&lt;br&gt;
to be. The TypeScript examples in this post are invented, incomplete, and use&lt;br&gt;
Prisma-style calls only to illustrate the two local transactions. They are not&lt;br&gt;
production code.&lt;sup id="fnref3"&gt;3&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The Student transaction creates the student and its outbox row together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;studentData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StudentData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idempotencyKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;student&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;studentData&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;idempotencyKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;studentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create-user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;student&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The outbox row keeps the same &lt;code&gt;idempotencyKey&lt;/code&gt; whenever the sender tries to deliver&lt;br&gt;
this create-user operation again.&lt;/p&gt;
&lt;h2&gt;
  
  
  The inbox keeps the Users result
&lt;/h2&gt;

&lt;p&gt;Once Student can retry, Users needs more than a way to say, “I have seen this&lt;br&gt;
before.” Student still needs the &lt;code&gt;userId&lt;/code&gt; from the first attempt.&lt;/p&gt;

&lt;p&gt;If Users stores only the key, it can avoid creating another user but cannot finish&lt;br&gt;
the original conversation. The inbox needs to keep both the &lt;code&gt;idempotencyKey&lt;/code&gt; and the&lt;br&gt;
result that belongs to it. A repeated request can then receive the same answer&lt;br&gt;
instead of triggering the same change again.&lt;sup id="fnref4"&gt;4&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Here, the inbox is an ordinary table. When the key is new, Users creates the user and&lt;br&gt;
the inbox row in one local transaction. When the key already exists, Users returns&lt;br&gt;
the result it stored earlier.&lt;/p&gt;

&lt;p&gt;Keeping both writes in the same transaction is what makes the record trustworthy.&lt;br&gt;
If user creation fails, there should be no inbox entry claiming it succeeded. If the&lt;br&gt;
inbox write fails, the user creation rolls back with it.&lt;/p&gt;

&lt;p&gt;The Users-side code can stay fairly small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idempotencyKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Ensure it is processed once.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;idempotencyKey&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;idempotencyKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example assumes &lt;code&gt;idempotencyKey&lt;/code&gt; is unique. Two concurrent calls might both check&lt;br&gt;
the inbox before either one inserts the row, but only one can claim that key. The&lt;br&gt;
other transaction rolls back and can retry. On its next attempt, &lt;code&gt;findUnique&lt;/code&gt;&lt;br&gt;
returns the result already stored for the operation.&lt;sup id="fnref3"&gt;3&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Put the two local transactions side by side and the change becomes easier to see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current synchronous flow
Student -&amp;gt; Users: create user
Users -&amp;gt; Users state: save user
Users --&amp;gt; Student: userId
Student -&amp;gt; Student state: save student

Outbox and inbox flow
Student -&amp;gt; Student state: save student + outbox (local transaction)
Outbox sender -&amp;gt; Users: create user [idempotencyKey]
Users -&amp;gt; Users state: save user + inbox result (local transaction)
Users --&amp;gt; Outbox sender: userId
Outbox sender -&amp;gt; Student state: associate userId
Outbox sender -&amp;gt; Users: repeat create user [same idempotencyKey]
Users --&amp;gt; Outbox sender: stored userId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This flow trades immediate agreement for recoverability. Student can commit its&lt;br&gt;
record and outbox entry before Users creates the user, so the relationship may&lt;br&gt;
remain incomplete for a while. The outbox does not decide what the application&lt;br&gt;
should expose during that window; that is a separate product decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idempotency does not replace business rules
&lt;/h2&gt;

&lt;p&gt;The same &lt;code&gt;idempotencyKey&lt;/code&gt; tells Users that this is another attempt at the same&lt;br&gt;
operation. A different key identifies a different operation, even when some fields&lt;br&gt;
in the two requests happen to match.&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;That is all the inbox should decide. It should not compare different requests and&lt;br&gt;
silently merge them because their payloads look similar. Whether two separate&lt;br&gt;
operations are both allowed belongs to domain validation and uniqueness rules, not&lt;br&gt;
to the inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repeated delivery, one business effect
&lt;/h2&gt;

&lt;p&gt;The outbox may send the same operation more than once. For one &lt;code&gt;idempotencyKey&lt;/code&gt;,&lt;br&gt;
Users can recognize the repeat, skip the second user creation, and return the&lt;br&gt;
&lt;code&gt;userId&lt;/code&gt; it saved the first time.&lt;/p&gt;

&lt;p&gt;The delivery still happened more than once. The create-user effect did not. That is&lt;br&gt;
the scoped guarantee here, rather than literal exactly-once delivery.&lt;sup id="fnref5"&gt;5&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;What I wanted from this design was not a magical transaction across two services. I&lt;br&gt;
wanted each service to know what it owned once the easy request path stopped being&lt;br&gt;
easy. Student keeps the work it still needs done. Users keeps the result of the&lt;br&gt;
operation it already processed.&lt;/p&gt;

&lt;p&gt;I first built the direct path as a junior. Later outbox work gave me a better way to&lt;br&gt;
reason about it, so I came back to the same boundary with different questions. That&lt;br&gt;
is a separate article I want to write: how revisiting earlier work has become part&lt;br&gt;
of how I learn.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;AWS Prescriptive Guidance, &lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/transactional-outbox.html" rel="noopener noreferrer"&gt;“Transactional outbox pattern”&lt;/a&gt;; Chris Richardson, Microservices.io, &lt;a href="https://microservices.io/patterns/data/transactional-outbox.html" rel="noopener noreferrer"&gt;“Pattern: Transactional outbox”&lt;/a&gt;.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;IETF, &lt;a href="https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2" rel="noopener noreferrer"&gt;&lt;em&gt;RFC 9110: HTTP Semantics&lt;/em&gt;, section 9.2.2&lt;/a&gt;; Malcolm Featonby, AWS Builders' Library, &lt;a href="https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/" rel="noopener noreferrer"&gt;“Making retries safe with idempotent APIs”&lt;/a&gt;.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Prisma Documentation, &lt;a href="https://www.prisma.io/docs/orm/prisma-client/queries/transactions" rel="noopener noreferrer"&gt;“Transactions and batch queries”&lt;/a&gt;, &lt;a href="https://www.prisma.io/docs/orm/reference/prisma-client-reference" rel="noopener noreferrer"&gt;“Prisma Client API”&lt;/a&gt;, and &lt;a href="https://www.prisma.io/docs/orm/reference/error-reference" rel="noopener noreferrer"&gt;“Error Reference”&lt;/a&gt;.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;Chris Richardson, Microservices.io, &lt;a href="https://microservices.io/patterns/communication-style/idempotent-consumer.html" rel="noopener noreferrer"&gt;“Pattern: Idempotent Consumer”&lt;/a&gt;; Malcolm Featonby, AWS Builders' Library, &lt;a href="https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/" rel="noopener noreferrer"&gt;“Making retries safe with idempotent APIs”&lt;/a&gt;.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;IETF, &lt;a href="https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2" rel="noopener noreferrer"&gt;&lt;em&gt;RFC 9110: HTTP Semantics&lt;/em&gt;, section 9.2.2&lt;/a&gt;; AWS Prescriptive Guidance, &lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/transactional-outbox.html" rel="noopener noreferrer"&gt;“Transactional outbox pattern”&lt;/a&gt;.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>backend</category>
      <category>architecture</category>
      <category>microservices</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How Java's Concurrency APIs Fit Together</title>
      <dc:creator>esteban389</dc:creator>
      <pubDate>Thu, 20 Aug 2026 23:14:16 +0000</pubDate>
      <link>https://dev.to/esteban389/how-javas-concurrency-apis-fit-together-bii</link>
      <guid>https://dev.to/esteban389/how-javas-concurrency-apis-fit-together-bii</guid>
      <description>&lt;p&gt;A concurrency problem can begin with an ordinary requirement: let two independent&lt;br&gt;
operations make progress without forcing one to wait for the other. The requirement&lt;br&gt;
is easy to state. Choosing among &lt;code&gt;Thread&lt;/code&gt;, &lt;code&gt;ExecutorService&lt;/code&gt;, &lt;code&gt;Future&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;CompletableFuture&lt;/code&gt;, locks, atomics, queues, and synchronizers is harder when they&lt;br&gt;
look like competing answers to the same question.&lt;/p&gt;

&lt;p&gt;These APIs answer different questions. Some describe work, some decide how it&lt;br&gt;
runs, some represent results, and others protect shared state or coordinate tasks.&lt;br&gt;
Grouping them by responsibility turns the standard library from a list of names&lt;br&gt;
into a map.&lt;/p&gt;

&lt;p&gt;We will build that map around a small customer-dashboard example, then use shorter&lt;br&gt;
examples for the problems the dashboard does not cover. The examples assume basic&lt;br&gt;
Java, not prior concurrency knowledge. Start with the responsibility the program&lt;br&gt;
needs; choose the class after that.&lt;/p&gt;
&lt;h2&gt;
  
  
  Start with a program that waits twice
&lt;/h2&gt;

&lt;p&gt;Suppose an endpoint builds a customer dashboard from a profile and a list of recent&lt;br&gt;
orders:&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loadProfile&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;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loadOrders&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code fragments below omit imports and surrounding class definitions when those&lt;br&gt;
details do not affect the concurrency mechanism.&lt;/p&gt;

&lt;p&gt;The second call starts after the first one returns. If the operations are independent&lt;br&gt;
and spend most of their time waiting for remote services, that order leaves an&lt;br&gt;
obvious opportunity: start both, then assemble the dashboard when both results are&lt;br&gt;
available.&lt;/p&gt;

&lt;p&gt;That small change already involves three separate responsibilities: describe each&lt;br&gt;
operation, decide how to execute it, and obtain its result. The full map uses seven&lt;br&gt;
questions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Representative APIs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What work should happen?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Runnable&lt;/code&gt;, &lt;code&gt;Callable&amp;lt;V&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where and how should it run?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Thread&lt;/code&gt;, &lt;code&gt;Executor&lt;/code&gt;, &lt;code&gt;ExecutorService&lt;/code&gt;, virtual threads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How do I obtain or combine results?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Future&amp;lt;V&amp;gt;&lt;/code&gt;, &lt;code&gt;CompletableFuture&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How do I protect shared state?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;synchronized&lt;/code&gt;, &lt;code&gt;volatile&lt;/code&gt;, &lt;code&gt;Lock&lt;/code&gt;, atomic variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How do I share data safely?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ConcurrentHashMap&lt;/code&gt;, &lt;code&gt;BlockingQueue&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How do tasks coordinate?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Semaphore&lt;/code&gt;, &lt;code&gt;CountDownLatch&lt;/code&gt;, &lt;code&gt;CyclicBarrier&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How do I divide computation?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ForkJoinPool&lt;/code&gt;, parallel streams&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These groups overlap. &lt;code&gt;CompletableFuture&lt;/code&gt;, for example, represents a result and can&lt;br&gt;
also arrange dependent execution. Treat the groups as questions for locating a&lt;br&gt;
problem rather than rigid boxes for classifying every type.&lt;/p&gt;

&lt;p&gt;On a first pass, focus on tasks, executors, futures, and the shared-state sections.&lt;br&gt;
Learn queues and semaphores as named solutions for handoff and limits. Leave&lt;br&gt;
&lt;code&gt;CyclicBarrier&lt;/code&gt;, fork/join, and continuation-scheduling rules as landmarks until a&lt;br&gt;
program gives you one of those problems.&lt;/p&gt;

&lt;p&gt;One vocabulary distinction will help throughout the map. Concurrent tasks make&lt;br&gt;
progress during overlapping periods; they do not have to execute at the same&lt;br&gt;
instant. Parallel work does execute at the same instant. A single CPU core can&lt;br&gt;
interleave concurrent tasks, while parallel execution requires hardware resources&lt;br&gt;
that can run work simultaneously. We will use concurrency for the waiting-heavy&lt;br&gt;
dashboard and reserve parallel computation for a separate data-processing example.&lt;/p&gt;
&lt;h2&gt;
  
  
  Tasks describe work
&lt;/h2&gt;

&lt;p&gt;A task describes work. A thread is one possible execution mechanism.&lt;/p&gt;

&lt;p&gt;Java's basic task interfaces make that separation visible. &lt;code&gt;Runnable&lt;/code&gt; represents&lt;br&gt;
an operation with no result,&lt;sup id="fnref1"&gt;1&lt;/sup&gt; while &lt;code&gt;Callable&amp;lt;V&amp;gt;&lt;/code&gt; returns a value and&lt;br&gt;
may throw an exception.&lt;sup id="fnref2"&gt;2&lt;/sup&gt; Neither interface chooses the thread that&lt;br&gt;
will run it. Their contracts only describe the operation.&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;Runnable&lt;/span&gt; &lt;span class="n"&gt;refreshCache&lt;/span&gt; &lt;span class="o"&gt;=&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;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;refresh&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;Callable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;loadProfile&lt;/span&gt; &lt;span class="o"&gt;=&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;profileClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchProfile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating either value does not start the work. A caller could invoke &lt;code&gt;run()&lt;/code&gt; or&lt;br&gt;
&lt;code&gt;call()&lt;/code&gt; directly, or it could hand the task to an executor. That later choice&lt;br&gt;
determines the execution policy.&lt;/p&gt;

&lt;p&gt;The code that describes a cache refresh stays unchanged whether the application&lt;br&gt;
runs it immediately, schedules it in a pool, or starts a virtual thread for it.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;Thread&lt;/code&gt; directly when the program intentionally owns one thread's identity or&lt;br&gt;
lifecycle, such as naming it, installing its uncaught-exception handler, or joining&lt;br&gt;
that specific thread. An executor is the better fit when thread creation,&lt;br&gt;
scheduling, and lifecycle belong to an execution policy rather than the task&lt;br&gt;
itself.&lt;sup id="fnref3"&gt;3&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Executors decide how work runs
&lt;/h2&gt;

&lt;p&gt;An &lt;code&gt;Executor&lt;/code&gt; receives a &lt;code&gt;Runnable&lt;/code&gt; and applies an execution policy. Its interface&lt;br&gt;
separates task submission from details such as thread creation, reuse, and&lt;br&gt;
scheduling. The &lt;code&gt;Executor&lt;/code&gt; contract does not promise asynchronous execution: a&lt;br&gt;
minimal executor is allowed to call &lt;code&gt;command.run()&lt;/code&gt; in the submitting thread, while&lt;br&gt;
other implementations create threads or reuse them from a pool.&lt;sup id="fnref4"&gt;4&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ExecutorService&lt;/code&gt; adds lifecycle operations and methods such as &lt;code&gt;submit&lt;/code&gt;, which&lt;br&gt;
returns a &lt;code&gt;Future&lt;/code&gt;.&lt;sup id="fnref5"&gt;5&lt;/sup&gt; An application should close or shut down&lt;br&gt;
an executor service when it no longer needs it. In modern Java, the interface is&lt;br&gt;
&lt;code&gt;AutoCloseable&lt;/code&gt;, so a try-with-resources block can own that lifecycle.&lt;/p&gt;

&lt;p&gt;The executable examples target Java 21 or newer because they use virtual threads;&lt;br&gt;
the responsibility map and the older APIs apply more broadly. Here is the dashboard&lt;br&gt;
using one virtual thread per submitted task:&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;Dashboard&lt;/span&gt; &lt;span class="nf"&gt;loadDashboard&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="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;executor&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="nc"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;profile&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;loadProfile&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;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;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;loadOrders&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profile&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;orders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both tasks are submitted before the code waits for either result. Their executions&lt;br&gt;
can therefore overlap when the executor can run them concurrently. Submission&lt;br&gt;
alone is not a guarantee of overlap; the executor owns that policy and may be&lt;br&gt;
constrained by available resources.&lt;/p&gt;

&lt;p&gt;The following order prevents the two dashboard operations from overlapping:&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;profile&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;loadProfile&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="kt"&gt;var&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;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;loadOrders&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first &lt;code&gt;get()&lt;/code&gt; may block before the second line can submit &lt;code&gt;loadOrders&lt;/code&gt;. Keep&lt;br&gt;
the handles first and the waits after both submissions when the operations are&lt;br&gt;
independent.&lt;/p&gt;

&lt;p&gt;Virtual threads became a final feature in Java 21. They are &lt;code&gt;Thread&lt;/code&gt; instances&lt;br&gt;
scheduled by the JDK rather than permanent one-to-one wrappers around operating&lt;br&gt;
system threads. They suit thread-per-task code with many concurrent operations that&lt;br&gt;
often wait, which describes calls to remote services. They do not make CPU-bound&lt;br&gt;
code run faster or make timing-dependent access to shared mutable state safe. JEP&lt;br&gt;
444 also advises against pooling virtual threads.&lt;sup id="fnref6"&gt;6&lt;/sup&gt; Create one per task; use&lt;br&gt;
a separate mechanism when a scarce resource needs a concurrency limit.&lt;/p&gt;
&lt;h2&gt;
  
  
  Results can be waited for or composed
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;Future&amp;lt;V&amp;gt;&lt;/code&gt; is a handle to a result that may not exist yet. &lt;code&gt;get()&lt;/code&gt; waits when&lt;br&gt;
necessary and then returns the value or reports the computation's failure. A&lt;br&gt;
&lt;code&gt;Future&lt;/code&gt; also exposes completion status and cancellation. Under the &lt;code&gt;Future&lt;/code&gt;&lt;br&gt;
contract, &lt;code&gt;cancel(...)&lt;/code&gt; attempts cancellation; already-running work may continue,&lt;br&gt;
depending on timing and whether the task responds to interruption.&lt;sup id="fnref7"&gt;7&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The dashboard example uses two plain futures because its control flow is short:&lt;br&gt;
submit two operations, wait for both, and build one value. The blocking &lt;code&gt;get()&lt;/code&gt;&lt;br&gt;
calls do not erase the earlier concurrency because both submissions already&lt;br&gt;
happened.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CompletableFuture&amp;lt;T&amp;gt;&lt;/code&gt; becomes useful when later work should depend on earlier&lt;br&gt;
results. It implements both &lt;code&gt;Future&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;CompletionStage&amp;lt;T&amp;gt;&lt;/code&gt;, which adds&lt;br&gt;
operations for transforming and combining completed stages.&lt;/p&gt;

&lt;p&gt;Start with one result and one transformation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;loadProfile&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="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApply&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;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Customer: "&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After &lt;code&gt;profile&lt;/code&gt; completes normally, &lt;code&gt;thenApply&lt;/code&gt; passes its result to the function&lt;br&gt;
and produces another stage containing the label. No &lt;code&gt;get()&lt;/code&gt; separates the two&lt;br&gt;
steps.&lt;sup id="fnref8"&gt;8&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;If we translated the earlier two-input dashboard directly, &lt;code&gt;CompletableFuture&lt;/code&gt;&lt;br&gt;
would mostly look like a syntax swap around the same fixed fan-out. Add one real&lt;br&gt;
dependency instead: recommendations can start only after the profile is available,&lt;br&gt;
while orders can still load independently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;profile + orders ----------&amp;gt; dashboard -------------\
profile -------------------&amp;gt; recommendations --------+--&amp;gt; personalized dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code mirrors that dependency graph:&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;executor&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="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;loadProfile&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="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;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="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;loadOrders&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="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;recommendations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCompose&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;loadedProfile&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;loadRecommendations&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loadedProfile&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="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dashboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Dashboard:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="k"&gt;new&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;dashboard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;recommendations&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loadedDashboard&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loadedRecommendations&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PersonalizedDashboard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                                    &lt;span class="n"&gt;loadedDashboard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                                    &lt;span class="n"&gt;loadedDashboard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orders&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                                    &lt;span class="n"&gt;loadedRecommendations&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&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 asynchronous suppliers receive the executor explicitly because&lt;br&gt;
&lt;code&gt;CompletableFuture&lt;/code&gt; async methods without one normally use&lt;br&gt;
&lt;code&gt;ForkJoinPool.commonPool()&lt;/code&gt;.&lt;sup id="fnref8"&gt;8&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;profile&lt;/code&gt; and &lt;code&gt;orders&lt;/code&gt; start independently. After &lt;code&gt;profile&lt;/code&gt; completes normally,&lt;br&gt;
&lt;code&gt;thenCompose&lt;/code&gt; invokes the recommendation function and flattens the&lt;br&gt;
&lt;code&gt;CompletableFuture&lt;/code&gt; it returns. The first &lt;code&gt;thenCombine&lt;/code&gt; builds a dashboard after&lt;br&gt;
both independent inputs arrive. The second combines that dashboard with the&lt;br&gt;
recommendations, and &lt;code&gt;join()&lt;/code&gt; waits once at the request boundary.&lt;/p&gt;

&lt;p&gt;Plain &lt;code&gt;Future&lt;/code&gt; and &lt;code&gt;CompletableFuture&lt;/code&gt; overlap, but they encourage different control&lt;br&gt;
flow. Plain &lt;code&gt;Future&lt;/code&gt; remains adequate for a short, fixed set of independent tasks&lt;br&gt;
when the caller can submit them together and wait at one clear boundary. Completion&lt;br&gt;
stages help when one result starts later work or several branches must converge.&lt;br&gt;
The example stops at composition. Production code still needs an explicit policy&lt;br&gt;
for errors, cancellation, timeouts, and executor ownership.&lt;/p&gt;
&lt;h2&gt;
  
  
  Shared state has three separate questions
&lt;/h2&gt;

&lt;p&gt;Choosing an executor does not make shared mutation safe. Imagine adding a counter&lt;br&gt;
that every completed dashboard task increments:&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;volatile&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;completed&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;markCompleted&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;completed&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 &lt;code&gt;volatile&lt;/code&gt; declaration gives reads and writes memory-consistency guarantees,&lt;br&gt;
but &lt;code&gt;completed++&lt;/code&gt; is a compound read-modify-write operation. Two threads can read&lt;br&gt;
the same value and both write the same incremented value, losing one update. The&lt;br&gt;
Java Language Specification separates these memory actions,&lt;sup id="fnref9"&gt;9&lt;/sup&gt;&lt;br&gt;
and the atomic package supplies operations that perform the complete update&lt;br&gt;
atomically.&lt;/p&gt;

&lt;p&gt;Shared-state safety involves three separate questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Atomicity:&lt;/strong&gt; must other threads observe a group of operations as one
indivisible action?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visibility:&lt;/strong&gt; when one thread writes a value, what guarantees that another
thread sees it?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordering:&lt;/strong&gt; what constrains the order in which actions become observable across
threads?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider a one-time handoff in which one thread publishes a dashboard and another&lt;br&gt;
reads it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="n"&gt;publishedDashboard&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;dashboardReady&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;publish&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;publishedDashboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;dashboardReady&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="o"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="nf"&gt;readIfReady&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;dashboardReady&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;publishedDashboard&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dashboard write occurs before the volatile flag write in the publishing&lt;br&gt;
thread. If another thread later reads &lt;code&gt;dashboardReady&lt;/code&gt; as &lt;code&gt;true&lt;/code&gt;, the Java Memory&lt;br&gt;
Model's volatile happens-before rule makes the earlier dashboard write visible to&lt;br&gt;
that reader.&lt;sup id="fnref10"&gt;10&lt;/sup&gt; The flag does not lock either method or make a&lt;br&gt;
compound update atomic.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;synchronized&lt;/code&gt; can provide mutual exclusion for a critical section and a&lt;br&gt;
visibility relationship around the same monitor. When one thread unlocks a&lt;br&gt;
monitor, that action happens-before a later lock of the same monitor, so writes&lt;br&gt;
before the unlock become visible through that synchronization relationship. The&lt;br&gt;
&lt;code&gt;java.util.concurrent&lt;/code&gt; memory-consistency summary also documents similar guarantees&lt;br&gt;
for task submission, successful &lt;code&gt;Future.get()&lt;/code&gt;, concurrent collections, and&lt;br&gt;
synchronizers.&lt;sup id="fnref11"&gt;11&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;volatile&lt;/code&gt; provides visibility and ordering for reads and writes of one field. It&lt;br&gt;
does not provide mutual exclusion around a sequence such as an increment. The&lt;br&gt;
&lt;code&gt;Lock&lt;/code&gt; interfaces provide explicit locking plus options such as interruptible or&lt;br&gt;
timed acquisition and multiple conditions.&lt;sup id="fnref12"&gt;12&lt;/sup&gt; That flexibility comes with&lt;br&gt;
explicit acquire/release code and does not make &lt;code&gt;Lock&lt;/code&gt; an automatic upgrade over&lt;br&gt;
&lt;code&gt;synchronized&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For one independent counter, &lt;code&gt;AtomicInteger&lt;/code&gt; matches the operation directly:&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;AtomicInteger&lt;/span&gt; &lt;span class="n"&gt;completed&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;AtomicInteger&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;Future&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;task&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="nl"&gt;completed:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;incrementAndGet&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;java.util.concurrent.atomic&lt;/code&gt; package provides thread-safe read-modify-write&lt;br&gt;
operations on single variables, including increment and compare-and-set.&lt;sup id="fnref13"&gt;13&lt;/sup&gt;&lt;br&gt;
One atomic variable does not make a multi-value invariant atomic. If a rule spans a&lt;br&gt;
balance and a ledger entry, or requires several objects to change together, a lock&lt;br&gt;
around the invariant or a design that avoids shared mutation may fit better.&lt;/p&gt;
&lt;h2&gt;
  
  
  Concurrent collections protect documented operations
&lt;/h2&gt;

&lt;p&gt;Shared data often needs more structure than one counter. Java supplies concurrent&lt;br&gt;
maps, queues, deques, and other collections with documented safety and consistency&lt;br&gt;
guarantees. That protection applies to their operations. It does not turn any&lt;br&gt;
sequence written by the caller into one atomic action.&lt;/p&gt;

&lt;p&gt;Consider a cache registration backed by a &lt;code&gt;ConcurrentHashMap&lt;/code&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;containsKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loadCustomer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customerId&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;Even with a concurrent map, another thread can change the map between the check and&lt;br&gt;
the &lt;code&gt;put&lt;/code&gt;. &lt;code&gt;ConcurrentMap&lt;/code&gt; supplies compound operations such as &lt;code&gt;putIfAbsent&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;compute&lt;/code&gt;, and &lt;code&gt;merge&lt;/code&gt; for transitions covered by their&lt;br&gt;
contracts:&lt;sup id="fnref14"&gt;14&lt;/sup&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;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;computeIfAbsent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customerId&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;loadCustomer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use one of those operations when its documented semantics match the state change.&lt;br&gt;
An invariant that spans several map entries or external side effects still needs a&lt;br&gt;
larger design. &lt;code&gt;ConcurrentHashMap&lt;/code&gt; documents the guarantees and restrictions of its&lt;br&gt;
&lt;code&gt;computeIfAbsent&lt;/code&gt; implementation.&lt;sup id="fnref15"&gt;15&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BlockingQueue&lt;/code&gt; solves another shared-data problem: handing items from producers to&lt;br&gt;
consumers.&lt;sup id="fnref16"&gt;16&lt;/sup&gt; Its operations let a producer fail immediately,&lt;br&gt;
wait for space, or wait up to a timeout; a consumer has corresponding choices when&lt;br&gt;
the queue is empty. Capacity depends on the implementation. &lt;code&gt;ArrayBlockingQueue&lt;/code&gt; is&lt;br&gt;
bounded, while other implementations may be unbounded or have different handoff&lt;br&gt;
semantics.&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;BlockingQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Job&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jobs&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;ArrayBlockingQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Job&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// waits when this bounded queue is full&lt;/span&gt;
&lt;span class="nc"&gt;Job&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;take&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;        &lt;span class="c1"&gt;// waits when it is empty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The queue owns safe transfer of each element. The &lt;code&gt;Job&lt;/code&gt; object may still need its&lt;br&gt;
own safe design if producers and consumers mutate it after handoff.&lt;/p&gt;
&lt;h2&gt;
  
  
  Coordination describes who may proceed
&lt;/h2&gt;

&lt;p&gt;A two-request dependency limit is a coordination policy. A semaphore represents&lt;br&gt;
that policy with permits:&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;String&lt;/span&gt; &lt;span class="nf"&gt;fetchWithLimit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Semaphore&lt;/span&gt; &lt;span class="n"&gt;permits&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;requestId&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;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;permits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;acquire&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dependency&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;requestId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;permits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;release&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;Constructing &lt;code&gt;new Semaphore(2)&lt;/code&gt; lets at most two successful acquisitions proceed&lt;br&gt;
at once. The &lt;code&gt;finally&lt;/code&gt; block returns the permit when the call completes or fails.&lt;br&gt;
The virtual-thread executor used earlier creates a new virtual thread per task and&lt;br&gt;
does not impose a thread-count bound. JEP 444 recommends keeping that model and&lt;br&gt;
using a semaphore to represent the actual limit on a scarce service.&lt;sup id="fnref6"&gt;6&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Other synchronizers encode other policies. A &lt;code&gt;CountDownLatch&lt;/code&gt; lets tasks wait until&lt;br&gt;
a count reaches zero, which fits a one-time startup gate. A &lt;code&gt;CyclicBarrier&lt;/code&gt;&lt;br&gt;
coordinates a group that must all reach the same phase before continuing. A&lt;br&gt;
&lt;code&gt;BlockingQueue&lt;/code&gt; coordinates through data availability and capacity. The&lt;br&gt;
&lt;code&gt;java.util.concurrent&lt;/code&gt; synchronizer overview groups these APIs by&lt;br&gt;
policy.&lt;sup id="fnref17"&gt;17&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;These policies do not protect every object touched by the participating tasks. The&lt;br&gt;
semaphore limits calls in the example; it says nothing about the thread safety of&lt;br&gt;
&lt;code&gt;dependency&lt;/code&gt; or other shared state. Use a synchronizer when the rule concerns who&lt;br&gt;
may proceed, and analyze shared invariants separately.&lt;/p&gt;
&lt;h2&gt;
  
  
  Parallel computation splits data or work
&lt;/h2&gt;

&lt;p&gt;The dashboard spends time waiting. A sum over a large collection presents a&lt;br&gt;
different problem: divide computation over data and combine the partial results.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ForkJoinPool&lt;/code&gt; is an &lt;code&gt;ExecutorService&lt;/code&gt; built around work-stealing and tasks that can&lt;br&gt;
split into smaller tasks. Its contract does not guarantee compensating threads for&lt;br&gt;
blocked I/O or unmanaged synchronization.&lt;sup id="fnref18"&gt;18&lt;/sup&gt; Do not treat a&lt;br&gt;
fork/join pool as the default executor for many blocking network calls. It is a&lt;br&gt;
better conceptual fit for decomposable computation than for replacing the&lt;br&gt;
waiting-oriented dashboard executor.&lt;/p&gt;

&lt;p&gt;Parallel streams expose data-parallel execution through the stream API:&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="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="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parallelStream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mapToLong&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduction follows the &lt;code&gt;java.util.stream&lt;/code&gt; requirements because the mapping is&lt;br&gt;
stateless, it does not modify the source, and addition is&lt;br&gt;
associative.&lt;sup id="fnref19"&gt;19&lt;/sup&gt; Those properties allow the stream implementation to&lt;br&gt;
partition work and combine partial results safely. Stateful operations,&lt;br&gt;
encounter-order requirements, coordination overhead, small inputs, and the&lt;br&gt;
available processors can change the tradeoff. Calling &lt;code&gt;parallelStream()&lt;/code&gt; does not&lt;br&gt;
promise a speedup.&lt;/p&gt;

&lt;p&gt;Measure a representative workload before choosing parallel execution for&lt;br&gt;
performance. The appropriate comparison includes the real data size, operation&lt;br&gt;
cost, ordering requirements, and environment. A tiny example can prove behavior;&lt;br&gt;
it cannot establish that production code will run faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose the responsibility before the class
&lt;/h2&gt;

&lt;p&gt;Start with the sentence that describes the problem. Let the API name come second.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem statement&lt;/th&gt;
&lt;th&gt;Useful starting point&lt;/th&gt;
&lt;th&gt;Check before committing to it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"I need to represent work with or without a result."&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Runnable&lt;/code&gt;, &lt;code&gt;Callable&amp;lt;V&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Who owns execution and failure handling?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"I need to run independent waiting operations."&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ExecutorService&lt;/code&gt;; often one virtual thread per task in modern Java&lt;/td&gt;
&lt;td&gt;What owns the executor, and what limits scarce dependencies?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"I need to retrieve one result later."&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Future&amp;lt;V&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Where will waiting happen, and what does cancellation really do?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"I need to transform or combine dependent results."&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CompletableFuture&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Which executor and error policy does each stage use?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Several tasks update one counter."&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AtomicInteger&lt;/code&gt; or a lock&lt;/td&gt;
&lt;td&gt;Does the invariant extend beyond that variable?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Several tasks share keyed state."&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ConcurrentHashMap&lt;/code&gt; and its compound operations&lt;/td&gt;
&lt;td&gt;Is the whole state transition covered by one documented operation?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Producers hand work to consumers."&lt;/td&gt;
&lt;td&gt;A suitable &lt;code&gt;BlockingQueue&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Should capacity apply backpressure, and which operations may wait?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Only N tasks may use a dependency."&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Semaphore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Are permits always released, including on failure?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"I need to divide CPU-oriented computation."&lt;/td&gt;
&lt;td&gt;Fork/join or a parallel stream&lt;/td&gt;
&lt;td&gt;Is the work large, independent, non-interfering, and measured?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After choosing the responsibility, evaluate lifecycle, failure policy, workload,&lt;br&gt;
contention, ordering, and resource limits before selecting the concrete API.&lt;/p&gt;

&lt;p&gt;As a practice exercise, return to the dashboard and write five sentences before&lt;br&gt;
changing its code: which operations are independent, what results they produce,&lt;br&gt;
where waiting is acceptable, what state they share, and which dependency limits&lt;br&gt;
must survive higher concurrency. Each answer points to one part of the map and to&lt;br&gt;
the next piece of documentation or testing the program needs.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Runnable.html" rel="noopener noreferrer"&gt;&lt;code&gt;Runnable&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Callable.html" rel="noopener noreferrer"&gt;&lt;code&gt;Callable&amp;lt;V&amp;gt;&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Thread.html" rel="noopener noreferrer"&gt;&lt;code&gt;Thread&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Executor.html" rel="noopener noreferrer"&gt;&lt;code&gt;Executor&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ExecutorService.html" rel="noopener noreferrer"&gt;&lt;code&gt;ExecutorService&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/444" rel="noopener noreferrer"&gt;JEP 444: Virtual Threads&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn7"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Future.html" rel="noopener noreferrer"&gt;&lt;code&gt;Future&amp;lt;V&amp;gt;&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn8"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/CompletableFuture.html" rel="noopener noreferrer"&gt;&lt;code&gt;CompletableFuture&amp;lt;T&amp;gt;&lt;/code&gt; API documentation&lt;/a&gt; and &lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/CompletionStage.html" rel="noopener noreferrer"&gt;&lt;code&gt;CompletionStage&amp;lt;T&amp;gt;&lt;/code&gt; API documentation&lt;/a&gt;. The &lt;code&gt;CompletableFuture&lt;/code&gt; policy section also explains that non-async dependent actions may run in the thread that completes the current stage or another caller of a completion method.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn9"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/javase/specs/jls/se25/html/jls-17.html#jls-17.4.2" rel="noopener noreferrer"&gt;Java Language Specification, §17.4.2: Actions&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn10"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/javase/specs/jls/se25/html/jls-17.html#jls-17.4.5" rel="noopener noreferrer"&gt;Java Language Specification, §17.4.5: Happens-before Order&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn11"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/package-summary.html#MemoryConsistency" rel="noopener noreferrer"&gt;&lt;code&gt;java.util.concurrent&lt;/code&gt; memory-consistency properties&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn12"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/locks/Lock.html" rel="noopener noreferrer"&gt;&lt;code&gt;Lock&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn13"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/atomic/package-summary.html" rel="noopener noreferrer"&gt;&lt;code&gt;java.util.concurrent.atomic&lt;/code&gt; package documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn14"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ConcurrentMap.html" rel="noopener noreferrer"&gt;&lt;code&gt;ConcurrentMap&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn15"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ConcurrentHashMap.html" rel="noopener noreferrer"&gt;&lt;code&gt;ConcurrentHashMap&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn16"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/BlockingQueue.html" rel="noopener noreferrer"&gt;&lt;code&gt;BlockingQueue&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn17"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/package-summary.html#Synchronizers" rel="noopener noreferrer"&gt;&lt;code&gt;java.util.concurrent&lt;/code&gt; synchronizer overview&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn18"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ForkJoinPool.html" rel="noopener noreferrer"&gt;&lt;code&gt;ForkJoinPool&lt;/code&gt; API documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn19"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/package-summary.html" rel="noopener noreferrer"&gt;&lt;code&gt;java.util.stream&lt;/code&gt; package documentation&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>java</category>
      <category>concurrency</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Demystifying Authentication in Spring Security</title>
      <dc:creator>esteban389</dc:creator>
      <pubDate>Wed, 19 Mar 2025 01:53:51 +0000</pubDate>
      <link>https://dev.to/esteban389/demystifying-authentication-in-spring-security-57oj</link>
      <guid>https://dev.to/esteban389/demystifying-authentication-in-spring-security-57oj</guid>
      <description>&lt;p&gt;Authentication is one of the most fundamental features in modern applications—whether you’re logging into a website, accessing an API, or even verifying a one-time password. If you’re working within the Spring ecosystem, you’ve probably heard of Spring Security, the go-to framework for handling authentication and security.&lt;/p&gt;

&lt;p&gt;But let’s be honest… Spring Security can feel overwhelming! 🌀 Between authentication providers, user details, and authentication managers, it’s easy to get lost. If you've ever found yourself wondering "Where does my password even get checked?"—you're not alone!&lt;/p&gt;

&lt;p&gt;In this article, I’ll break down authentication in Spring Security into simple, easy-to-follow steps. We’ll compare a basic authentication flow (like checking a username and password) with how Spring Security handles each step under the hood. By the end, you'll have a clear understanding of what’s happening behind the scenes. 🚀​&lt;/p&gt;

&lt;p&gt;Let’s dive in! 🔍​&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Basic Authentication
&lt;/h2&gt;

&lt;p&gt;Before we jump into how Spring Security handles authentication, let’s talk about why we need authentication in the first place. In most applications, you want to control access to certain features or data. That means you need a way to confirm that users are who they say they are. That’s exactly what authentication does!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In a computer system, authentication (“auth” for short) is the process that verifies that a user is who they claim to be.  &lt;a href="https://www.ibm.com/think/topics/authentication" rel="noopener noreferrer"&gt;IBM What is Authentication?&lt;/a&gt; | IBM​&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Although web applications can be quite different from each other, the authentication flow is often very similar. A single, generalized flow might cover the vast majority of use cases. Here’s a diagram of a common authentication flow:&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%2Fcgalqfpkhz1esducey85.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%2Fcgalqfpkhz1esducey85.png" alt="Common authentication flow diagram" width="800" height="1198"&gt;&lt;/a&gt;&lt;br&gt;
Let’s break it down step by step. 🏃‍♂️💨​&lt;/p&gt;
&lt;h3&gt;
  
  
  Visiting the server
&lt;/h3&gt;

&lt;p&gt;It all starts when a user visits your site or makes an initial request to your server. In some cases, the server may include a CSRF token in its response, depending on your security needs (these are steps 1 and 1.1 in the diagram).&lt;/p&gt;

&lt;p&gt;Think of the CSRF token as a little “secret handshake” 🤝 that helps protect against certain security attacks.&lt;/p&gt;
&lt;h3&gt;
  
  
  Request an Authenticated Resource
&lt;/h3&gt;

&lt;p&gt;Next, the user attempts to access a resource that requires authentication—for example, a page or an API endpoint that only logged-in users should see. The server then responds with a prompt for credentials, asking the user to prove they’re really who they claim to be.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Commonly, these credentials are:&lt;/li&gt;
&lt;li&gt;Username and password&lt;/li&gt;
&lt;li&gt;Email (for sending a magic link)&lt;/li&gt;
&lt;li&gt;WebAuthn credentials (hardware security keys, etc.)&lt;/li&gt;
&lt;li&gt;Or any other unique proof of identity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is all covered in steps 2 to 4 in the diagram. 🛂​&lt;/p&gt;
&lt;h3&gt;
  
  
  Search user
&lt;/h3&gt;

&lt;p&gt;When the user’s credentials arrive at the server, the next step is to look them up in the database (or another storage system).&lt;br&gt;
If the user doesn’t exist, the server immediately returns an error (steps 5 to 7.1).&lt;/p&gt;

&lt;p&gt;If the user is found, we move on to the final phase: checking the validity of their credentials.&lt;/p&gt;
&lt;h3&gt;
  
  
  Authenticate
&lt;/h3&gt;

&lt;p&gt;At this point, the server validates the credentials. The exact process depends on your chosen authentication method:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Username &amp;amp; Password: The server will hash the incoming password and compare it with the hashed password stored in the database.&lt;/li&gt;
&lt;li&gt;Magic Link: The server checks if the link’s token is valid and hasn’t expired.&lt;/li&gt;
&lt;li&gt;WebAuthn: The server verifies the security challenge with the user’s device or browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the credentials are valid, the server returns a success response along with some identifier—often a session cookie or a token (like a JWT)—so the user doesn’t have to log in again on every request. This corresponds to steps 7.2 and 8 in the diagram.&lt;/p&gt;

&lt;p&gt;Think of this identifier as your “I’m logged in” badge. 🏷️​&lt;/p&gt;

&lt;p&gt;Now that you understand the core concepts, we’ll see how Spring Security manages each of these steps under the hood. Buckle up! 🚀&lt;/p&gt;
&lt;h3&gt;
  
  
  Mapping Authentication Steps to Spring Security Components
&lt;/h3&gt;

&lt;p&gt;Now that we understand a typical authentication flow, let’s see how Spring Security tackles each step. Before diving in, let’s clear up one thing: if you've tried learning Spring Security before, you might have heard about a lot of additional concepts like CORS, the security filter chain, and more. But for this article, we’re keeping our focus solely on authentication. I’ll be showing you how Spring Security handles authentication in a REST API style. (I’ve personally never used Spring as a full-stack framework, so this approach suits my experience—but don’t worry, the concepts translate easily if you need a full-stack solution!)&lt;/p&gt;

&lt;p&gt;Here’s an overall view mapping a standard authentication flow to Spring Security components:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Authentication Flow&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Spring Security Component&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;User submits credentials&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Authentication&lt;/code&gt; (e.g., &lt;code&gt;UsernamePasswordAuthenticationToken&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server searches for user&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UserDetailsService&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check if user exists&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UsernameNotFoundException&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify credentials&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AuthenticationProvider&lt;/code&gt; (e.g., &lt;code&gt;DaoAuthenticationProvider&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication success/failure&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AuthenticationManager&lt;/code&gt; orchestrates this&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Return authentication identifier&lt;/td&gt;
&lt;td&gt;Typically handled by a session or token mechanism&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is a high-level overview of how authentication works within Spring Security. I’ve intentionally skipped some details that we’ll dig into as we break down each part further. Let’s dive in!&lt;/p&gt;
&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;p&gt;Every time a user accesses a protected resource, they must prove their identity using credentials. This is where the &lt;code&gt;Authentication&lt;/code&gt; interface comes into play. According to the Spring docs, it “represents the token for an authentication request or for an authenticated principal once the request has been processed by the &lt;code&gt;AuthenticationManager.authenticate(Authentication)&lt;/code&gt; method.”&lt;br&gt;
The &lt;code&gt;Authentication&lt;/code&gt; object contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Credentials (e.g., a password)&lt;/li&gt;
&lt;li&gt;Permissions/Authorities&lt;/li&gt;
&lt;li&gt;Principal (a representation of the authenticated user)&lt;/li&gt;
&lt;li&gt;Authentication status (authenticated or not)&lt;/li&gt;
&lt;li&gt;And other details regarding the authentication request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common implementation that you’ll likely use in many projects is the &lt;code&gt;UsernamePasswordAuthenticationToken&lt;/code&gt;. Other examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OneTimeTokenAuthenticationToken&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AnonymousAuthenticationToken&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JwtAuthenticationToken&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BearerTokenAuthenticationToken&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many more out there, or you can roll your own (though I recommend doing so only for learning purposes) 😊.&lt;/p&gt;
&lt;h3&gt;
  
  
  UserDetailsService
&lt;/h3&gt;

&lt;p&gt;If you’ve spent any time with Spring and the MVC pattern, you’ve likely encountered the concept of services. These act as a bridge between your business logic and your database interactions. In Spring Security, the &lt;code&gt;UserDetailsService&lt;/code&gt; is your go-to for retrieving user data.&lt;/p&gt;

&lt;p&gt;The interface defines a single method: &lt;code&gt;loadUserByUsername(String username)&lt;/code&gt;. This method’s job is to:&lt;/p&gt;
&lt;h3&gt;
  
  
  Locate the user based on the provided username.
&lt;/h3&gt;

&lt;p&gt;Return a &lt;code&gt;UserDetails&lt;/code&gt; object representation of the user that focuses on authentication and authorization data.&lt;/p&gt;

&lt;p&gt;Remember, your user entity can still have other attributes and extend different classes; the &lt;code&gt;UserDetails&lt;/code&gt; interface just provides a focused view for security. You could technically bypass using &lt;code&gt;UserDetailsService&lt;/code&gt; or &lt;code&gt;UserDetails&lt;/code&gt; if you implement a custom authentication provider, but then you’d be fighting the framework’s conventions.&lt;/p&gt;

&lt;p&gt;Spring even offers some default implementations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;InMemoryUserDetailsManager&lt;/code&gt; (great for prototyping, since it stores data only in memory)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JdbcDaoImpl&lt;/code&gt; (retrieves user details from a database using JDBC queries)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JdbcUserDetailsManager&lt;/code&gt; (an enhanced version of JdbcDaoImpl with additional features) &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  UsernameNotFoundException
&lt;/h3&gt;

&lt;p&gt;When the &lt;code&gt;UserDetailsService&lt;/code&gt; can’t find a user, it throws a &lt;code&gt;UsernameNotFoundException&lt;/code&gt;. This exception is a subclass of &lt;code&gt;AuthenticationException&lt;/code&gt;, the base class for all exceptions related to failed authentication attempts. Other exceptions in this family include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BadCredentialsException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AuthenticationCredentialsNotFoundException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CompromisedPasswordException&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These exceptions help Spring Security signal what went wrong during the authentication process ⚠️.&lt;/p&gt;
&lt;h3&gt;
  
  
  AuthenticationManager and AuthenticationProvider
&lt;/h3&gt;

&lt;p&gt;Now we’re at the stage where we verify that the credentials are correct 🧐. This is handled by the &lt;code&gt;AuthenticationManager&lt;/code&gt;, which processes an &lt;code&gt;Authentication&lt;/code&gt; object (remember, the representation of your user’s credentials, whether authenticated or not).&lt;/p&gt;

&lt;p&gt;The most common implementation of &lt;code&gt;AuthenticationManager&lt;/code&gt; is the &lt;code&gt;ProviderManager&lt;/code&gt;. This manager maintains a list of &lt;code&gt;AuthenticationProvider&lt;/code&gt; instances and iterates over them until one can successfully handle the authentication request. Here’s a simplified snippet to illustrate this:&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="nc"&gt;Authentication&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;authentication&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;AuthenticationException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Authentication&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;toTest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;authentication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClass&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;AuthenticationException&lt;/span&gt; &lt;span class="n"&gt;lastException&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="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;result&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="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AuthenticationProvider&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;getProviders&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;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supports&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toTest&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&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="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authenticate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authentication&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;result&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="n"&gt;copyDetails&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authentication&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="k"&gt;break&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;Notice how the ProviderManager checks each provider to see if it supports the type of authentication being attempted. It stops once it finds one that successfully authenticates the request ✅.&lt;/p&gt;

&lt;p&gt;The AuthenticationProvider interface itself defines just two methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;supports(Class&amp;lt;?&amp;gt; authentication)&lt;/code&gt;: Checks if the provider can handle the given authentication type.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;authenticate(Authentication authentication)&lt;/code&gt;: Contains the logic for verifying the credentials.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spring Security provides several implementations, like &lt;code&gt;DaoAuthenticationProvider&lt;/code&gt; for username/password checks or &lt;code&gt;JwtAuthenticationProvider&lt;/code&gt; for JWT-based authentication. For example, a snippet from the JwtAuthenticationProvider might look like this:&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;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;authentication&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;AuthenticationException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;BearerTokenAuthenticationToken&lt;/span&gt; &lt;span class="n"&gt;bearer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BearerTokenAuthenticationToken&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;authentication&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;Jwt&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getJwt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bearer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;AbstractAuthenticationToken&lt;/span&gt; &lt;span class="n"&gt;token&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;jwtAuthenticationConverter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;convert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwt&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;token&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDetails&lt;/span&gt;&lt;span class="o"&gt;()&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="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDetails&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bearer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDetails&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;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authenticated token"&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;token&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;supports&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;authentication&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="nc"&gt;BearerTokenAuthenticationToken&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="na"&gt;isAssignableFrom&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authentication&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the provider casts the &lt;code&gt;Authentication&lt;/code&gt; object to the expected type, processes the JWT, and converts it back to an authenticated token. If a provider returns null, the &lt;code&gt;ProviderManager&lt;/code&gt; moves on to the next one. This mechanism ensures that your application finds the right way to authenticate each request 🔍.&lt;/p&gt;

&lt;h3&gt;
  
  
  Returning a response
&lt;/h3&gt;

&lt;p&gt;At the end of the authentication process, your application needs to return a response. If you’re building your own implementation, this could mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting a cookie in a cookie-based authentication.&lt;/li&gt;
&lt;li&gt;Returning a JWT token for stateless APIs.&lt;/li&gt;
&lt;li&gt;Or any other mechanism you choose.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a quick example, you might create an AuthController with a login endpoint that accepts a record like this:&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="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;LoginRequest&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;username&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;passsword&lt;/span&gt;&lt;span class="o"&gt;){}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;​&lt;/p&gt;

&lt;p&gt;This controller would create a &lt;code&gt;UsernamePasswordAuthenticationToken&lt;/code&gt;, trigger the authentication process, and then return a response containing either a cookie or a token based on the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diving Deeper: Exploring Spring Security’s Built-In Login Mechanism
&lt;/h2&gt;

&lt;p&gt;So far, we’ve covered the essentials, and you could build your own authentication flow with these pieces. But if you’re curious about the “Spring way” of doing things, here’s a sneak peek into how Spring handles login by default.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: If this next section feels a bit heavy or introduces additional concepts you’re not yet comfortable with, feel free to skip ahead and come back later. Understanding these concepts—even at a high level—will help you grasp how Spring Security works under the hood.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  How Does Spring Security Handle Login?
&lt;/h3&gt;

&lt;p&gt;Spring Security provides a default login mechanism, but how does it actually work?&lt;/p&gt;

&lt;p&gt;When a user submits their credentials, the request is sent to the configured login endpoint.&lt;/p&gt;

&lt;p&gt;Spring Security intercepts this request using a filter, specifically &lt;code&gt;UsernamePasswordAuthenticationFilter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The filter attempts authentication, following the flow we discussed earlier. If authentication succeeds, Spring Security stores the &lt;code&gt;Authentication&lt;/code&gt; object in the &lt;code&gt;SecurityContextHolder&lt;/code&gt;. Before responding to the client, the &lt;code&gt;SecurityContext&lt;/code&gt;is persisted via a &lt;code&gt;SecurityContextRepository&lt;/code&gt;. This sequence allows Spring Security to maintain authentication across multiple requests.&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%2Ftkgpv6rpa5gepvjpcbxj.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%2Ftkgpv6rpa5gepvjpcbxj.png" alt="WoW" width="491" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;WOW that was a lot of info and new concepts in such a short amount of time right?  Let’s, once again, define what we need and how those needs are solved by different components of spring.&lt;br&gt;
First things first,&lt;/p&gt;
&lt;h3&gt;
  
  
  WHAT THE F*CK IS A FILTER?
&lt;/h3&gt;

&lt;p&gt;Spring Security relies on a Security Filter Chain, a series of filters that process requests and responses. These filters handle security tasks such as authentication, authorization, and CSRF protection.&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%2F822rnemv0geujebgj54z.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%2F822rnemv0geujebgj54z.png" alt="Filter chain illustration" width="320" height="462"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.spring.io/spring-security/reference/servlet/architecture.html" rel="noopener noreferrer"&gt;Architecture::Spring Security &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a client makes an HTTP request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The request passes through multiple security filters.&lt;/li&gt;
&lt;li&gt;The request is authenticated and authorized.&lt;/li&gt;
&lt;li&gt;If allowed, it reaches the servlet for further processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spring Boot automatically configures these filters, but you can inspect them with the following example:&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;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;UserDetailsService&lt;/span&gt; &lt;span class="nf"&gt;inMemoryUserDetails&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;UserDetails&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{noop}admin"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ADMIN"&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InMemoryUserDetailsManager&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SecurityFilterChain&lt;/span&gt; &lt;span class="nf"&gt;securityFilterChain&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpSecurity&lt;/span&gt; &lt;span class="n"&gt;http&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="n"&gt;http&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizeHttpRequests&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorizeHttp&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;authorizeHttp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requestMatchers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;permitAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                    &lt;span class="n"&gt;authorizeHttp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;anyRequest&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;authenticated&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="na"&gt;formLogin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;withDefaults&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;http&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates an in-memory admin user.&lt;/li&gt;
&lt;li&gt;Enables default login behavior.&lt;/li&gt;
&lt;li&gt;Allows access to /login while protecting other endpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exploring the Security Filter Chain
&lt;/h3&gt;

&lt;p&gt;Spring Security manages filters using a Filter Chain Proxy, which contains one or more Security Filter Chains. The Security Filter Chain is Spring-specific and integrates deeply with the Spring framework, unlike the standard Servlet Filter Chain.&lt;br&gt;
You can inspect the active Security Filter Chains using this 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;@GetMapping&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getSecurityFilterChainProxy&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;filterChains&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="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;1&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="nc"&gt;SecurityFilterChain&lt;/span&gt; &lt;span class="n"&gt;securityFilterChain&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;filterChainProxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFilterChains&lt;/span&gt;&lt;span class="o"&gt;()){&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;filterChain&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&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="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Filter&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;securityFilterChain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFilters&lt;/span&gt;&lt;span class="o"&gt;()){&lt;/span&gt;
                &lt;span class="n"&gt;filterChain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClass&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;filterChains&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filterChain&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;filterChains&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;br&gt;
Do you remember how i explained the filters work? Well, I kinda lied, spring security actually uses a filter chain proxy to have the filters defined in the Security Filter Chain, which is different from the Filter Chain, while the former is a Spring Thingy and can then take advantage of other spring features like the ApplicationContext, and is actually the one you’ll be using 99.99% of the time, the later is a Servlet thing, the Security Filter Chain is called inside the Filter Chain, you don’t really have to worry too much about those details but if you do want to go deper you can read the spring security documentation on the Servlet Applicatoins / Architecture section&lt;br&gt;
What this endpoint i showed you does is it will get the Security Filter Chains that are registerd in the Filter Chain Proxy (the one that spring wires inside the Servlet Filter Chain) and return the class names of the Filters inside the Security Filter Chain, you will get a response like this&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;"1"&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;"1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.session.DisableEncodeUrlFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.context.SecurityContextHolderFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.header.HeaderWriterFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"5"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.csrf.CsrfFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"6"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.authentication.logout.LogoutFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"7"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"8"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.authentication.ui.DefaultResourcesFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"9"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"10"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"11"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.savedrequest.RequestCacheAwareFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"12"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"13"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.authentication.AnonymousAuthenticationFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"14"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.access.ExceptionTranslationFilter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"15"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.security.web.access.intercept.AuthorizationFilter"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;​&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Filters in Spring Security
&lt;/h3&gt;

&lt;p&gt;I’m not gonna explain every single filter but instead let’s go with the ones we care those being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;SecurityContextHolderFilter&lt;/code&gt;&lt;br&gt;
Retrieves the SecurityContext for requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CsrfFilter&lt;/code&gt;&lt;br&gt;
Ensures CSRF tokens are included in requests (if enabled).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;LogoutFilter&lt;/code&gt;&lt;br&gt;
Manages user logout by calling LogoutHandlers and redirecting upon success.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;UsernamePasswordAuthenticationFilter&lt;/code&gt;&lt;br&gt;
Handles login requests, extracting credentials and passing them to authentication mechanisms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DefaultLoginPageGeneratingFilter&lt;/code&gt;&lt;br&gt;
Generates the default login page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DefaultLogoutPageGeneratingFilter&lt;/code&gt;&lt;br&gt;
Creates the default logout page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;AnonymousAuthenticationFilter&lt;/code&gt;&lt;br&gt;
Assigns anonymous authentication when no user is authenticated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ExceptionTranslationFilter&lt;/code&gt;&lt;br&gt;
Converts AccessDeniedException and AuthenticationException into HTTP responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;AuthorizationFilter&lt;/code&gt;&lt;br&gt;
Enforces authorization policies.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Configuring the Security Filter Chain
&lt;/h3&gt;

&lt;p&gt;Below is an example of configuring key security filters:&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;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SecurityFilterChain&lt;/span&gt; &lt;span class="nf"&gt;securityFilterChain&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpSecurity&lt;/span&gt; &lt;span class="n"&gt;http&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="n"&gt;http&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;securityContextConfigurer&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                        &lt;span class="n"&gt;securityContextConfigurer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;securityContextRepository&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;MyCustonSecurityContextRepository&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="na"&gt;csrf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csrfConfigurer&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;csrfConfigurer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disable&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logoutConfigurer&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;logoutConfigurer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logoutUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/logout"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="n"&gt;logoutConfigurer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invalidateHttpSession&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="o"&gt;})&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formLogin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loginConfigurer&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;loginConfigurer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loginPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                            &lt;span class="n"&gt;loginConfigurer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;failureForwardUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/login?error"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                            &lt;span class="n"&gt;loginConfigurer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;usernameParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"username"&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="na"&gt;anonymous&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anonymousConfigurer&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;anonymousConfigurer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;principal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&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="na"&gt;exceptionHandling&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exceptionHandlingConfigurer&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;exceptionHandlingConfigurer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accessDeniedPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/access-denied"&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="na"&gt;authorizeHttpRequests&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorizeHttp&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;authorizeHttp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requestMatchers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;permitAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                    &lt;span class="n"&gt;authorizeHttp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;anyRequest&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;authenticated&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;http&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defines a custom SecurityContextRepository.&lt;/li&gt;
&lt;li&gt;Disables CSRF (if needed).&lt;/li&gt;
&lt;li&gt;Customizes login/logout behavior.&lt;/li&gt;
&lt;li&gt;Handles anonymous users and access denial.&lt;/li&gt;
&lt;li&gt;Enforces authentication for all routes except /login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is all good and great but let’s go a little deeper into how the spring team normally implements authentication inside filters, for this we dive into the implementation of the &lt;code&gt;UsernamePasswordAuthenticationFilter&lt;/code&gt;, &lt;code&gt;LogoutFilter&lt;/code&gt;, &lt;code&gt;AnonymousFilter&lt;/code&gt;, &lt;code&gt;SecurityContextHolderFilter&lt;/code&gt; and lastly &lt;code&gt;SecurityContextRepository&lt;/code&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  SecurityContextHolderFilter
&lt;/h3&gt;

&lt;p&gt;Ensures that the SecurityContext is correctly set before proceeding with request handling. Runs early in the filter chain and guarantees that any downstream filters can access security details.&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;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;FilterChain&lt;/span&gt; &lt;span class="n"&gt;chain&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;ServletException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;IOException&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;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FILTER_APPLIED&lt;/span&gt;&lt;span class="o"&gt;)&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="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="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="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FILTER_APPLIED&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TRUE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SecurityContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;deferredContext&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;securityContextRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadDeferredContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;securityContextHolderStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDeferredContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deferredContext&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;finally&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;securityContextHolderStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clearContext&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FILTER_APPLIED&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;In the implementation you can see that it will check whether the filter has already been applied, if it hasn’t it will pass the method to load the context to the SecurityContextHolder and continue with the next filter.&lt;/p&gt;

&lt;h3&gt;
  
  
  SecurityContextRepository
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Restores and retrieves the SecurityContext during request processing.&lt;/li&gt;
&lt;li&gt;Works with session-based authentication to persist the SecurityContext between requests.&lt;/li&gt;
&lt;li&gt;Common implementations:

&lt;ul&gt;
&lt;li&gt;HttpSessionSecurityContextRepository: Stores the SecurityContext in the HTTP session.&lt;/li&gt;
&lt;li&gt;RequestAttributeSecurityContextRepository: Stores the SecurityContext in request attributes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  AnonymousFilter
&lt;/h3&gt;

&lt;p&gt;Assigns an anonymous Authentication object when no authenticated user is present. It ensures that unauthenticated users still have a valid SecurityContext. The anonymous authentication has a special role (ROLE_ANONYMOUS), allowing fine-grained access control.&lt;/p&gt;

&lt;p&gt;Let’s look at a small part of the filter’s implementation&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;private&lt;/span&gt; &lt;span class="nc"&gt;SecurityContext&lt;/span&gt; &lt;span class="nf"&gt;defaultWithAnonymous&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SecurityContext&lt;/span&gt; &lt;span class="n"&gt;currentContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;currentAuthentication&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAuthentication&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;currentAuthentication&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="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;anonymous&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;createAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isTraceEnabled&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;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogMessage&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Set SecurityContextHolder to "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;anonymous&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&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;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Set SecurityContextHolder to anonymous SecurityContext"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;SecurityContext&lt;/span&gt; &lt;span class="n"&gt;anonymousContext&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;securityContextHolderStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createEmptyContext&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;anonymousContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anonymous&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;anonymousContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isTraceEnabled&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;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogMessage&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Did not set SecurityContextHolder since already authenticated "&lt;/span&gt;
                    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;currentAuthentication&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="n"&gt;currentContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="nf"&gt;createAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;AnonymousAuthenticationToken&lt;/span&gt; &lt;span class="n"&gt;token&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;AnonymousAuthenticationToken&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;key&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;principal&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;authorities&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDetails&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;authenticationDetailsSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buildDetails&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&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;token&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This two methods are the ones we actually care about for the purposes of this article, the defeaultWithAnonymous method will get the current authentication and check if it’s null, if it isn’t it logs that it wasn’t necessary to set the &lt;code&gt;SecurityContextHolder&lt;/code&gt;, if it is, it creates an &lt;code&gt;AnonymousAuthenticationToken&lt;/code&gt; and then an empty context and sets the authentication in it, finally it returns the &lt;code&gt;SecurityContext&lt;/code&gt;, the anonymous token will use a key, a principal as a String (which you can configure as you saw in the example) and the details, the details willfrom the http request and those will be the ip address and the session id&lt;/p&gt;

&lt;h3&gt;
  
  
  UsernamePasswordAuthenticationFilter
&lt;/h3&gt;

&lt;p&gt;This filter a little bit special, normally when you want to create a filter to add to the spring security filter chain you would extend your class with either &lt;code&gt;GenericFilterBean&lt;/code&gt;or &lt;code&gt;OncePerRequestFilter&lt;/code&gt; but the filters that deal with broswer based http based authentications such as this filter or &lt;code&gt;Oauth2LoginAuthenticationFilter&lt;/code&gt;, &lt;code&gt;WebAuthnAuthenticationFilter&lt;/code&gt;, etc…, they extend a different class instead, the &lt;code&gt;AbstractAuthenticationProcessingFilter&lt;/code&gt; this filter will require an &lt;code&gt;AuthenticationManager&lt;/code&gt; to process the authentication request and a &lt;code&gt;RequestMatcher&lt;/code&gt; to check if it should attempt authentication for the current request, it has three important methods the &lt;code&gt;attemptAuthentication&lt;/code&gt; which will receive both the request and response objects and will perform the actual authentication, if the authentication passess the &lt;code&gt;Authentication&lt;/code&gt; result will be placed into the &lt;code&gt;SecurityContext&lt;/code&gt; and it will call a configured &lt;code&gt;AuthenticationSuccessHandler&lt;/code&gt; and if it fails it will delegate to a configured &lt;code&gt;AuthenticationFailurehandler&lt;/code&gt; &lt;br&gt;
From the actual implementation of the &lt;code&gt;UsernamePasswordAuthenticationFilter&lt;/code&gt; we see relatively how simple this is&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;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="nf"&gt;attemptAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&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;AuthenticationException&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;postOnly&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMethod&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POST"&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AuthenticationServiceException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authentication method not supported: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMethod&lt;/span&gt;&lt;span class="o"&gt;());&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;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obtainUsername&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&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="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&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;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obtainPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&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="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;UsernamePasswordAuthenticationToken&lt;/span&gt; &lt;span class="n"&gt;authRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UsernamePasswordAuthenticationToken&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unauthenticated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Allow subclasses to set the "details" property&lt;/span&gt;
        &lt;span class="n"&gt;setDetails&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authRequest&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAuthenticationManager&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;authenticate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authRequest&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;It first checks if it must be a post request and then it obtains both the username and password, it creates an Authentication with the details from the request and lastly it passes this &lt;code&gt;Authentication&lt;/code&gt; to the &lt;code&gt;AuthenticationManager&lt;/code&gt; &lt;br&gt;
now let’s see how this is used in the &lt;code&gt;AbstractAuthenticationProcessingFilter&lt;/code&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="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;FilterChain&lt;/span&gt; &lt;span class="n"&gt;chain&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;IOException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ServletException&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requiresAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;Authentication&lt;/span&gt; &lt;span class="n"&gt;authenticationResult&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;attemptAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authenticationResult&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="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;sessionStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authenticationResult&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if&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;continueChainBeforeSuccessfulAuthentication&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="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;successfulAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authenticationResult&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;InternalAuthenticationServiceException&lt;/span&gt; &lt;span class="n"&gt;failed&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;logger&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;"An internal error occurred while trying to authenticate the user."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;failed&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;unsuccessfulAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;failed&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;AuthenticationException&lt;/span&gt; &lt;span class="n"&gt;ex&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;unsuccessfulAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&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="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;requiresAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requiresAuthenticationRequestMatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&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="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isTraceEnabled&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;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Did not match request to %s"&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;requiresAuthenticationRequestMatcher&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="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;​&lt;br&gt;
It will use the configured &lt;code&gt;RequestMatcher&lt;/code&gt; to check if it should perform authentication and then it will call the &lt;code&gt;attemptAuthentication&lt;/code&gt; method, if it is successful it will perform some aditional operations (not really important for the purposes of this article) and lastly it will use the &lt;code&gt;succesfulAuthentication&lt;/code&gt; method which in turn will use the handler we passed, if it fails it will use the &lt;code&gt;unsuccessfulAuthentication&lt;/code&gt;method which uses our failure handler&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;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;successfulAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;FilterChain&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;authResult&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;IOException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ServletException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SecurityContext&lt;/span&gt; &lt;span class="n"&gt;context&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;securityContextHolderStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createEmptyContext&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAuthentication&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authResult&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;securityContextHolderStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&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;securityContextRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saveContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&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;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDebugEnabled&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;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Set SecurityContextHolder to %s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authResult&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;rememberMeServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loginSuccess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authResult&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;eventPublisher&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;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;eventPublisher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publishEvent&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;InteractiveAuthenticationSuccessEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authResult&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;getClass&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;successHandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onAuthenticationSuccess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authResult&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;Here we can see that it will do some aditional logic like event publishing, remember me services, etc…, but the part i want to highlight is the save of the context using the &lt;code&gt;SecurityContextRepository&lt;/code&gt; this bean comes from the configuration, so let’s talk a little about the configuration of these special filters.&lt;/p&gt;

&lt;p&gt;The default implementations of these filters are typically configured with the HttpSecurity builder spring provides for the SecurityFilterChain configuration, more specifically it will use special classes that extend the &lt;code&gt;AbstractAuthenticationFilterConfigurer&lt;/code&gt; like the &lt;code&gt;FormLoginConfigurer&lt;/code&gt; and such, allow me to show a small part of the code in this abstract class:&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;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;B&lt;/span&gt; &lt;span class="n"&gt;http&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="o"&gt;...&lt;/span&gt;
    &lt;span class="nc"&gt;SecurityContextConfigurer&lt;/span&gt; &lt;span class="n"&gt;securityContextConfigurer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConfigurer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecurityContextConfigurer&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;securityContextConfigurer&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;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;securityContextConfigurer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isRequireExplicitSave&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SecurityContextRepository&lt;/span&gt; &lt;span class="n"&gt;securityContextRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;securityContextConfigurer&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSecurityContextRepository&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;authFilter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSecurityContextRepository&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;securityContextRepository&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;authFilter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSecurityContextHolderStrategy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getSecurityContextHolderStrategy&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="no"&gt;F&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;postProcess&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;authFilter&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see here it will use another configurer to get the repository that is going to be needed to save (and restore) the sessions if it was configured as such, do you remember the filter chain configuration example I showed where i provided a configuration example for each of the relevant filters? well, in that example the &lt;code&gt;.securityContext()&lt;/code&gt; method is the &lt;code&gt;SecurityContextConfigurer&lt;/code&gt;, let’s go see what repository it uses by default&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;SecurityContextRepository&lt;/span&gt; &lt;span class="nf"&gt;getSecurityContextRepository&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;SecurityContextRepository&lt;/span&gt; &lt;span class="n"&gt;securityContextRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSharedObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecurityContextRepository&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;securityContextRepository&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="n"&gt;securityContextRepository&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;DelegatingSecurityContextRepository&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;RequestAttributeSecurityContextRepository&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;HttpSessionSecurityContextRepository&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;securityContextRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see here, it will use either the one you pass to the configuration or a &lt;code&gt;DelegatingSecurityContextRepository&lt;/code&gt; one which is composed of the &lt;code&gt;RequestAttributeSecurityContextRepository&lt;/code&gt; (it persits the context on the current request only) and the &lt;code&gt;HttpSessionSecurityContextRepository&lt;/code&gt; (it persits the context on the http session) if you didn’t configure one, although there are some small extra details they are not exactly a must to understand the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  LogoutFilter
&lt;/h3&gt;

&lt;p&gt;It uses a series of LogoutHandlers which will be used in the order they are specified, after a succesful logout it will perform a redirect using either the &lt;code&gt;LogoutSuccessHandler&lt;/code&gt; or the &lt;code&gt;logoutSuccessUrl&lt;/code&gt; configured.&lt;/p&gt;

&lt;p&gt;The implementation of this filter is pretty similar to the previous one so instead of showing it I willl show you the implementation of a logout handler that spring provides.&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;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;authentication&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"HttpServletRequest required"&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invalidateHttpSession&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;HttpSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSession&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&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="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invalidate&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDebugEnabled&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;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalidated session %s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;SecurityContext&lt;/span&gt; &lt;span class="n"&gt;context&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;securityContextHolderStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getContext&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;securityContextHolderStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clearContext&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clearAuthentication&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAuthentication&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="nc"&gt;SecurityContext&lt;/span&gt; &lt;span class="n"&gt;emptyContext&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;securityContextHolderStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createEmptyContext&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;securityContextRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saveContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emptyContext&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code comes from the &lt;code&gt;SecurityContextLogoutHandler&lt;/code&gt; which is one of the default ones spring security uses, it will assert that there is a request, if configured it will invalidate the session, then it will clear the context and if set, it will also clear the authentication it will also use the &lt;code&gt;SecurityContextRepository&lt;/code&gt; to update the context to unauthenticated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion &amp;amp; What’s Next
&lt;/h2&gt;

&lt;p&gt;So far we’ve explored the key components involved in Spring Security’s authentication flow, from simple things like the &lt;code&gt;Authentication&lt;/code&gt; interface to more complext parts like the &lt;code&gt;SecurityContextRepository&lt;/code&gt;, by understanding how these parts work together we can gain a deeper insight into how Spring Security manages authentication behind the scenes and allows you to write your own implementations or decide whether you should you the default ones or not. &lt;/p&gt;

&lt;p&gt;Looking ahead, I plan to write follow-up articles exploring custom authentication implementations, such as integrating alternative authentication mechanisms beyond username-password authentication. I may also cover different Spring Security configurations, including OAuth2, JWT-based authentication, and fine-grained access control strategies.&lt;/p&gt;

&lt;p&gt;If you’re interested in diving deeper into these topics, stay tuned for upcoming posts where we’ll explore practical examples and real-world use cases. 🚀​&lt;/p&gt;

&lt;p&gt;Do keep in mind that i’m by no means an expert in either security or spring so I will need lots and lots of documentation which means posting each article will take time, please comment any questions or sugestions you may have I'd be glad to read your thoughts 😁, with nothing else left to say, bye and best regards. 🎉🎉🎉&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>springsecurity</category>
      <category>authentication</category>
      <category>security</category>
    </item>
  </channel>
</rss>
