<?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: Ankit Verma</title>
    <description>The latest articles on DEV Community by Ankit Verma (@ankit_verma_e2fa7fb2aa95d).</description>
    <link>https://dev.to/ankit_verma_e2fa7fb2aa95d</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3973400%2F62bb2cd4-9517-49ee-9812-abecef838b1b.jpg</url>
      <title>DEV Community: Ankit Verma</title>
      <link>https://dev.to/ankit_verma_e2fa7fb2aa95d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ankit_verma_e2fa7fb2aa95d"/>
    <language>en</language>
    <item>
      <title>Bean scopes (singleton/prototype/request/session) + singleton thread-safety gotcha</title>
      <dc:creator>Ankit Verma</dc:creator>
      <pubDate>Mon, 08 Jun 2026 07:41:11 +0000</pubDate>
      <link>https://dev.to/ankit_verma_e2fa7fb2aa95d/bean-scopes-singletonprototyperequestsession-singleton-thread-safety-gotcha-10n</link>
      <guid>https://dev.to/ankit_verma_e2fa7fb2aa95d/bean-scopes-singletonprototyperequestsession-singleton-thread-safety-gotcha-10n</guid>
      <description>&lt;p&gt;Every object the container builds has to answer two quiet questions: how many copies of it should exist, and how long should each one live? One shared copy for the whole application? A fresh one every time someone asks? One per web request? The answer to those two questions is the bean's &lt;strong&gt;scope&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You usually meet scope the day shared state misbehaves. A field on a &lt;code&gt;@Service&lt;/code&gt; holds a value for one user and somehow shows up for another. Or you expected a brand-new object each time and kept getting the same one back. Both are scope surprises — and both have the same root cause once you can see it.&lt;/p&gt;

&lt;p&gt;So this article walks the scopes Spring gives you, starting with the default you have been leaning on without ever naming it. Then it covers the two traps scope sets — including the one that causes real, hard-to-find production bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The default you have already been using
&lt;/h2&gt;

&lt;p&gt;Every bean in the previous articles was a &lt;strong&gt;singleton&lt;/strong&gt;: the container builds exactly one instance, caches it at startup, and hands that same object to everyone who needs it, for the whole life of the application. You never asked for this. It is simply what &lt;code&gt;@Component&lt;/code&gt;, &lt;code&gt;@Service&lt;/code&gt;, and a bare &lt;code&gt;@Bean&lt;/code&gt; give you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;   &lt;span class="c1"&gt;// one instance, shared everywhere&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask the container for it twice and you get the identical object back:&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;OrderService&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderService&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="c1"&gt;// a == b  → true, same instance&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One word of caution on the name. A Spring &lt;strong&gt;singleton&lt;/strong&gt; means &lt;em&gt;one instance per container&lt;/em&gt; — not the classic JVM-wide singleton from design-pattern books. Spin up a second container and you get a second instance. Within one application that distinction rarely bites, but it is why "singleton" here is a scope, not a guarantee about the whole JVM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asking for a fresh one each time: prototype
&lt;/h2&gt;

&lt;p&gt;Sometimes one shared instance is exactly wrong. You want a short-lived, stateful helper — a builder you fill in, use once, and throw away. For that, Spring offers the &lt;strong&gt;prototype&lt;/strong&gt; scope: a brand-new instance every single time the bean is requested.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@Scope&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"prototype"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReportBuilder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;   &lt;span class="c1"&gt;// a new one on every request&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now each &lt;code&gt;getBean&lt;/code&gt; hands back a different object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ReportBuilder&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReportBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;ReportBuilder&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReportBuilder&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="c1"&gt;// a != b  → two separate instances&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two more things change with prototype. The container builds it &lt;strong&gt;on demand&lt;/strong&gt;, when you ask — not eagerly at startup like a singleton. And, as the lifecycle article noted, Spring runs a prototype's setup but then forgets it: it never calls the destroy stage. The container builds a prototype, hands it over, and walks away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the default is a singleton — and the trap hiding inside it
&lt;/h2&gt;

&lt;p&gt;One shared instance is cheap and fast, which is why it is the default. But "shared" is the dangerous word, and it leads straight to the single most common Spring bug.&lt;/p&gt;

&lt;p&gt;A web application handles many requests at the same time, each on its own thread. Every one of those threads calls into the &lt;em&gt;same&lt;/em&gt; singleton instance. So any mutable field on a singleton is shared across all of them at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CartService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;itemCount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;// ONE field, shared by every thread&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;itemCount&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// two threads here = lost updates&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks fine in testing, where one request runs at a time. In production it corrupts data. Two users add items concurrently, both threads read &lt;code&gt;itemCount&lt;/code&gt;, both increment, both write back — and one update vanishes. Worse, one user's count is now visible to another, because there was only ever one field.&lt;/p&gt;

&lt;p&gt;The fix is a rule, not a trick: &lt;strong&gt;keep singletons stateless.&lt;/strong&gt; Don't store per-call or per-user data in fields. Let that data live in method parameters, local variables, and return values — those sit on each thread's own stack, so they are never shared.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CartService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;withItemAdded&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;   &lt;span class="c1"&gt;// state passed in and out, never stored&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note what is &lt;em&gt;not&lt;/em&gt; a problem: fields that are set once at construction and never change — your injected dependencies, anything &lt;code&gt;final&lt;/code&gt;. Those are shared too, but since nobody mutates them, no thread can corrupt them. The bug is specifically &lt;em&gt;mutable&lt;/em&gt; shared state. Immutable shared state is exactly what a singleton is good at.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scopes that follow the web request
&lt;/h2&gt;

&lt;p&gt;Sometimes you genuinely need per-user or per-request state, and stuffing it through method parameters everywhere gets ugly. For that, Spring adds two web-aware scopes.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;request-scoped&lt;/strong&gt; bean lives for exactly one HTTP request: the container builds a fresh one when the request arrives and discards it when the response is sent. A &lt;strong&gt;session-scoped&lt;/strong&gt; bean lives for one user's session, spanning their many requests until the session ends.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@RequestScope&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RequestContext&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;traceId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// safe: each request gets its own instance&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because every request gets its own instance, that mutable &lt;code&gt;traceId&lt;/code&gt; field is now perfectly safe — the sharing that doomed the singleton simply isn't there. This is the right home for "data that belongs to this one request."&lt;/p&gt;

&lt;p&gt;But it raises an awkward question. A singleton is built once, at startup. A request-scoped bean does not exist yet at startup — no request is in flight. So how can you inject a request-scoped bean into a singleton, when the thing you want to inject won't exist until much later, and then keeps being replaced?&lt;/p&gt;

&lt;h2&gt;
  
  
  The scoped-proxy fix
&lt;/h2&gt;

&lt;p&gt;This is where the &lt;strong&gt;proxy&lt;/strong&gt; from the first article comes back to do real work. When you inject a shorter-lived bean into a longer-lived one, Spring does not inject the real bean — it injects a &lt;strong&gt;proxy&lt;/strong&gt;: a same-shaped stand-in that, on every method call, looks up the correct instance for the &lt;em&gt;current&lt;/em&gt; request and forwards to it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@RequestScope&lt;/code&gt; switches this proxy on by default, so the injection just works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuditService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;RequestContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// really a proxy, injected once&lt;/span&gt;

    &lt;span class="nc"&gt;AuditService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RequestContext&lt;/span&gt; &lt;span class="n"&gt;context&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;context&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="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;record&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;event&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;setTraceId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// resolves to THIS request's instance&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 singleton &lt;code&gt;AuditService&lt;/code&gt; is wired exactly once at startup, holding the proxy forever. But each call through that proxy lands on the right per-request &lt;code&gt;RequestContext&lt;/code&gt;. Without the proxy you would be stuck: either a startup failure because no request exists to inject, or one shared instance that defeats the entire point of request scope. The proxy bridges the lifespans.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prototype-in-singleton trap
&lt;/h2&gt;

&lt;p&gt;Now the trap that catches almost everyone, because it fails silently rather than loudly. Inject a prototype into a singleton the obvious way, and you do &lt;em&gt;not&lt;/em&gt; get a fresh prototype per call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvoiceService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ReportBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// injected ONCE, frozen forever&lt;/span&gt;

    &lt;span class="nc"&gt;InvoiceService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReportBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&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;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;;&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;generate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reset&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// same instance every invoice — not what you wanted&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;You chose &lt;code&gt;prototype&lt;/code&gt; precisely so each invoice would get its own &lt;code&gt;ReportBuilder&lt;/code&gt;. Instead you got exactly one, captured at startup, reused for the life of the app. The reason is simple once it clicks: &lt;strong&gt;injection is a one-time event for a singleton.&lt;/strong&gt; Spring builds &lt;code&gt;InvoiceService&lt;/code&gt; once, so it resolves and injects its dependencies once. The prototype scope only promises a new instance &lt;em&gt;per request to the container&lt;/em&gt; — and that request happened a single time, at wiring.&lt;/p&gt;

&lt;p&gt;The fix is to ask the container for a new one at the moment you need it, instead of capturing one at startup. &lt;code&gt;ObjectProvider&lt;/code&gt; is the clean way to do exactly that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvoiceService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ObjectProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReportBuilder&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;builders&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;InvoiceService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ObjectProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReportBuilder&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;builders&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;builders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builders&lt;/span&gt;&lt;span class="o"&gt;;&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;generate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ReportBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getObject&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// a fresh prototype each call&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;Each &lt;code&gt;getObject()&lt;/code&gt; is a new request to the container, so each returns a new prototype. (A scoped proxy on the prototype achieves the same thing transparently, the way &lt;code&gt;@RequestScope&lt;/code&gt; did — but &lt;code&gt;ObjectProvider&lt;/code&gt; makes the "give me a fresh one now" intent obvious at the call site.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together
&lt;/h2&gt;

&lt;p&gt;A scope answers two questions about a bean: &lt;strong&gt;how many&lt;/strong&gt; instances exist, and &lt;strong&gt;how long&lt;/strong&gt; each lives. &lt;strong&gt;Singleton&lt;/strong&gt; — one per container, the default — is built once and shared by everyone. &lt;strong&gt;Prototype&lt;/strong&gt; is a new instance on every request, built on demand, and never destroyed by the container. &lt;strong&gt;Request&lt;/strong&gt; and &lt;strong&gt;session&lt;/strong&gt; scope tie a bean's life to one HTTP request or one user's session.&lt;/p&gt;

&lt;p&gt;Both traps in this article come from mixing lifespans. The thread-safety bug is one singleton shared across many threads at once, so any mutable field is a race — fixed by keeping singletons stateless. The stale-injection bug is a short-lived bean injected once into a long-lived one, so it freezes at startup — fixed by the scoped proxy, or by pulling a fresh instance from an &lt;code&gt;ObjectProvider&lt;/code&gt; when you actually need it.&lt;/p&gt;

&lt;p&gt;Hold on to the one idea underneath both: for a singleton, wiring happens exactly once. Everything that surprises you about scope follows from remembering when injection actually runs.&lt;/p&gt;

</description>
      <category>spring</category>
      <category>java</category>
      <category>backend</category>
      <category>programming</category>
    </item>
    <item>
      <title>Bean lifecycle: instantiate populate init destroy</title>
      <dc:creator>Ankit Verma</dc:creator>
      <pubDate>Mon, 08 Jun 2026 06:49:43 +0000</pubDate>
      <link>https://dev.to/ankit_verma_e2fa7fb2aa95d/bean-lifecycle-instantiate-populate-init-destroy-2p68</link>
      <guid>https://dev.to/ankit_verma_e2fa7fb2aa95d/bean-lifecycle-instantiate-populate-init-destroy-2p68</guid>
      <description>&lt;p&gt;A Spring bean does not blink into existence fully formed. The container assembles it in a fixed order of stages — build the object, fill in its dependencies, run its setup, and much later, run its teardown. That ordered sequence is the &lt;strong&gt;bean lifecycle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You meet it the first time you need something to happen at an exact moment. You want a connection pool opened &lt;em&gt;after&lt;/em&gt; the bean has all its dependencies, but &lt;em&gt;before&lt;/em&gt; it handles a single request. You want a cache flushed to disk when the app shuts down — but only if startup actually finished. To put your code in the right place, you have to know the order these stages run in, and what is guaranteed to be ready when each one fires.&lt;/p&gt;

&lt;p&gt;The whole lifecycle is just the container doing work around an object it built. We will walk it end to end: the four main stages, the hooks Spring opens at each one, and two traps that fall straight out of the ordering.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four stages, in one breath
&lt;/h2&gt;

&lt;p&gt;Here is the spine of the whole article — the path every singleton bean walks, from startup to shutdown:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Instantiate&lt;/strong&gt; — construct the raw object.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Populate&lt;/strong&gt; — inject its dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initialize&lt;/strong&gt; — run setup now that it is fully wired.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destroy&lt;/strong&gt; — run teardown at shutdown.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Everything else is detail hung on those four pegs. Let's take them one at a time, because the &lt;em&gt;order&lt;/em&gt; is the entire point — each stage is only safe to use once you know what ran before it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 1: instantiate — a bare object
&lt;/h2&gt;

&lt;p&gt;First the container calls a constructor and gets back a raw Java object. Nothing Spring-specific has happened yet; this is the same &lt;code&gt;new&lt;/code&gt; you would write by hand, just done for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;WarehouseClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;InventoryService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WarehouseClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;   &lt;span class="c1"&gt;// constructor injection&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="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;There is a subtlety worth pausing on. When you use &lt;strong&gt;constructor injection&lt;/strong&gt; — dependencies passed as constructor arguments, as above — the wiring happens &lt;em&gt;inside&lt;/em&gt; this first stage. Spring works out what &lt;code&gt;WarehouseClient&lt;/code&gt; is, builds it, and hands it in as the object is created. For constructor-injected beans, "instantiate" and "populate" are the same moment.&lt;/p&gt;

&lt;p&gt;That is &lt;em&gt;not&lt;/em&gt; true for the other injection styles, and the difference is where the next stage earns its name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 2: populate — the fields get filled
&lt;/h2&gt;

&lt;p&gt;If a dependency is injected into a field or through a setter, it cannot arrive in the constructor — the object has to exist first, then Spring reaches in and sets it. That second step is &lt;strong&gt;populate&lt;/strong&gt;: the container assigns every field- and setter-injected dependency onto the freshly built object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;WarehouseClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// set during populate, not in the constructor&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ordering explains a bug everyone hits once. A field-injected dependency is &lt;code&gt;null&lt;/code&gt; if you touch it inside the constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;WarehouseClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;InventoryService&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;connect&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// NullPointerException — populate hasn't run yet&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 constructor runs in stage 1. Populate is stage 2. At the moment the constructor body executes, the field is still empty. This is one more reason the previous article pushed constructor injection so hard: it collapses these two stages into one, so a dependency is never half-there. But when you do use field or setter injection, populate is the stage that fills them — and nothing before it can rely on them.&lt;/p&gt;

&lt;p&gt;Between populate and the next stage, Spring may also hand the bean a few references to the container itself, if the bean asks for them by implementing an &lt;strong&gt;Aware&lt;/strong&gt; interface (for example &lt;code&gt;BeanNameAware&lt;/code&gt; to learn its own bean name). It is a narrow feature you will rarely reach for, but it slots in right here: after the dependencies, before initialization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 3: initialize — the bean gets ready
&lt;/h2&gt;

&lt;p&gt;Now the object is fully wired. This is the moment to do setup that &lt;em&gt;needs&lt;/em&gt; the dependencies in place — open that connection pool, warm a cache, validate configuration. Spring calls this the &lt;strong&gt;initialization&lt;/strong&gt; stage, and it gives you a hook that fires exactly here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InventoryService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;WarehouseClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;InventoryService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WarehouseClient&lt;/span&gt; &lt;span class="n"&gt;client&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@PostConstruct&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;openPool&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;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;connect&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// every dependency is guaranteed wired by now&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;@PostConstruct&lt;/code&gt; method runs after populate, so it can lean on every dependency being present — the guarantee the constructor could not give you. This is the &lt;em&gt;right&lt;/em&gt; home for "do this once, at startup, after wiring."&lt;/p&gt;

&lt;p&gt;There are three ways to register init code, and when more than one is present they run in a fixed order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A method annotated &lt;strong&gt;&lt;code&gt;@PostConstruct&lt;/code&gt;&lt;/strong&gt; — runs first. This is the standard, framework-agnostic choice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;afterPropertiesSet()&lt;/code&gt;&lt;/strong&gt;, if the bean implements the &lt;code&gt;InitializingBean&lt;/code&gt; interface — runs second. It couples your class to Spring's API, so it is rarely the better option.&lt;/li&gt;
&lt;li&gt;A method named in &lt;strong&gt;&lt;code&gt;@Bean(initMethod = "...")&lt;/code&gt;&lt;/strong&gt; — runs last. Useful when the class is third-party and you cannot annotate it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Reach for &lt;code&gt;@PostConstruct&lt;/code&gt; unless you have a specific reason not to. The other two exist mostly for cases where you cannot put an annotation on the method.&lt;/p&gt;

&lt;h2&gt;
  
  
  The proxy slips in right after init
&lt;/h2&gt;

&lt;p&gt;Remember from the first article that the container can wrap a bean in a &lt;strong&gt;proxy&lt;/strong&gt; — a same-shaped stand-in that runs extra code (a transaction, an async hand-off) around your methods. The lifecycle is where that wrapping actually happens, and &lt;em&gt;exactly when&lt;/em&gt; it happens is the source of a classic trap.&lt;/p&gt;

&lt;p&gt;Spring exposes the init stage through an interface called &lt;strong&gt;&lt;code&gt;BeanPostProcessor&lt;/code&gt;&lt;/strong&gt;, which has two callbacks: one that runs &lt;em&gt;before&lt;/em&gt; your init code, and one that runs &lt;em&gt;after&lt;/em&gt;. The proxy is created in that second, after-init callback. So the order is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Populate the bean.&lt;/li&gt;
&lt;li&gt;Run your &lt;code&gt;@PostConstruct&lt;/code&gt; / init methods — on the &lt;strong&gt;raw&lt;/strong&gt; object.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Then&lt;/em&gt; wrap the result in a proxy and store that proxy in the container.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Read step 2 again, because it bites. Inside &lt;code&gt;@PostConstruct&lt;/code&gt;, the proxy does not exist yet. The &lt;code&gt;this&lt;/code&gt; you are holding is the bare bean. So if your init method calls one of its own proxied methods, the wrapper is skipped:&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;@PostConstruct&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;warmUp&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;reload&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// if reload() is @Transactional, there is NO transaction here&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;reload()&lt;/code&gt; may be annotated &lt;code&gt;@Transactional&lt;/code&gt;, but calling it through &lt;code&gt;this&lt;/code&gt; during init goes straight to the raw method — the proxy that would have opened the transaction has not been built yet. The fix is not to depend on proxied behavior from inside initialization. The lesson generalizes: &lt;strong&gt;your own init code always sees the unwrapped bean.&lt;/strong&gt; Everyone else, fetching the bean from the container later, sees the proxy.&lt;/p&gt;

&lt;h2&gt;
  
  
  In service
&lt;/h2&gt;

&lt;p&gt;Once initialization and any wrapping are done, the bean is finished. The container drops it on the shelf and hands out that same instance — the proxy, if there is one — to everyone who needs it, for the rest of the application's life. No more lifecycle events fire until shutdown. For a normal singleton, that "in service" period is essentially the whole life of the program.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 4: destroy — teardown at shutdown
&lt;/h2&gt;

&lt;p&gt;When the application context closes — a graceful shutdown, a &lt;code&gt;SIGTERM&lt;/code&gt;, the JVM shutdown hook firing — Spring walks its singletons one last time and runs their teardown. This is the place to release what initialization acquired: close the pool, flush the buffer, deregister from a discovery service.&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;@PreDestroy&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;closePool&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// mirror of @PostConstruct, run on the way down&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Destruction mirrors initialization exactly, including the three-way ordering:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A method annotated &lt;strong&gt;&lt;code&gt;@PreDestroy&lt;/code&gt;&lt;/strong&gt; — runs first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;destroy()&lt;/code&gt;&lt;/strong&gt;, if the bean implements &lt;code&gt;DisposableBean&lt;/code&gt; — runs second.&lt;/li&gt;
&lt;li&gt;A method named in &lt;strong&gt;&lt;code&gt;@Bean(destroyMethod = "...")&lt;/code&gt;&lt;/strong&gt; — runs last.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One honest caveat: these run only on an &lt;em&gt;orderly&lt;/em&gt; shutdown, when Spring is given the chance to close the context. A hard kill — &lt;code&gt;kill -9&lt;/code&gt;, a power loss — bypasses the whole stage. So &lt;code&gt;@PreDestroy&lt;/code&gt; is the right place for a graceful flush, but it is not a guarantee that your teardown will ever run. Anything that absolutely must survive a crash needs to be durable by other means, not parked in a destroy callback.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prototype trap
&lt;/h2&gt;

&lt;p&gt;Everything above describes a &lt;strong&gt;singleton&lt;/strong&gt; — the default, one shared instance the container holds and manages. Spring also offers the &lt;strong&gt;prototype&lt;/strong&gt; scope, where you get a brand-new bean every time you ask for one. Prototypes go through the first three stages in full: Spring instantiates them, populates them, and runs their init callbacks.&lt;/p&gt;

&lt;p&gt;Then it lets go. &lt;strong&gt;Spring does not run the destroy stage for prototype beans.&lt;/strong&gt; It builds one, hands it to you, and forgets it ever existed — so &lt;code&gt;@PreDestroy&lt;/code&gt; on a prototype is never called by the container.&lt;/p&gt;

&lt;p&gt;That is a real leak waiting to happen. If a prototype opens a file handle or a socket in &lt;code&gt;@PostConstruct&lt;/code&gt;, expecting &lt;code&gt;@PreDestroy&lt;/code&gt; to close it, the close never fires and the resource leaks every time you request the bean. For a prototype that holds something which must be released, you are responsible for closing it yourself — the lifecycle only takes you halfway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together
&lt;/h2&gt;

&lt;p&gt;A bean is built in four ordered stages, and the order is the whole point. &lt;strong&gt;Instantiate&lt;/strong&gt; makes the raw object — and for constructor injection, wires it at the same time. &lt;strong&gt;Populate&lt;/strong&gt; fills in any field- and setter-injected dependencies, which is why those are &lt;code&gt;null&lt;/code&gt; if you touch them too early. &lt;strong&gt;Initialize&lt;/strong&gt; runs your setup once everything is wired, with &lt;code&gt;@PostConstruct&lt;/code&gt; as the natural home. And &lt;strong&gt;destroy&lt;/strong&gt; runs your teardown on an orderly shutdown, with &lt;code&gt;@PreDestroy&lt;/code&gt; as its mirror.&lt;/p&gt;

&lt;p&gt;Two traps fall straight out of that ordering. The proxy is built &lt;em&gt;after&lt;/em&gt; your init code, so initialization always sees the unwrapped bean — self-calls to transactional or async methods quietly do nothing there. And prototypes get the first three stages but never the fourth, so anything they open, you must close.&lt;/p&gt;

&lt;p&gt;Hold on to the shape rather than the annotations: wired, then ready, then — much later, and only if you shut down cleanly — gone.&lt;/p&gt;

</description>
      <category>spring</category>
      <category>java</category>
      <category>backend</category>
      <category>programming</category>
    </item>
    <item>
      <title>Dependency Injection — the problem it solves</title>
      <dc:creator>Ankit Verma</dc:creator>
      <pubDate>Mon, 08 Jun 2026 06:43:53 +0000</pubDate>
      <link>https://dev.to/ankit_verma_e2fa7fb2aa95d/dependency-injection-the-problem-it-solves-5098</link>
      <guid>https://dev.to/ankit_verma_e2fa7fb2aa95d/dependency-injection-the-problem-it-solves-5098</guid>
      <description>&lt;p&gt;The first article in this module made one claim and moved on: stop calling &lt;code&gt;new&lt;/code&gt; on your collaborators, and let the container hand them in. That was the &lt;em&gt;what&lt;/em&gt;. This article is the &lt;em&gt;why&lt;/em&gt; — because a rule you don't understand is a rule you'll break the first time it's inconvenient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency injection&lt;/strong&gt; is the practice of giving an object the things it needs from the outside, instead of letting it build them itself. You met the name in passing already. Here we look at what it actually buys you, what it costs, and why one way of doing it is plainly better than the rest.&lt;/p&gt;

&lt;p&gt;You hit this decision every time you write a class that needs another class. Do you reach for &lt;code&gt;new&lt;/code&gt; and build the collaborator inside? Or do you ask for it and let something else supply it? That one choice, repeated across a codebase, is the difference between code you can test and change and code that quietly fights you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing DI actually fights
&lt;/h2&gt;

&lt;p&gt;It is tempting to think the enemy here is the &lt;code&gt;new&lt;/code&gt; keyword. It isn't. The enemy is &lt;strong&gt;coupling to construction&lt;/strong&gt; — a class deciding, inside its own body, exactly how its collaborators are built.&lt;/p&gt;

&lt;p&gt;Look at what a class signs up for the moment it builds its own collaborator:&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;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PaymentGateway&lt;/span&gt; &lt;span class="n"&gt;gateway&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;PaymentGateway&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;StripeClient&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;placeOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;total&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;That one line welds together two decisions that have nothing to do with each other:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What&lt;/strong&gt; &lt;code&gt;OrderService&lt;/code&gt; needs — something that can charge money.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which&lt;/strong&gt; exact thing it gets, and how that thing is built — this concrete class, wired to Stripe, constructed just so.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first decision is &lt;code&gt;OrderService&lt;/code&gt;'s business. The second is not. &lt;code&gt;OrderService&lt;/code&gt; should not hold an opinion on whether payments go through Stripe or Adyen, or what a gateway needs underneath. The moment it bakes that opinion into code, the two decisions can never move apart again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pulling the two decisions apart
&lt;/h2&gt;

&lt;p&gt;So separate them. Make &lt;code&gt;OrderService&lt;/code&gt; depend only on the &lt;em&gt;role&lt;/em&gt; — what it needs — and let it state that need without naming a concrete 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="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PaymentGateway&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;charge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PaymentGateway&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;OrderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentGateway&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;   &lt;span class="c1"&gt;// "give me something that charges"&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;gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;OrderService&lt;/code&gt; now names an interface and nothing else. It has no idea which class shows up at runtime. Something outside decides that and supplies it.&lt;/p&gt;

&lt;p&gt;The principle you just applied has a name: &lt;strong&gt;depend on abstractions, not on concrete implementations&lt;/strong&gt; — and let an outside party choose and supply the concrete one. Dependency injection is simply the delivery mechanism for that idea. The interface is the contract; injection is how the chosen implementation arrives.&lt;/p&gt;

&lt;p&gt;That separation is the whole payoff, and it shows up in three concrete ways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can test it.&lt;/strong&gt; In a test you hand &lt;code&gt;OrderService&lt;/code&gt; a fake gateway that records calls instead of hitting a bank — possible only because nothing concrete is baked in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can swap implementations.&lt;/strong&gt; Moving from Stripe to Adyen in production means changing one bean definition. Not a single line of &lt;code&gt;OrderService&lt;/code&gt; changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The container can wrap what it supplies.&lt;/strong&gt; Because the gateway arrives from outside, the container gets a chance to hand you something that isn't your plain object — it can wrap it first. That wrap is how &lt;code&gt;@Transactional&lt;/code&gt; and the other annotations from the last article attach themselves, and it is only possible because you didn't build the thing yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Spring picks what to inject
&lt;/h2&gt;

&lt;p&gt;So &lt;code&gt;OrderService&lt;/code&gt; asks for a &lt;code&gt;PaymentGateway&lt;/code&gt;. How does the container know what to give it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By type.&lt;/strong&gt; When Spring builds &lt;code&gt;OrderService&lt;/code&gt; and sees a constructor parameter of type &lt;code&gt;PaymentGateway&lt;/code&gt;, it looks through the beans it knows about for one whose type fits &lt;code&gt;PaymentGateway&lt;/code&gt;, and injects that one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StripeGateway&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;PaymentGateway&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;charge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&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;You never told Spring "use &lt;code&gt;StripeGateway&lt;/code&gt; for &lt;code&gt;OrderService&lt;/code&gt;." You declared a need by type, you have one bean of that type, and the container connected them.&lt;/p&gt;

&lt;p&gt;What happens when &lt;em&gt;two&lt;/em&gt; classes implement &lt;code&gt;PaymentGateway&lt;/code&gt; — how you break the tie — is its own topic later in this module. For now the point is just this: resolution is by type.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the style of injection is not a matter of taste
&lt;/h2&gt;

&lt;p&gt;There are three places Spring can put an injected dependency: the constructor, a setter, or straight into a field by reflection. They look interchangeable. They are not — and the difference is mechanical, not stylistic.&lt;/p&gt;

&lt;p&gt;Here is the field version. It looks the cleanest and costs the most:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;PaymentGateway&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// looks tidy&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch what this quietly allows. The object can be &lt;strong&gt;fully built while completely empty&lt;/strong&gt; — &lt;code&gt;new OrderService()&lt;/code&gt; succeeds and hands you an instance whose &lt;code&gt;gateway&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;. The field can't be &lt;code&gt;final&lt;/code&gt;, so it stays mutable for the object's whole life. The only way to fill it is reflection, so you can't build a valid instance in a plain unit test without dragging Spring in. And the dependency is invisible from outside: nothing in the signature tells a caller this class even needs a gateway.&lt;/p&gt;

&lt;p&gt;Now the constructor version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PaymentGateway&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;OrderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentGateway&lt;/span&gt; &lt;span class="n"&gt;gateway&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;gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gateway&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;Every one of those problems is gone — and not by convention, by language mechanics. The field is &lt;code&gt;final&lt;/code&gt;, so it is set exactly once and the object is immutable after construction. There is &lt;strong&gt;no way to create the object without supplying its dependency&lt;/strong&gt;; the compiler enforces it. And the dependency is right there in the signature for anyone to read.&lt;/p&gt;

&lt;p&gt;The testing win becomes concrete the moment you write a test. No framework, no reflection — just a constructor call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;chargesTheOrderTotal&lt;/span&gt;&lt;span class="o"&gt;()&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;gateway&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;RecordingGateway&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;          &lt;span class="c1"&gt;// a fake, records instead of charging&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// plain Java, no Spring in sight&lt;/span&gt;

    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;placeOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;

    &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lastCharge&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isEqualTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;90&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;That last point hides the most useful one. Because every dependency has to pass through the constructor, a class with too many of them grows an ugly seven-argument constructor you can't ignore. Field injection lets the same class quietly pile up fifteen &lt;code&gt;@Autowired&lt;/code&gt; fields and still look tidy. The constructor turns "this class is doing too much" from a hidden fact into a visible smell. That isn't a style preference — it is design feedback you would otherwise never get.&lt;/p&gt;

&lt;h2&gt;
  
  
  The circular-dependency trap
&lt;/h2&gt;

&lt;p&gt;There is a sharper version of the same benefit, and it is worth seeing in full. Suppose &lt;code&gt;A&lt;/code&gt; needs &lt;code&gt;B&lt;/code&gt;, and &lt;code&gt;B&lt;/code&gt; needs &lt;code&gt;A&lt;/code&gt; — a circular dependency.&lt;/p&gt;

&lt;p&gt;With field injection, Spring can often paper over it. It creates both raw objects first, then sets the fields afterward, so the cycle "works" by accident and ships. With constructor injection, neither object can be built before the other exists, so Spring can't even start — it fails at boot with &lt;code&gt;BeanCurrentlyInCreationException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is tempting to read that as constructor injection being stricter and therefore more annoying. It is the opposite. The cycle is a real design flaw. Constructor injection forces you to see it the second you boot the app, instead of meeting it as a &lt;code&gt;StackOverflowError&lt;/code&gt; in production weeks later. Failing fast, at the safest possible moment, is the feature.&lt;/p&gt;

&lt;p&gt;Setter injection is the third style. It has one honest, narrow use: a genuinely &lt;em&gt;optional&lt;/em&gt; dependency that can be reconfigured after the object exists. That is rare. Everywhere else, reach for the constructor.&lt;/p&gt;

&lt;h2&gt;
  
  
  One thing resolution-by-type gives you for free
&lt;/h2&gt;

&lt;p&gt;Because injection is by type, a trick falls out that turns DI into a plugin system. Ask for a &lt;code&gt;List&lt;/code&gt; of an interface, and Spring injects &lt;strong&gt;every&lt;/strong&gt; bean that implements 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="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ShippingRule&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;applies&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;surcharge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShippingCalculator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ShippingRule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;ShippingCalculator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ShippingRule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;   &lt;span class="c1"&gt;// every ShippingRule bean, injected&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;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;totalSurcharge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;applies&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;surcharge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reduce&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ZERO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Money:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;add&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;Adding a new rule is now just adding one &lt;code&gt;@Component&lt;/code&gt; that implements &lt;code&gt;ShippingRule&lt;/code&gt;. &lt;code&gt;ShippingCalculator&lt;/code&gt; never changes — it doesn't even know how many rules exist. That is the plugin pattern, delivered entirely by DI.&lt;/p&gt;

&lt;p&gt;One trap rides along with it: &lt;strong&gt;the order of the beans in that injected list is not guaranteed&lt;/strong&gt; unless you make it so. If your rules must run in a set sequence — a discount rule before a tax rule — relying on whatever order Spring happened to hand them in is a bug waiting for the day a refactor reshuffles them. Pin it with &lt;code&gt;@Order&lt;/code&gt; on each implementation (or have them implement &lt;code&gt;Ordered&lt;/code&gt;), and the list arrives in that order. (Ask for &lt;code&gt;Map&amp;lt;String, ShippingRule&amp;gt;&lt;/code&gt; instead, and you get each implementation keyed by its bean name — handy when you need to pick one by name at runtime.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together
&lt;/h2&gt;

&lt;p&gt;Dependency injection isn't about dodging a keyword. It is about refusing to let a class decide both &lt;em&gt;what it needs&lt;/em&gt; and &lt;em&gt;which implementation it gets&lt;/em&gt; — and pulling those apart so the implementation can be swapped, centralized, and wrapped by the container.&lt;/p&gt;

&lt;p&gt;Spring resolves the need by type. Constructor injection is the way to receive it — not for neatness, but because the language then guarantees your object is immutable, impossible to build half-wired, trivial to test without the framework, and honest about how many dependencies it really carries. And once injection is by type, the &lt;code&gt;List&lt;/code&gt;-of-interface plugin pattern comes for free — just remember to pin the order when it matters.&lt;/p&gt;

</description>
      <category>spring</category>
      <category>java</category>
      <category>backend</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why Spring exists; the IoC container in one analogy</title>
      <dc:creator>Ankit Verma</dc:creator>
      <pubDate>Mon, 08 Jun 2026 06:41:13 +0000</pubDate>
      <link>https://dev.to/ankit_verma_e2fa7fb2aa95d/why-spring-exists-the-ioc-container-in-one-analogy-53n2</link>
      <guid>https://dev.to/ankit_verma_e2fa7fb2aa95d/why-spring-exists-the-ioc-container-in-one-analogy-53n2</guid>
      <description>&lt;p&gt;Spring is a framework that builds and connects the objects your application is made of. You write the classes. Spring creates them, wires them together, and hands them to each other at startup. That sounds like a small favor. It quietly reshapes how the whole codebase fits together, and almost every other Spring feature is built on top of it.&lt;/p&gt;

&lt;p&gt;You meet this on day one, usually before anyone names it for you. You open a Spring project, find a class with no &lt;code&gt;new&lt;/code&gt; anywhere in it, and wonder where its dependencies actually come from. The answer is the mechanism this article is about.&lt;/p&gt;

&lt;p&gt;So this first piece is about &lt;em&gt;why&lt;/em&gt; that job needs to exist at all, and the single mechanism Spring uses to do it. Once that mechanism is clear, most of Spring stops looking like magic.&lt;/p&gt;

&lt;p&gt;Let's start with no Spring at all, and watch the problem show up on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  A class that builds its own tools
&lt;/h2&gt;

&lt;p&gt;Here is a class that needs another class to do its job. The natural instinct is to build what it needs, right where it needs it, with &lt;code&gt;new&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;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PaymentGateway&lt;/span&gt; &lt;span class="n"&gt;gateway&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;PaymentGateway&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;placeOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;total&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;Look at what &lt;code&gt;OrderService&lt;/code&gt; now owns. It places orders — that is its real job. But it also knows how to &lt;em&gt;build&lt;/em&gt; a &lt;code&gt;PaymentGateway&lt;/code&gt;. And because a gateway needs an &lt;code&gt;HttpClient&lt;/code&gt;, it builds that too. One class doing two jobs: its actual work, and the plumbing underneath it.&lt;/p&gt;

&lt;p&gt;That second job is where the trouble starts. It costs you three concrete things, and each one points to what comes next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can't test it in isolation.&lt;/strong&gt; The real &lt;code&gt;PaymentGateway&lt;/code&gt; calls a real bank. It is baked in with &lt;code&gt;new&lt;/code&gt;, so there is no way to slip a fake one in for a test. To test the order logic, you'd have to charge actual money.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The plumbing gets copied everywhere.&lt;/strong&gt; Every class that needs a gateway writes the same &lt;code&gt;new PaymentGateway(new HttpClient())&lt;/code&gt;. Change how a gateway is built, and you have to hunt down every copy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There is nowhere to add shared behavior.&lt;/strong&gt; Suppose you want every payment wrapped in a database transaction. With the gateway hard-wired by &lt;code&gt;new&lt;/code&gt;, there is no single seam to hook that in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handing over control
&lt;/h2&gt;

&lt;p&gt;Now the same class, written the way Spring wants it. It stops building anything. It just states what it needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PaymentGateway&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;OrderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentGateway&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;   &lt;span class="c1"&gt;// "I need a PaymentGateway"&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;gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;              &lt;span class="c1"&gt;// someone hands one in&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;OrderService&lt;/code&gt; no longer knows or cares &lt;em&gt;how&lt;/em&gt; a &lt;code&gt;PaymentGateway&lt;/code&gt; is built. It declares the need in its constructor and trusts that a finished one will arrive from outside.&lt;/p&gt;

&lt;p&gt;That flip has a name. Normally your code is in control of creating its own collaborators. Here, your code gives that control away — something else creates the objects and supplies them. Handing that control to the framework is called &lt;strong&gt;Inversion of Control&lt;/strong&gt;, or IoC. The "control" is specifically control over creating and wiring objects. The "inversion" is that it now runs the other way around: the framework builds your objects and calls into them, instead of your objects building everything themselves.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;way&lt;/em&gt; the gateway actually arrives — through the constructor above — has its own name: &lt;strong&gt;Dependency Injection&lt;/strong&gt;, or DI. The dependency, the gateway, is injected into &lt;code&gt;OrderService&lt;/code&gt; from outside. It can arrive through a constructor, through a setter, or straight into a field. Prefer the constructor: the dependency is visible right there in the signature, and the field can be &lt;code&gt;final&lt;/code&gt;, so the object is complete the moment it exists.&lt;/p&gt;

&lt;p&gt;So IoC is the idea — your code no longer creates its own collaborators. DI is the delivery — how each collaborator gets in. Which raises the obvious question: who actually does the creating and the handing-over?&lt;/p&gt;

&lt;h2&gt;
  
  
  The container: a factory that runs at startup
&lt;/h2&gt;

&lt;p&gt;The thing that creates and wires your objects is the &lt;strong&gt;container&lt;/strong&gt;. In Spring it is an object called the &lt;code&gt;ApplicationContext&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is the one analogy worth holding onto: the container is a &lt;strong&gt;factory&lt;/strong&gt;. Not "factory" in the design-pattern sense — picture a literal assembly line that runs once, when your application starts. You hand it a list of what to build and how the pieces fit together. It produces every finished, connected object your app is made of, sets them on a shelf, and hands them out on request for the rest of the program's life. Everything below is just detail about how that factory runs.&lt;/p&gt;

&lt;p&gt;Two small words have been quietly working and now deserve a definition. To &lt;strong&gt;wire&lt;/strong&gt; two objects is just to give one a reference to the other — to set &lt;code&gt;OrderService&lt;/code&gt;'s &lt;code&gt;gateway&lt;/code&gt; field to a real &lt;code&gt;PaymentGateway&lt;/code&gt; instance, so the call inside &lt;code&gt;placeOrder&lt;/code&gt; has something to land on. And a &lt;strong&gt;bean&lt;/strong&gt; is simply an object that the factory creates and manages for you. Your &lt;code&gt;@Service&lt;/code&gt;, your &lt;code&gt;@Component&lt;/code&gt;, the things Spring builds — those are beans. An object you build yourself with &lt;code&gt;new&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a bean, because Spring never touched it. That distinction looks small now; it matters in a minute.&lt;/p&gt;

&lt;p&gt;Here is what the factory does, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It scans your code and writes down recipes, not objects.&lt;/strong&gt; When Spring sees &lt;code&gt;@Component&lt;/code&gt;, &lt;code&gt;@Service&lt;/code&gt;, or a method marked &lt;code&gt;@Bean&lt;/code&gt;, it does not build anything yet. It records a &lt;strong&gt;bean definition&lt;/strong&gt;: which class, how many copies to make, what that bean depends on, and any startup hooks. Think of it as a recipe card, not the finished dish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It works out the dependency graph.&lt;/strong&gt; From those recipes it figures out who needs whom. &lt;code&gt;OrderService&lt;/code&gt; needs &lt;code&gt;PaymentGateway&lt;/code&gt;, which needs &lt;code&gt;HttpClient&lt;/code&gt;. A short chain here; in a real app, a wide web.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It builds the objects bottom-up.&lt;/strong&gt; You can't inject a &lt;code&gt;PaymentGateway&lt;/code&gt; before it exists, so Spring builds the leaves of the graph first and works upward, passing each finished bean into the next one's constructor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It caches each finished bean and reuses it.&lt;/strong&gt; Once a bean is built, the container keeps it and hands out that same instance to everyone who needs it. It does not build a fresh one each time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That third step is worth making concrete, because the &lt;em&gt;order&lt;/em&gt; is the whole point. Take the chain from earlier: &lt;code&gt;OrderService&lt;/code&gt; needs a &lt;code&gt;PaymentGateway&lt;/code&gt;, which needs an &lt;code&gt;HttpClient&lt;/code&gt;. The factory cannot build &lt;code&gt;OrderService&lt;/code&gt; first — it has nothing to put in the constructor yet. So it walks the chain from the bottom:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build &lt;code&gt;HttpClient&lt;/code&gt;. It depends on nothing, so it is a leaf and goes first.&lt;/li&gt;
&lt;li&gt;Build &lt;code&gt;PaymentGateway&lt;/code&gt;, passing in the &lt;code&gt;HttpClient&lt;/code&gt; from step 1.&lt;/li&gt;
&lt;li&gt;Build &lt;code&gt;OrderService&lt;/code&gt;, passing in the &lt;code&gt;PaymentGateway&lt;/code&gt; from step 2.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Three objects, built in the one order that lets each constructor receive a finished dependency. You never wrote a line of that sequencing. The factory read it off the graph and did it for you — and the same logic scales from this three-link chain to a graph with thousands of beans.&lt;/p&gt;

&lt;p&gt;By the time startup finishes, every bean exists and every dependency is in place. Asking for one is now instant, because the work already happened:&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;ApplicationContext&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="n"&gt;svc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderService&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="c1"&gt;// already built and wired&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The extra move: wrapping a bean in a proxy
&lt;/h2&gt;

&lt;p&gt;There is one more thing the factory can do while it builds a bean, and it explains a surprising amount of Spring. While assembling a bean, the container can wrap it in a &lt;strong&gt;proxy&lt;/strong&gt; before handing it over.&lt;/p&gt;

&lt;p&gt;A proxy is a stand-in object. It looks exactly like your bean — same type, same methods — but it runs a little extra code before and after each call, then forwards to your real object. Callers cannot tell the difference. They think they are holding your bean directly.&lt;/p&gt;

&lt;p&gt;That one trick is the real answer to a whole family of "how does Spring even do that?" questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@Transactional&lt;/code&gt; works because the proxy opens a database transaction before your method runs, and commits it after the method returns.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@Async&lt;/code&gt; works because the proxy hands your call off to run on another thread.&lt;/li&gt;
&lt;li&gt;Security and caching annotations work the same way — extra code wrapped neatly around your untouched method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is also the seam the third cost was missing earlier. Back when &lt;code&gt;OrderService&lt;/code&gt; built its own gateway with &lt;code&gt;new&lt;/code&gt;, there was nowhere to slip in "wrap every payment in a transaction." Now there is: the gateway arrives from the factory, so the factory gets one chance, at build time, to hand back a wrapped version instead of the bare one. You wrote a plain method; the container wrapped it at startup. Hold on to this frame, because it keeps paying off: &lt;strong&gt;most Spring features are just the container doing extra work while it assembles your beans.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule that ties it together
&lt;/h2&gt;

&lt;p&gt;All of this only works on objects the container built. The moment you build one yourself, none of it happens:&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;OrderService&lt;/span&gt; &lt;span class="n"&gt;svc&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;OrderService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// built by you, not Spring&lt;/span&gt;
&lt;span class="c1"&gt;// no gateway injected — Spring never saw this object&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The usual symptom is a &lt;code&gt;NullPointerException&lt;/code&gt; on a field you were sure Spring would fill in. Spring did not create the object, so it never wired it, and the field stayed &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The same bypass quietly kills proxies. Call a &lt;code&gt;@Transactional&lt;/code&gt; method on a hand-built instance, and there is no proxy around it, so no transaction ever starts. Nothing errors. The transaction simply isn't there. This is exactly why the bean-versus-&lt;code&gt;new&lt;/code&gt; distinction from earlier mattered: Spring's powers ride on objects the factory made, and skip everything it didn't.&lt;/p&gt;

&lt;p&gt;So the rule is short: &lt;strong&gt;if you want any of Spring's powers on an object, let Spring create the object.&lt;/strong&gt; Don't &lt;code&gt;new&lt;/code&gt; your beans.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together
&lt;/h2&gt;

&lt;p&gt;Spring exists to take one job off your code: creating and connecting objects. Hand that job over, and three ideas fall out of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inversion of Control&lt;/strong&gt; is the handover itself — your code stops creating its own collaborators. &lt;strong&gt;Dependency injection&lt;/strong&gt; is how those collaborators arrive, best through the constructor. And the &lt;strong&gt;container&lt;/strong&gt; is the factory that does the work: it reads your recipes at startup, builds the objects in dependency order, caches them, and can quietly wrap each one in a proxy on the way out.&lt;/p&gt;

&lt;p&gt;That last move, the proxy, is why so much of Spring feels like magic later. It isn't magic. It is the factory doing extra work as it builds your beans. Bean scopes, AOP, transactions — everything heavier you meet from here is a variation on this one startup pass.&lt;/p&gt;

</description>
      <category>spring</category>
      <category>java</category>
      <category>backend</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
