<?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>Forem: Rajat Arora</title>
    <description>The latest articles on Forem by Rajat Arora (@rajatarora).</description>
    <link>https://forem.com/rajatarora</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%2F90837%2Ffe4ff4aa-b193-4825-b873-3b398b46b220.jpeg</url>
      <title>Forem: Rajat Arora</title>
      <link>https://forem.com/rajatarora</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rajatarora"/>
    <language>en</language>
    <item>
      <title>Breaking the interface barrier: CGLIB and ByteBuddy</title>
      <dc:creator>Rajat Arora</dc:creator>
      <pubDate>Fri, 09 Jan 2026 08:13:11 +0000</pubDate>
      <link>https://forem.com/rajatarora/breaking-the-interface-barrier-cglib-and-bytebuddy-462a</link>
      <guid>https://forem.com/rajatarora/breaking-the-interface-barrier-cglib-and-bytebuddy-462a</guid>
      <description>&lt;p&gt;Welcome back! If you've been following along our journey through the world of Java proxies, you know we've spent a lot of time learning about the Proxy pattern and how it is used, its uses in various large libraries in the Java world, and even created a dynamic proxy using Java's internal feature: The JDK Dynamic Proxy.&lt;/p&gt;

&lt;p&gt;While using JDK Dynamic Proxies is &lt;em&gt;easy&lt;/em&gt;... after all, they're built right into the JDK! You don't have to import any third-party library in order to create a dynamic proxy. They are convenient and they are reliable... but, they're a bit too restrictive. &lt;em&gt;They only work with interfaces&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;What if the class you want to proxy doesn't implement an interface? In that case, the JDK is going to look at your face and politely decline to help. But in the real world of Hibernate entities, Spring beans, and legacy monoliths, we often need to proxy classes directly. To break this &lt;em&gt;interface barrier&lt;/em&gt;, we have to move away from high-level Java and start playing with the actual bytecode that makes up our classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Class-based Proxies
&lt;/h2&gt;

&lt;p&gt;If you can't use an interface to define a proxy, how do you do it? The answer is surprisingly simple in theory: &lt;strong&gt;Inheritance&lt;/strong&gt;. Instead of creating a sibling class that shares an interface, we create a child class at runtime. This child class overrides the methods of the parent and inserts the &lt;em&gt;extra&lt;/em&gt; logic (logging, transactions, security) before calling &lt;code&gt;super.method()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w82imuk4v0livcg9v42.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%2F4w82imuk4v0livcg9v42.png" alt="An Interface-based Proxy" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpv7j86bxxboejibau8wc.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%2Fpv7j86bxxboejibau8wc.png" alt="A Class-based Proxy" width="764" height="1204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By becoming a subclass, the proxy is now an instance of the original class (thanks, polymorphism!), allowing it to be injected anywhere the original was expected. This is the bedrock of most Java frameworks, which rely on this "invisible" inheritance to add powerful features without forcing you to change a single line of your domain logic.&lt;/p&gt;

&lt;p&gt;But this capability didn't appear overnight. Before we reached the modern landscape of bytecode engineering, the Java community relied on a singular, powerful tool to bridge the gap where the JDK fell short. To understand where we are going with modern solutions, we first have to look at the library that paved the way and defined an entire era of enterprise Java development.&lt;/p&gt;

&lt;h2&gt;
  
  
  The history of CGLIB: The Fallen Giant
&lt;/h2&gt;

&lt;p&gt;For over a decade, CGLIB (&lt;strong&gt;C&lt;/strong&gt;ode &lt;strong&gt;G&lt;/strong&gt;eneration &lt;strong&gt;Lib&lt;/strong&gt;rary) was the undisputed king of class-based proxies. If you've ever looked at a stack trace in a Spring Boot application and seen something like &lt;code&gt;UserService$$EnhancerBySpringCGLIB$$&lt;/code&gt;..., you've seen CGLIB in action. &lt;/p&gt;

&lt;p&gt;CGLIB sat on top of ASM, a very low-level bytecode manipulation library. It provided a "high-level" (at the time) API to generate subclasses on the fly. Its most famous tools were the &lt;code&gt;Enhancer&lt;/code&gt; class and the &lt;code&gt;MethodInterceptor&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;While revolutionary, CGLIB is now considered "legacy". It hasn't kept pace with the rapid evolution of Java. Since Java 9, the JVM has become much more restrictive about &lt;em&gt;illegal reflective access&lt;/em&gt;, and CGLIB's internal reliance on older ASM versions and dirty tricks for class loading started to cause headaches for developers moving to modern runtimes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Unsafe" instantiation
&lt;/h3&gt;

&lt;p&gt;One of the most notorious "dirty" tricks CGLIB employed (and a primary reason it has struggled with modern Java versions) is its use of the &lt;code&gt;sun.misc.Unsafe&lt;/code&gt; API to instantiate proxy classes by &lt;strong&gt;skipping constructors entirely&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To understand why this is a "trick," we have to look at how Java normally handles objects. Usually, when you extend a class, your constructor must call &lt;code&gt;super()&lt;/code&gt;. But what if the parent class doesn't have a default constructor? Or what if the constructor does something heavy, like opening a database connection or throwing an exception?&lt;/p&gt;

&lt;p&gt;CGLIB wanted to create a proxy &lt;em&gt;without&lt;/em&gt; triggering any of that parent logic.&lt;/p&gt;

&lt;p&gt;Here is a simplified look at the kind of "dirty" logic happening under the hood when you use CGLIB to proxy a class with a "difficult" 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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sun.misc.Unsafe&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.lang.reflect.Field&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DirtyInstantiator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="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="c1"&gt;// 1. Access the "Unsafe" instance via reflection &lt;/span&gt;
        &lt;span class="c1"&gt;// (It's private, so we have to cheat)&lt;/span&gt;
        &lt;span class="nc"&gt;Field&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Unsafe&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;getDeclaredField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"theUnsafe"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAccessible&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="nc"&gt;Unsafe&lt;/span&gt; &lt;span class="n"&gt;unsafe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Unsafe&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;f&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="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Imagine 'ProxyClass' is the subclass CGLIB generated&lt;/span&gt;
        &lt;span class="c1"&gt;// We can create an instance of it WITHOUT calling the constructor&lt;/span&gt;
        &lt;span class="c1"&gt;// even if the constructor is private or throws an exception!&lt;/span&gt;
        &lt;span class="nc"&gt;TargetClass&lt;/span&gt; &lt;span class="n"&gt;proxyInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TargetClass&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
            &lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allocateInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TargetClass&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;proxyInstance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doSomething&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;class&lt;/span&gt; &lt;span class="nc"&gt;TargetClass&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TargetClass&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// This code will NEVER run when CGLIB uses the 'Unsafe' trick&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;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You cannot instantiate me directly!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wait... how am I running? My constructor failed!"&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;This technique is considered dirty for several reasons that affect the stability and security of your application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Violates Language Guarantees:&lt;/strong&gt; Java guarantees that a constructor will run before an object is used. By skipping it, CGLIB can leave internal fields uninitialized (null), leading to unpredictable &lt;code&gt;NullPointerException&lt;/code&gt; errors later in the execution flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encapsulation Breaking:&lt;/strong&gt; It relies on &lt;code&gt;sun.misc.Unsafe&lt;/code&gt;, an internal API that was never meant for public use. Starting with Java 9 and the Module System (Project Jigsaw), the JVM began strictly "encapsulating" these internals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Risks:&lt;/strong&gt; If a class has security checks in its constructor to prevent unauthorized instantiation, CGLIB’s trick bypasses those checks completely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JVM Fragility:&lt;/strong&gt; Because this relies on internal JVM behavior, an update to the OpenJDK can (and often does) break this logic, leading to the "Illegal Reflective Access" warnings that have plagued Spring developers for years.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern libraries like Byte Buddy still have to deal with constructor issues, but they prefer using documented, "cleaner" ways to handle class definition, or they provide much more transparent ways to handle the &lt;code&gt;super()&lt;/code&gt; call requirements.&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;Unsafe&lt;/code&gt; allowed CGLIB to perform technical miracles, they also turned the library into a "black box" that grew increasingly fragile as the Java platform matured. This fragility eventually created a vacuum in the ecosystem for a tool that could handle the raw power of bytecode manipulation without resorting to the "dirty" hacks of the past.&lt;/p&gt;

&lt;p&gt;This is precisely where the industry shifted. We moved away from libraries that try to trick the JVM and toward a framework that works &lt;em&gt;with&lt;/em&gt; the JVM's rules while providing a developer experience that feels like modern, idiomatic Java.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Byte Buddy and the Fluent API
&lt;/h2&gt;

&lt;p&gt;If CGLIB is the aging rockstar of the 2000s, Byte Buddy is the modern virtuoso. Created by Rafael Winterhalter, Byte Buddy won the "Bytecode Wars" because it realized a simple truth: writing bytecode shouldn't feel like writing assembly. It should feel like writing Java.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Philosophy: Type Safety and Simplicity
&lt;/h3&gt;

&lt;p&gt;Byte Buddy’s philosophy is built on moving away from the "stringly-typed" and reflection-heavy approach of CGLIB. Instead of passing strings or raw method objects around and hoping for the best, it uses a &lt;strong&gt;Fluent DSL (Domain Specific Language)&lt;/strong&gt;. This allows you to describe what you want the class to do in a way that the compiler can actually understand and validate, catching potential errors before your application even starts.&lt;/p&gt;

&lt;p&gt;Unlike its predecessors, which often felt like a black box of runtime magic, Byte Buddy is designed to be predictable. It doesn't try to hide the fact that it's generating a class; instead, it gives you a powerful, transparent set of tools to define exactly how that class should behave, ensuring compatibility with modern Java versions and the Module System.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fluent DSL: Subclass, Method, Intercept
&lt;/h3&gt;

&lt;p&gt;To create a proxy in Byte Buddy, you follow a flow that reads like a sentence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;subclass(Target.class)&lt;/code&gt;&lt;/strong&gt;: "I want a new class that extends Target."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;method(ElementMatcher)&lt;/code&gt;&lt;/strong&gt;: "I want to target these specific methods."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;intercept(Implementation)&lt;/code&gt;&lt;/strong&gt;: "When those methods are called, do &lt;em&gt;this&lt;/em&gt;."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ElementMatchers: The "SQL" of Methods
&lt;/h3&gt;

&lt;p&gt;One of the most powerful features of Byte Buddy is the &lt;code&gt;ElementMatchers&lt;/code&gt; library. Instead of messy &lt;code&gt;if&lt;/code&gt; statements, you select targets using declarative syntax like &lt;code&gt;named("save")&lt;/code&gt;, &lt;code&gt;isPublic()&lt;/code&gt;, or &lt;code&gt;isAnnotatedWith(Transactional.class)&lt;/code&gt;. These are composable using &lt;code&gt;.and()&lt;/code&gt; and &lt;code&gt;.or()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hands-on: Intercepting a UserService
&lt;/h3&gt;

&lt;p&gt;Let's build a real-world example. We have a &lt;code&gt;UserService&lt;/code&gt; and we want to measure the execution time of the &lt;code&gt;save()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Here is a minimal implementation that includes a basic dependency (a logger or simulated database) and a method that we can easily target for interception.&lt;br&gt;
&lt;/p&gt;

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

    &lt;span class="c1"&gt;// A concrete method with logic we want to 'wrap'&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&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="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&amp;gt;&amp;gt; UserService: Persisting user '"&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="s"&gt;"' to database..."&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="c1"&gt;// Simulate some network or disk latency&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&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;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;interrupt&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"SUCCESS: "&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="s"&gt;" is now in the system."&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 method we might want to ignore or match differently&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;delete&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="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&amp;gt;&amp;gt; UserService: Deleting user '"&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="s"&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;Here, we implement the &lt;code&gt;Interceptor&lt;/code&gt;, which is roughly equivalent to &lt;code&gt;InvocationHandler&lt;/code&gt; we wrote while creating a JDK Dynamic Proxy. The &lt;code&gt;Interceptor&lt;/code&gt; defines the "extra" logic that we want to inject in our proxy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;net.bytebuddy.implementation.bind.annotation.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.lang.reflect.Method&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.Callable&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PerformanceInterceptor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@RuntimeType&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;intercept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@Origin&lt;/span&gt; &lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;            &lt;span class="c1"&gt;// The method being called&lt;/span&gt;
        &lt;span class="nd"&gt;@SuperCall&lt;/span&gt; &lt;span class="nc"&gt;Callable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;zuper&lt;/span&gt;      &lt;span class="c1"&gt;// The original method logic&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;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;zuper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Execute super.save()&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="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&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="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" took "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"ms"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's dig into the code a bit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@Origin Method method&lt;/code&gt;: This is the standard &lt;code&gt;java.lang.reflect.Method&lt;/code&gt; object. It is Byte Buddy's way of handing you the "metadata" of the method being called. You can use this object to access the method name, its annotations, or its parameters without you doing any manual reflection.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@SuperCall Callable&amp;lt;?&amp;gt; zuper&lt;/code&gt;: This is the real secret sauce. Byte Buddy creates a special auxiliary class that knows how to call the original method in the parent class. By wrapping it in a &lt;code&gt;Callable&lt;/code&gt;, you can decide exactly when, or even if, the original logic should execute. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;try/finally&lt;/code&gt; block: This ensures that even if the original method throws an exception, our timer still finishes. It is the standard way to implement reliable "around advice" in the AOP world.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last step is actually creating the proxy using Byte Buddy. Here we instruct JVM to build a new type.&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;UserService&lt;/span&gt; &lt;span class="n"&gt;proxy&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;ByteBuddy&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subclass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ElementMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;named&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"save"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;intercept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MethodDelegation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PerformanceInterceptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;make&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserService&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;getClassLoader&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;ClassLoadingStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INWRAPPER&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLoaded&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredConstructor&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;newInstance&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Alice"&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 above snippet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.subclass(UserService.class)&lt;/code&gt;&lt;/strong&gt;: This tells Byte Buddy to generate a new class in memory that extends our &lt;code&gt;UserService&lt;/code&gt;. To the JVM, this new class is a legitimate child of the original.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.method(ElementMatchers.named("saveUser"))&lt;/code&gt;&lt;/strong&gt;: Think of this as a filter. Byte Buddy iterates through all methods available in the subclass and only applies our "advice" to the ones that pass this test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.intercept(MethodDelegation.to(PerformanceInterceptor.class))&lt;/code&gt;&lt;/strong&gt;: Here, we are "binding" the matched method to our interceptor. Byte Buddy is smart enough to see the annotations in our interceptor and figure out how to pass the right arguments into it at runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.load(...)&lt;/code&gt;&lt;/strong&gt;: This is the bridge to the JVM. We have the bytecode in a byte array, but to use it, we need to define it through a &lt;code&gt;ClassLoader&lt;/code&gt;. The &lt;code&gt;INWRAPPER&lt;/code&gt; strategy is the most common approach, as it loads the proxy in a child class loader of the original class, preventing class-loading conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.getLoaded().getDeclaredConstructor().newInstance()&lt;/code&gt;&lt;/strong&gt;: Finally, we treat the generated class like any other Java class. We grab its constructor and create an instance. This instance is what we pass around our application, and because of polymorphism, everyone thinks it's just a regular &lt;code&gt;UserService&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Did you notice that we only proxied the &lt;code&gt;save()&lt;/code&gt; method of &lt;code&gt;UserService&lt;/code&gt; and &lt;em&gt;not&lt;/em&gt; the &lt;code&gt;delete()&lt;/code&gt;? Well this is another advantage of using Byte Buddy. &lt;/p&gt;

&lt;p&gt;In a JDK proxy, you are forced into a single &lt;code&gt;InvocationHandler&lt;/code&gt; where you must handle &lt;em&gt;every&lt;/em&gt; method call (including &lt;code&gt;toString&lt;/code&gt;, &lt;code&gt;equals&lt;/code&gt;, etc.) in one giant &lt;code&gt;switch&lt;/code&gt; or &lt;code&gt;if&lt;/code&gt; block. Byte Buddy allows you to be surgical. You can apply different interceptors to different methods within the same proxy definition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Byte Buddy is the current standard
&lt;/h2&gt;

&lt;p&gt;When you run the code above, Byte Buddy generates a class at runtime that effectively overrides the save method. But unlike CGLIB, Byte Buddy's generated code is highly optimized. It uses "Inlining" where possible and avoids the heavy overhead of reflection during every method call.&lt;/p&gt;

&lt;p&gt;Furthermore, Byte Buddy handles the complexity of Java's Module System (Project Jigsaw) gracefully. It knows how to "open" packages or define classes in a way that doesn't trigger security exceptions on modern JVMs (Java 11, 17, and 21).&lt;/p&gt;

&lt;p&gt;In the next part, we'll look at how these libraries handle "Redefinition" and "Rebasing"—techniques that allow you to modify existing classes rather than just creating subclasses. This is where we move into the territory of Java Agents and serious performance monitoring tools. For now, try running the Byte Buddy example and see if you can add a matcher that intercepts all methods except for those starting with "get".&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>learning</category>
      <category>backend</category>
    </item>
    <item>
      <title>Proxies the Native Way: JDK Dynamic Proxies</title>
      <dc:creator>Rajat Arora</dc:creator>
      <pubDate>Mon, 05 Jan 2026 10:10:04 +0000</pubDate>
      <link>https://forem.com/rajatarora/proxies-the-native-way-jdk-dynamic-proxies-2pin</link>
      <guid>https://forem.com/rajatarora/proxies-the-native-way-jdk-dynamic-proxies-2pin</guid>
      <description>&lt;p&gt;Welcome back to our series on Java Proxies! If you've been following along, we've already discussed the conceptual &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;why&lt;/em&gt; of the Proxy Pattern, learned how to write a static proxy, introduced the idea behind dynamic proxies, and looked at how some of the Java giants like Spring, Hibernate, and Mockito use dynamic proxies to power features that you and I use every day.&lt;/p&gt;

&lt;p&gt;Now, it's time to roll up our sleeves and look at the first "real" tool in our kit: &lt;strong&gt;JDK Dynamic Proxies&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the native way to do things. No external libraries, no Maven dependencies, no other shenanigans. These are built right into the JDK in the &lt;code&gt;java.lang.reflect&lt;/code&gt; package. They're elegant, powerful, and a &lt;em&gt;tad&lt;/em&gt; bit opinionated. Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet &lt;code&gt;java.lang.reflect.Proxy&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In the early days of Java, if you wanted a proxy, you had to write it by hand. If you had 50 interfaces, you wrote 50 proxy classes. It was tedious, error-prone, and let's face it: a bit boring!&lt;/p&gt;

&lt;p&gt;Enter the &lt;strong&gt;Reflection API&lt;/strong&gt;. It gave Java the ability to look into a mirror. &lt;/p&gt;

&lt;p&gt;Just like you can inspect your face and your body by looking into a mirror, Reflection API allows a Java program to inspect its own classes, interfaces, fields, and methods at runtime. By using reflection, Java can "ask" an object what methods it has, and then execute them dynamically.&lt;/p&gt;

&lt;p&gt;The JDK Dynamic Proxy mechanism, introduced way back in JDK 1.3, allows you to create proxy instances at &lt;strong&gt;runtime&lt;/strong&gt;. Instead of a &lt;code&gt;.class&lt;/code&gt; file sitting on your disk for a specific proxy, the JVM generates the bytecode for the proxy class on the fly in memory.&lt;/p&gt;

&lt;p&gt;The star of the show is the &lt;code&gt;java.lang.reflect.Proxy&lt;/code&gt; class. It provides a static method that is the "Open Sesame" of the proxy world:&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;Object&lt;/span&gt; &lt;span class="nf"&gt;newProxyInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClassLoader&lt;/span&gt; &lt;span class="n"&gt;loader&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;interfaces&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nc"&gt;InvocationHandler&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think of this method as a factory. You give it a &lt;code&gt;ClassLoader&lt;/code&gt;, a list of interfaces you want the proxy to "pretend" to be, and a "brain" (the &lt;code&gt;InvocationHandler&lt;/code&gt;). In return, it hands you an object that implements all those interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  It does need an Interface
&lt;/h2&gt;

&lt;p&gt;Did you read the last paragraph carefully? &lt;em&gt;You give it a &lt;code&gt;ClassLoader&lt;/code&gt;, **a list of interfaces you want the proxy to "pretend" to be&lt;/em&gt;&lt;em&gt;, and a "brain" (the &lt;code&gt;InvocationHandler&lt;/code&gt;). In return, it hands you **an object that implements all those interfaces&lt;/em&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yes, JDK Dynamic Proxies have one non-negotiable rule. &lt;strong&gt;They only work with interfaces&lt;/strong&gt;. If you have a concrete class (say, &lt;code&gt;UserService&lt;/code&gt;) that doesn't implement an interface, the JDK Dynamic Proxy cannot help you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the Interface constraint?
&lt;/h3&gt;

&lt;p&gt;It comes down to two things: How JDK Dynamic Proxy creates the proxy class, and how Java handles inheritance.&lt;/p&gt;

&lt;p&gt;Java doesn't support multiple inheritance: You cannot create a class extending more than one parent class. However, a class &lt;em&gt;can&lt;/em&gt; implement multiple interfaces at the same time.&lt;/p&gt;

&lt;p&gt;The proxy classes created by JDK Dynamic Proxy &lt;em&gt;already&lt;/em&gt; extend &lt;code&gt;java.lang.reflect.Proxy&lt;/code&gt;. In order to be a drop-in replacement of your real class, they'd &lt;em&gt;also&lt;/em&gt; need to extend it: something that Java doesn't allow. So they do the next best thing. They implement the &lt;em&gt;same&lt;/em&gt; interface(s) implemented by your real class.&lt;/p&gt;

&lt;p&gt;This is why the &lt;code&gt;newProxyInstance&lt;/code&gt; method takes &lt;code&gt;Class&amp;lt;?&amp;gt;[] interfaces&lt;/code&gt; as one of its arguments. Your real class can implement multiple interfaces, hence all of those interfaces need to be passed on to the &lt;code&gt;newProxyInstance&lt;/code&gt; method in order for it to create the proxy class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the &lt;code&gt;InvocationHandler&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;If the &lt;code&gt;Proxy&lt;/code&gt; class is the body of our dynamic object, the &lt;code&gt;InvocationHandler&lt;/code&gt; is the brain.&lt;/p&gt;

&lt;p&gt;In a standard Java setup, when you call a method on an object, the JVM knows exactly where the method's code lives. But a dynamic proxy is created at runtime; it doesn't have its own hardcoded logic. It needs a &lt;em&gt;middleman&lt;/em&gt; to decide what happens when a method is triggered. That's why the &lt;code&gt;InvocationHandler&lt;/code&gt; is mandatory. It provides a centralized place to handle every single method call made to the proxy.&lt;/p&gt;

&lt;p&gt;It's interface is simple, just one method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                     &lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                     &lt;span class="nc"&gt;Object&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="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;proxy&lt;/code&gt; is the instance of the proxy itself, &lt;code&gt;method&lt;/code&gt; is an object representing the specific interface method being called, and &lt;code&gt;args&lt;/code&gt; is an array of objects containing the arguments to be passed to the method. &lt;/p&gt;

&lt;p&gt;Because every method call to the proxy funnels through this single point, you have total control. You can define the dynamic proxy's behavior by providing your own implementation of the &lt;code&gt;InvocationHandler&lt;/code&gt; interface, and by doing so, you can inject functionality &lt;em&gt;before&lt;/em&gt; or &lt;em&gt;after&lt;/em&gt; the actual method call. &lt;/p&gt;

&lt;p&gt;Moreover, you can even decide whether you &lt;em&gt;want&lt;/em&gt; to call the actual method or not. For example, for dynamic proxies created for &lt;code&gt;Mockito.spy()&lt;/code&gt;, the actual method is called &lt;em&gt;only if&lt;/em&gt; there isn't a subbing present for it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Be careful, though
&lt;/h3&gt;

&lt;p&gt;You might have noticed that &lt;code&gt;invoke()&lt;/code&gt; takes an instance of &lt;code&gt;proxy&lt;/code&gt; as one of its arguments. It might be tempting for you to use it inside the &lt;code&gt;InvocationHandler&lt;/code&gt; - but be very careful.&lt;/p&gt;

&lt;p&gt;If you call a method &lt;strong&gt;on the proxy instance itself&lt;/strong&gt; inside the &lt;code&gt;invoke&lt;/code&gt; method (for example, &lt;code&gt;proxy.toString()&lt;/code&gt;), the JVM will intercept &lt;em&gt;that&lt;/em&gt; call too and send it right back to &lt;code&gt;invoke&lt;/code&gt;. This creates an infinite loop that ends in the dreaded &lt;code&gt;StackOverflowError&lt;/code&gt;. Usually, if you need to call a method, you should call it on the &lt;strong&gt;target&lt;/strong&gt; (the real object), not the proxy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-on: Building a Generic &lt;code&gt;LoggingHandler&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Enough theory, isn't it? Now let's &lt;em&gt;build something!&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Let's build a dynamic proxy that logs the execution time and arguments of every method call in your application... &lt;em&gt;without&lt;/em&gt; sprinkling &lt;code&gt;log.info()&lt;/code&gt; statements everywhere. We'll create an &lt;code&gt;InvocationHandler&lt;/code&gt; implementation that does that, and then use it to create a proxy for a real class containing business logic. Here goes:&lt;/p&gt;

&lt;p&gt;First of all, let's build an &lt;code&gt;InvocationHandler&lt;/code&gt; implementation that logs the arguments and execution time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.lang.reflect.InvocationHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.lang.reflect.Method&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Arrays&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.slf4j.Logger&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.slf4j.LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoggingHandler&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;InvocationHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LoggingHandler&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="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;LoggingHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;target&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;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&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="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&amp;gt;&amp;gt; Entering: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&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;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&amp;gt;&amp;gt; Arguments: {}"&lt;/span&gt;&lt;span class="o"&gt;,&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="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="s"&gt;"[]"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nanoTime&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// This is where we call the ACTUAL method on the ACTUAL object&lt;/span&gt;
        &lt;span class="nc"&gt;Object&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;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&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="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nanoTime&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&amp;gt;&amp;gt; Result: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&amp;gt;&amp;gt; Time taken: {}ns"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's decode what's happening in the above piece of code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We created a class &lt;code&gt;LoggingHandler&lt;/code&gt; that &lt;code&gt;implements InvocationHandler&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;We overrode &lt;code&gt;invoke()&lt;/code&gt;, and inside, we wrapped the actual method call - &lt;code&gt;method.invoke(target, args)&lt;/code&gt; with logging statements that specified entry, exit, and execution time of the method. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;result&lt;/code&gt; returned by the actual method call was also returned by &lt;code&gt;invoke()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that we haven't defined our business logic as yet. The &lt;em&gt;dynamic&lt;/em&gt; nature of this proxy means that &lt;em&gt;any&lt;/em&gt; suitable Java method can be proxied and passed on to &lt;code&gt;invoke()&lt;/code&gt; to log its vitals.&lt;/p&gt;

&lt;p&gt;Anyway, let's now build a simple calculator to show this dynamic proxy in action.&lt;/p&gt;

&lt;p&gt;As required by JDK Dynamic Proxy, let's define an interface first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Calculator&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;add&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;a&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;b&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;multiply&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;a&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;b&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;And a simple, bare-bones 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;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RealCalculator&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Calculator&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;int&lt;/span&gt; &lt;span class="nf"&gt;add&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;a&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;b&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;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;multiply&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;a&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;b&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;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's put this all together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// 1. Create the real object&lt;/span&gt;
        &lt;span class="nc"&gt;Calculator&lt;/span&gt; &lt;span class="n"&gt;realCalc&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;RealCalculator&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Create the logging handler&lt;/span&gt;
        &lt;span class="nc"&gt;LoggingHandler&lt;/span&gt; &lt;span class="n"&gt;handler&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;LoggingHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;realCalc&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 3. Create the Proxy&lt;/span&gt;
        &lt;span class="nc"&gt;Calculator&lt;/span&gt; &lt;span class="n"&gt;proxyCalc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Calculator&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newProxyInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;Calculator&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;getClassLoader&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;Class&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Calculator&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;handler&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 4. Use the proxy!&lt;/span&gt;
        &lt;span class="kt"&gt;int&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;proxyCalc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&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;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proxyCalc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&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;If you execute the &lt;code&gt;Main&lt;/code&gt; class now, you will see logging statements detailing the entry, exit, and time taken for both &lt;code&gt;add()&lt;/code&gt; and &lt;code&gt;multiply()&lt;/code&gt; methods. &lt;/p&gt;

&lt;p&gt;Notice how we didn't add any logging statements to the real &lt;code&gt;add()&lt;/code&gt; and &lt;code&gt;multiply()&lt;/code&gt; methods - the proxy took care of it! When you called &lt;code&gt;proxyCalc.add(5, 10)&lt;/code&gt;, the JVM didn't go to &lt;code&gt;RealCalculator&lt;/code&gt;. It went to &lt;code&gt;LoggingHandler&lt;/code&gt;. The handler printed the logs, then used Reflection (&lt;code&gt;method.invoke&lt;/code&gt;) to call the real &lt;code&gt;add&lt;/code&gt; method on &lt;code&gt;realCalc&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Considerations
&lt;/h2&gt;

&lt;p&gt;A common question is: &lt;em&gt;"Is this slow?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the early days of Java, Reflection was indeed slow. However, modern JVMs are incredibly good at optimizing Dynamic Proxies. After a few calls, the JIT (Just-In-Time) compiler can often inline these calls, making the overhead negligible for most business applications.&lt;/p&gt;

&lt;p&gt;That said, if you are calling a method millions of times per second in a tight loop, you might want to measure the impact. But for 99% of use cases (Spring &lt;code&gt;@Transactional&lt;/code&gt;, Hibernate Lazy Loading, etc.), it's plenty fast!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;The JDK Dynamic Proxy is a beautiful example of the "Open-Closed Principle" in action. You can add behavior (logging, security, caching) to any interface without changing a single line of the original code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Built-in:&lt;/strong&gt; No extra libraries needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface-based:&lt;/strong&gt; Your target must implement an interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralized:&lt;/strong&gt; All calls go through one &lt;code&gt;InvocationHandler&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next part of this series, we’ll tackle the limitation we found today: &lt;strong&gt;What if we don't have an interface?&lt;/strong&gt; That's where &lt;strong&gt;CGLIB&lt;/strong&gt; and &lt;strong&gt;Byte Buddy&lt;/strong&gt; enter the ring. Stay tuned!&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>backend</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Magic in the Wild: How Java Giants like Spring, Hibernate, and Mockito use Dynamic Proxies</title>
      <dc:creator>Rajat Arora</dc:creator>
      <pubDate>Thu, 01 Jan 2026 14:59:53 +0000</pubDate>
      <link>https://forem.com/rajatarora/magic-in-the-wild-how-java-giants-like-spring-hibernate-and-mockito-use-dynamic-proxies-3khc</link>
      <guid>https://forem.com/rajatarora/magic-in-the-wild-how-java-giants-like-spring-hibernate-and-mockito-use-dynamic-proxies-3khc</guid>
      <description>&lt;p&gt;Welcome to the second installment of the series: Java Proxies Unmasked. In the &lt;a href="https://dev.to/rajatarora/understanding-proxy-patterns-the-why-and-how-of-static-and-dynamic-proxies-in-java-h1g"&gt;previous post&lt;/a&gt;, we learned about the classic Proxy pattern. We built a Static Proxy and realized that while it works for a simple example, it doesn't scale. Nobody wants to write a static proxy for every relevant class in their codebase.&lt;/p&gt;

&lt;p&gt;We then teased the idea of Dynamic Proxies, which gave us a way to generate those proxies at runtime. They solved the N+1 problem plaguing static proxies and enabled us to write hundreds of them in few lines of code. But before we delve into the area further, we need to understand "why".&lt;/p&gt;

&lt;p&gt;In this post, we're going to pull back the curtain from some of the widely used frameworks and libraries - Spring, Hibernate, and Mockito, and see how they use dynamic proxies to power features that a modern Java developer uses every day.&lt;/p&gt;

&lt;p&gt;If you've ever felt that these frameworks do &lt;strong&gt;magic&lt;/strong&gt;, today is the day we reveal their secrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spring AOP: The &lt;code&gt;@Transactional&lt;/code&gt; Onion
&lt;/h2&gt;

&lt;p&gt;The most common place you'll encounter a proxy in Spring Framework is with the &lt;code&gt;@Transactional&lt;/code&gt; annotation. To us, it's a single line of code. To Spring, it is a signal to wrap the bean in a complex "Proxy Onion". When you call a method marked with &lt;code&gt;@Transactional&lt;/code&gt;, you aren't actually calling your code directly. You are calling a proxy that manages the lifecycle of a database connection.&lt;/p&gt;

&lt;p&gt;To understand how this proxy is created, we have to look at the factory worker of the Spring container, the &lt;strong&gt;Bean Post-Processor&lt;/strong&gt;. This processor puts your class through a multi-step transformation process during the Context Refresh phase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Discovery &amp;amp; Pointcut Matching
&lt;/h3&gt;

&lt;p&gt;As your application starts, Spring scans for beans. When it finds a class with &lt;code&gt;@Transactional&lt;/code&gt;, a specialized component called the &lt;code&gt;InfrastructureAdvisorAutoProxyCreator&lt;/code&gt; steps in. It asks two questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Does this bean have a "Pointcut" match?&lt;/strong&gt; (e.g., Is it annotated with &lt;code&gt;@Transactional&lt;/code&gt;?)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What "Advice" should I apply?&lt;/strong&gt; (In this case, the &lt;code&gt;TransactionInterceptor&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Creation Phase (The Wrapper)
&lt;/h3&gt;

&lt;p&gt;Once Spring decides a proxy is needed, it uses a &lt;code&gt;ProxyFactory&lt;/code&gt;. Depending on your configuration and class structure, it chooses one of two paths:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;JDK Dynamic Proxy&lt;/strong&gt;: If your service implements an interface (e.g., &lt;code&gt;UserServiceImpl&lt;/code&gt; implements &lt;code&gt;UserService&lt;/code&gt;), Spring creates a proxy using the standard Java &lt;code&gt;reflect.Proxy&lt;/code&gt; API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CGLIB Proxy&lt;/strong&gt;: If your service is a concrete class with no interface, Spring uses CGLIB to generate a subclass of your bean at runtime.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;We will take a look at JDK Dynamic Proxies in the next post. CGLIB (Code Generation Library) is an old technology, so we'll skip it in favor of ByteBuddy as we move further along.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Call in Action
&lt;/h3&gt;

&lt;p&gt;When a client calls your service, it doesn't hit your code first. It hits the Proxy's &lt;code&gt;invoke()&lt;/code&gt; or &lt;code&gt;intercept()&lt;/code&gt; methods. Here's how the sequence of events looks:&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%2Fg59ikf30g9j2tsah9nnk.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%2Fg59ikf30g9j2tsah9nnk.png" alt="Proxies in action in Spring's @Transactional" width="800" height="1140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Secret Sauce&lt;/strong&gt;: &lt;code&gt;TransactionAspectSupport&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to see the real "engine room," look at the &lt;code&gt;TransactionAspectSupport.java&lt;/code&gt; in the Spring source code. Specifically, the &lt;code&gt;invokeWithinTransaction&lt;/code&gt; method. This is where the actual &lt;code&gt;try-catch&lt;/code&gt; block lives that wraps your code!&lt;/p&gt;

&lt;p&gt;This is also why self-invocation doesn't work. If a method inside your &lt;code&gt;UserService&lt;/code&gt; calls another &lt;code&gt;@Transactional&lt;/code&gt; method in the same class using &lt;code&gt;this.otherMethod()&lt;/code&gt;, the call never goes through the proxy "bouncer"—it stays inside the real object, and the transaction logic is skipped entirely!&lt;/p&gt;

&lt;h2&gt;
  
  
  Hibernate: When Loading is Lazy
&lt;/h2&gt;

&lt;p&gt;Hibernate uses proxies to solve a massive performance problem: &lt;strong&gt;Lazy Loading&lt;/strong&gt;. Imagine a &lt;code&gt;User&lt;/code&gt; entity that has a &lt;code&gt;List&amp;lt;Order&amp;gt;&lt;/code&gt;. A user may have placed hundreds of orders in the system, but we don't need them every time we fetch the user's details. Maybe we just need their name for an email campaign. If Hibernate loaded everything every time, &lt;em&gt;your database would crawl to a halt.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Instead, Hibernate defaults to lazy loading for &lt;code&gt;@OneToMany&lt;/code&gt; and &lt;code&gt;@ManyToMany&lt;/code&gt; associations. It returns &lt;strong&gt;Hollow Objects&lt;/strong&gt; whose data is fetched only when it is accessed by your code. &lt;/p&gt;

&lt;h3&gt;
  
  
  The birth of a Proxy
&lt;/h3&gt;

&lt;p&gt;Hibernate uses &lt;strong&gt;Byte Buddy&lt;/strong&gt; to generate a new class at Runtime that extends your entity. If you have an &lt;code&gt;Order&lt;/code&gt; class, Hibernate generates a class that looks something like &lt;code&gt;Order$HibernateProxy$Q4X0SwcL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This generated subclass contains a special field: &lt;code&gt;LazyInitializer&lt;/code&gt;. This is the "brain" of the proxy. It stores:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;Entity ID&lt;/strong&gt;, which is knows immediately&lt;/li&gt;
&lt;li&gt;A reference to the &lt;strong&gt;Hibernate Session&lt;/strong&gt;, to fetch data later&lt;/li&gt;
&lt;li&gt;Overridden &lt;strong&gt;Accessor Methods&lt;/strong&gt;. These trigger SQL queries when they are accessed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy Initialization Logic&lt;/strong&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Call in Action
&lt;/h3&gt;

&lt;p&gt;When you call an accessor method (like, a getter) on this proxy, Byte Buddy intercepts the call. It checks if the proxy object already as the data. If not, it "hydrates" the object (i.e. fetches the data) by running an SQL query. &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%2F1lzkgxbb9610y70qqnxq.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%2F1lzkgxbb9610y70qqnxq.png" alt="How Hibernate's Lazy Loading feature uses dynamic proxies" width="800" height="842"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Secret Sauce: &lt;code&gt;ProxyConfiguration&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;If you want to see where Hibernate configures this bytecode "sorcery", check out the &lt;a href="https://www.google.com/search?q=https://github.com/hibernate/hibernate-orm/blob/main/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyProxyFactory.java" rel="noopener noreferrer"&gt;ByteBuddyProxyFactory.java&lt;/a&gt; in the Hibernate source code. This is the factory that tells Byte Buddy exactly how to build that hollow subclass and how to hook the getters and setters to the &lt;a href="https://www.google.com/search?q=https://github.com/hibernate/hibernate-orm/blob/main/hibernate-core/src/main/java/org/hibernate/proxy/LazyInitializer.java" rel="noopener noreferrer"&gt;LazyInitializer&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mockito's Secret Agent: The spy()
&lt;/h2&gt;

&lt;p&gt;A Mockito &lt;strong&gt;Spy&lt;/strong&gt; is a special type of test double that wraps a &lt;strong&gt;real object&lt;/strong&gt;. Unlike a regular mock that starts with no behavior, a spy delegates method calls to the actual underlying object unless you specifically stub (override) certain methods.&lt;/p&gt;

&lt;p&gt;In simple words, if you don't tell the spy what to do, it simply passes the call through to the real method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;spyList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Create a proxy around a real list&lt;/span&gt;

&lt;span class="c1"&gt;// This call is intercepted by the proxy, but since &lt;/span&gt;
&lt;span class="c1"&gt;// we didn't stub it, it delegates to the REAL ArrayList.size()&lt;/span&gt;
&lt;span class="n"&gt;spyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 

&lt;span class="c1"&gt;// Now we "stub" the proxy to lie to us&lt;/span&gt;
&lt;span class="n"&gt;doReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spyList&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;spyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Returns 100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Subclassing the Real Thing
&lt;/h3&gt;

&lt;p&gt;When you call &lt;code&gt;Mockito.spy(myObject)&lt;/code&gt;, Mockito doesn't just wrap the instance; it uses &lt;strong&gt;Byte Buddy&lt;/strong&gt; to create a new class at runtime that &lt;strong&gt;extends&lt;/strong&gt; your object's class.&lt;/p&gt;

&lt;p&gt;If your class is &lt;code&gt;PaymentService&lt;/code&gt;, Mockito creates &lt;code&gt;PaymentService$MockitoMock$cG76HxJ8v&lt;/code&gt;. It then copies the state (the fields) from your real object into this new proxy instance. This is how you can spy on existing objects!&lt;/p&gt;

&lt;h3&gt;
  
  
  The Brain: &lt;code&gt;MockMethodInterceptor&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Every method in this generated subclass is overridden to call a single dispatcher: the &lt;code&gt;MockMethodInterceptor&lt;/code&gt;. This interceptor holds a "Registry" of all your stubbing instructions (e.g., &lt;code&gt;when(...).thenReturn(...)&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Call in Action: To Real or Not to Real?
&lt;/h3&gt;

&lt;p&gt;When you call a method on a spy, the proxy has to make a split-second decision: &lt;em&gt;"Do I run the real code, or do I return a canned answer?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0vi52y5e0ft1xlznohht.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%2F0vi52y5e0ft1xlznohht.png" alt="Mockito's spy() using proxies" width="800" height="976"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Gotcha": &lt;code&gt;when()&lt;/code&gt; vs. &lt;code&gt;doReturn()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This proxy mechanism explains a famous Mockito trap.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you use &lt;code&gt;when(spy.get(0)).thenReturn("foo")&lt;/code&gt;, the proxy &lt;strong&gt;actually calls the real &lt;code&gt;get(0)&lt;/code&gt; method&lt;/strong&gt; once before the stubbing is applied. if the list is empty, it throws an &lt;code&gt;IndexOutOfBoundsException&lt;/code&gt;!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you use &lt;code&gt;doReturn("foo").when(spy).get(0)&lt;/code&gt;, you are talking to the proxy's "settings" directly. The real method is &lt;strong&gt;never&lt;/strong&gt; called.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Secret Sauce: &lt;code&gt;InvocationContainer&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to see how Mockito tracks these calls, look at &lt;a href="https://www.google.com/search?q=https://github.com/mockito/mockito/blob/main/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java" rel="noopener noreferrer"&gt;InvocationContainerImpl.java&lt;/a&gt;. It’s the ledger that stores every method call made to the proxy, which is what allows you to later call &lt;code&gt;verify(spy).add(anyString())&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Whether it's Spring managing your transactions, Hibernate saving you memory, or Mockito helping you test, the secret ingredient is &lt;strong&gt;Interception&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Proxies allow these frameworks to "hook" into your method calls and execute their own logic without you ever having to change your source code. This is the essence of &lt;strong&gt;Declarative Programming&lt;/strong&gt;: you declare the intent (via annotations), and the proxy handles the mechanics.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s Next?
&lt;/h3&gt;

&lt;p&gt;We’ve seen the magic in action. Now, it’s time to become the magician. In the next post, we are going to build our very first dynamic proxy using nothing but the standard JDK. No libraries, no Maven dependencies—just pure Java.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3: The Native Way&lt;/strong&gt; is where we write our first &lt;code&gt;InvocationHandler&lt;/code&gt;. Get your IDE ready!&lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>hibernate</category>
      <category>mockito</category>
    </item>
    <item>
      <title>Understanding Proxy Patterns: The Why and How of Static and Dynamic Proxies in Java</title>
      <dc:creator>Rajat Arora</dc:creator>
      <pubDate>Mon, 29 Dec 2025 10:49:14 +0000</pubDate>
      <link>https://forem.com/rajatarora/understanding-proxy-patterns-the-why-and-how-of-static-and-dynamic-proxies-in-java-h1g</link>
      <guid>https://forem.com/rajatarora/understanding-proxy-patterns-the-why-and-how-of-static-and-dynamic-proxies-in-java-h1g</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/rajatarora/the-proxy-paradox-why-spring-transactional-vanishes-4758"&gt;previous&lt;/a&gt; post, we talked about Spring's &lt;code&gt;@Transactional&lt;/code&gt; annotation, and saw how it does its magic with Spring AOP, thanks to the unsung hero working behind the scenes: dynamic proxies.&lt;/p&gt;

&lt;p&gt;That got me thinking: why stop there? Proxies are used all the time in Spring, so why not do a &lt;em&gt;deeper&lt;/em&gt; dive under the hood to understand how they work?&lt;/p&gt;

&lt;p&gt;So today, I’m excited to kick off a series of posts dedicated to unlocking the power of dynamic proxies! Think of them as your secret weapon for writing cleaner code. You can package up all that repetitive boilerplate just &lt;strong&gt;once&lt;/strong&gt;, and then use simple annotations to sprinkle the functionality anywhere you need it. It’s like writing a superpower and then handing it out to your entire codebase.&lt;/p&gt;

&lt;p&gt;We’ll start our journey with the classic &lt;a href="https://en.wikipedia.org/wiki/Proxy_pattern" rel="noopener noreferrer"&gt;Proxy pattern&lt;/a&gt; from the Gang of Four's famous book, &lt;em&gt;&lt;a href="https://en.wikipedia.org/wiki/Design_Patterns" rel="noopener noreferrer"&gt;Design Patterns&lt;/a&gt;&lt;/em&gt;. We'll connect the dots between this pattern and the dynamic proxies that frameworks like Spring use every day. To make sure we’re all on the same page, we’ll even build a simple static proxy together first.&lt;/p&gt;

&lt;p&gt;And because the best way to learn is by doing, we'll do a capstone project at the end, where we will build our own annotation: &lt;code&gt;@MyTransactional&lt;/code&gt;, mimicking the functionality of Spring's &lt;code&gt;@Transactional&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, whether you're completely new to proxies or you're looking to get handy with advanced tools like ByteBuddy, pull up a chair! I hope this series will be a friendly and practical guide for you, and you'll have a better understanding of dynamic proxies at the end.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's start with the Proxy Pattern
&lt;/h3&gt;

&lt;p&gt;A proxy is used when you want to add a layer of control between the client calling a method and the actual object (the "Real Subject") executing it. At its core, the Proxy Pattern provides an object that represents another object.&lt;/p&gt;

&lt;p&gt;If that sounds a bit abstract, no worries—let's break it down with an example.&lt;/p&gt;

&lt;p&gt;Imagine you have a &lt;strong&gt;Client&lt;/strong&gt; who wants to use a service, which we'll call the &lt;strong&gt;Subject&lt;/strong&gt;. Normally, the Client could just talk directly to the Subject to get what it needs.&lt;/p&gt;

&lt;p&gt;Now, let's say our &lt;strong&gt;Subject&lt;/strong&gt; is actually an interface. The real work is performed by a class called the &lt;strong&gt;Real Subject&lt;/strong&gt;, which implements that interface.&lt;/p&gt;

&lt;p&gt;This is where our &lt;strong&gt;Proxy&lt;/strong&gt; comes in! It steps in between the Client and the Real Subject. When the Client calls a method on the Subject, the Proxy intercepts that call &lt;em&gt;before&lt;/em&gt; it reaches the Real Subject. This gives the Proxy a chance to do some extra work either before passing the request along or after getting the result back.&lt;/p&gt;

&lt;p&gt;So, what kind of "extra work" can this proxy do? Lots of useful things!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Playing Bouncer (Access Control):&lt;/strong&gt; "Hold on, do you have the right permissions to make this call?"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Being Lazy (Lazy Initialization):&lt;/strong&gt; "I won't create this heavy object (like a huge file or database connection) until I absolutely have to."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Being a Messenger (Remote Invocation):&lt;/strong&gt; "The real object is actually on another machine? No problem, I'll handle the long-distance communication for you."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling the Annoying Stuff (Cross-Cutting Concerns):&lt;/strong&gt; "I'll automatically take care of logging, caching, or starting a transaction so the main object doesn't have to."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The beauty of all this? Your &lt;strong&gt;Real Subject&lt;/strong&gt; can stay clean and focused purely on the business logic. All the other important but repetitive tasks are handled by the proxy. It’s like having a dedicated assistant that takes care of all the prep work and clean-up!&lt;/p&gt;

&lt;h3&gt;
  
  
  Building a Static Proxy
&lt;/h3&gt;

&lt;p&gt;Alright, we've learned what a Proxy is. Now let's roll up our sleeves and build one together in Java!&lt;/p&gt;

&lt;p&gt;First up, we need to define our &lt;strong&gt;Subject&lt;/strong&gt;. Think of this as the contract for a service our client wants to use.&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;Subject&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;execute&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 simple interface has just one method: &lt;code&gt;execute()&lt;/code&gt;. Next, let's create the real deal, our &lt;strong&gt;RealSubject&lt;/strong&gt;, which does the actual heavy lifting:&lt;br&gt;
&lt;/p&gt;

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

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Performing an expensive operation."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// an operation&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;And now for the star of the show: the &lt;strong&gt;Proxy&lt;/strong&gt; itself! It also implements the &lt;code&gt;Subject&lt;/code&gt; interface, acting as a helpful middleman.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SubjectProxy&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Subject&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;RealSubject&lt;/span&gt; &lt;span class="n"&gt;realSubject&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;RealSubject&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Proxy intercepting Real Subject's operation"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// logging the method call&lt;/span&gt;
        &lt;span class="c1"&gt;// passing control to real subject  &lt;/span&gt;
        &lt;span class="n"&gt;realSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&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;Finally, our client code simply interacts with the proxy, blissfully unaware of the extra steps happening behind the scenes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;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;Subject&lt;/span&gt; &lt;span class="n"&gt;subject&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;SubjectProxy&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;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the beauty of the proxy is its ability to seamlessly add its own functionality before or after the real method is called. And just like that, you've created a clever helper that can manage, secure, or monitor access without changing the real object!&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem with Doing it Manually
&lt;/h3&gt;

&lt;p&gt;Our &lt;code&gt;SubjectProxy&lt;/code&gt; works great for a simple example. But imagine you’re working on a massive enterprise application with hundreds of services. If you wanted to add logging or transaction management to every single one of them using this "static" approach, you’d have to write a separate proxy class for every single service interface.&lt;/p&gt;

&lt;p&gt;That’s a lot of boilerplate! It’s tedious, error-prone, and—let’s be honest—not very "engineer-y." This is what we call the N+1 Class Problem: for every business class you write, you’re forced to write a corresponding proxy class.&lt;/p&gt;

&lt;p&gt;There has to be a better way, right?&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter the Dynamic Proxy: The Automated Middleman
&lt;/h3&gt;

&lt;p&gt;If static proxies are like hand-writing a custom contract for every single person you meet, Dynamic Proxies are like having a smart template that writes itself the moment it’s needed.&lt;/p&gt;

&lt;p&gt;The core idea is simple: instead of us writing &lt;code&gt;SubjectProxy.java&lt;/code&gt;, we tell the Java Virtual Machine (JVM) at runtime: &lt;em&gt;"Hey, I need an object that looks like this interface, but whenever someone calls a method on it, send that call to this single 'Handler' class I've written."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To give you a little teaser, here is how you create a dynamic proxy in just a few lines of code using the built-in JDK tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Our single "Handler" that handles EVERY method call for EVERY interface&lt;/span&gt;
&lt;span class="nc"&gt;InvocationHandler&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dynamic Proxy intercepting: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;method&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;realSubject&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// The Magic: Creating the proxy instance on the fly&lt;/span&gt;
&lt;span class="nc"&gt;Subject&lt;/span&gt; &lt;span class="n"&gt;dynamicProxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newProxyInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Subject&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;getClassLoader&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;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;[]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Subject&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;handler&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;dynamicProxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// This call is intercepted by our handler!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't worry if this code seems unfamiliar to you. We'll get to know more about JDK dynamic proxies further along in the series. But do notice their power here: we didn't write a class called &lt;code&gt;SubjectProxy&lt;/code&gt;. We generated it while the program was running. If we had 100 different interfaces, we could use this same logic to handle all of them. &lt;em&gt;No more N+1 problem.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary &amp;amp; What's Next
&lt;/h3&gt;

&lt;p&gt;We’ve traveled from the classic design pattern to the reality of "manual labor" with static proxies. We’ve also seen a glimpse of how Java allows us to generate these middlemen dynamically to save us from drowning in boilerplate.&lt;/p&gt;

&lt;p&gt;But is this just a neat trick for lazy developers? Far from it.&lt;/p&gt;

&lt;p&gt;In the next post, we’re going to step out of our "Hello World" examples and look at &lt;strong&gt;Real-World Magic&lt;/strong&gt;. We will do a deep dive into how the giants of the Java ecosystem: Spring, Hibernate, and Mockito, use these dynamic proxies to power the features we use every day. We’ll look at how the &lt;code&gt;@Transactional&lt;/code&gt; annotation works under the hood using proxies, how Hibernate manages to load data only when you ask for it, and how Mockito is able to &lt;em&gt;simulate&lt;/em&gt; a method call and return mocked data.&lt;/p&gt;

&lt;p&gt;Stay tuned for Part 2. It’s going to get interesting!&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>The Proxy Paradox: Why Spring @Transactional Vanishes</title>
      <dc:creator>Rajat Arora</dc:creator>
      <pubDate>Wed, 24 Dec 2025 06:30:02 +0000</pubDate>
      <link>https://forem.com/rajatarora/the-proxy-paradox-why-spring-transactional-vanishes-4758</link>
      <guid>https://forem.com/rajatarora/the-proxy-paradox-why-spring-transactional-vanishes-4758</guid>
      <description>&lt;p&gt;We've all been there. You annotate &lt;code&gt;@Transactional&lt;/code&gt; on a critical method in your Spring application, run &lt;code&gt;mvn test&lt;/code&gt;, watch the green checkmarks fly by, and feel good about yourself. &lt;em&gt;Everything's going swell innit?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But then you open the transaction log and find... &lt;em&gt;nothing.&lt;/em&gt; Where did your transaction go?&lt;/p&gt;

&lt;p&gt;No connection enlisted. No timeout. No rollback on error. The code &lt;em&gt;did&lt;/em&gt; execute, but a transaction was not created.&lt;/p&gt;

&lt;p&gt;Congratulations, you've just met the &lt;strong&gt;Proxy Paradox&lt;/strong&gt;. The coding equivalent to plugging in your phone overnight and waking up to 7% battery.&lt;/p&gt;

&lt;p&gt;Stick around for a few minutes, and you'll know why this happens, and how to mitigate this behavior with some well-known patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Spring AOP
&lt;/h2&gt;

&lt;p&gt;The seeds of this bug are planted in Spring's Aspect Oriented Programming (AOP). &lt;/p&gt;

&lt;p&gt;In Spring, AOP is used to decouple cross-cutting concerns (like logging, security, or transactions) from your core business logic to keep code modular. It achieves this by wrapping your beans in &lt;strong&gt;dynamic proxies&lt;/strong&gt; that intercept method calls to inject this extra behavior at runtime -- without modifying the original code.&lt;/p&gt;

&lt;p&gt;Spring AOP is how &lt;code&gt;@Transactional&lt;/code&gt; annotation works in the first place. &lt;/p&gt;

&lt;p&gt;When a Spring container starts up, it scans your beans. It asks, &lt;em&gt;"Hey, does this class have any aspect-related annotations, like &lt;code&gt;@Transactional&lt;/code&gt;, &lt;code&gt;@Async&lt;/code&gt;, or &lt;code&gt;@Cacheable&lt;/code&gt;?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If the answer is yes, it doesn't give you the raw bean. It wraps that bean in a proxy (either a JDK dynamic proxy or a CGLIB-generated subclass). This wrapper intercepts calls from the outside world and funnels them through an &lt;em&gt;interceptor chain&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;However, the interceptor chain does not come into picture if a call comes &lt;em&gt;internally&lt;/em&gt;, i.e., from within the class.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bug in Action
&lt;/h2&gt;

&lt;p&gt;Take a look at this code snippet:&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;WalletService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// The entry point&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;pay&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// The internal call causing the issue&lt;/span&gt;
        &lt;span class="n"&gt;withdrawMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Transactional&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;withdrawMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ... complex logic with database writes ...&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, &lt;code&gt;withdrawMoney()&lt;/code&gt; is marked &lt;code&gt;@Transactional&lt;/code&gt;. Any calls to this method from outside of &lt;code&gt;WalletService&lt;/code&gt; (say, a controller) work as expected. The call goes through the proxy, &lt;strong&gt;a transaction is started&lt;/strong&gt;, and then the raw bean's method is executed. &lt;/p&gt;

&lt;p&gt;However, if the call to &lt;code&gt;withdrawMoney()&lt;/code&gt; comes through &lt;code&gt;pay()&lt;/code&gt;, it executes &lt;strong&gt;non-transactionally&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why? Because the call to &lt;code&gt;withdrawMoney()&lt;/code&gt; happens &lt;em&gt;inside&lt;/em&gt; the raw bean, bypassing the proxy completely. Spring's &lt;code&gt;TransactionInterceptor&lt;/code&gt; never comes into picture. No connection is bound to the thread. No commit. No rollback.&lt;/p&gt;

&lt;h2&gt;
  
  
  But... sometimes it works!
&lt;/h2&gt;

&lt;p&gt;If you have a colleague who claims that this works, they're probably using &lt;strong&gt;AspectJ Load-Time Weaving&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@EnableTransactionManagement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AdviceMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ASPECTJ&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AspectJ is different. It doesn't use proxies; it modifies the actual bytecode of your class during class loading. It literally weaves the transaction logic &lt;em&gt;into&lt;/em&gt; your original method.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; Self-invocation works perfectly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; Requires a special Java agent, adds complexity to the build process, increases startup time, and is generally overkill for standard web apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical Fixes
&lt;/h2&gt;

&lt;p&gt;So, you're stuck with the proxy issue. How do you fix it? Here are the top 5 solutions, ranked from "Best Practice" to "Please Don't Do This":&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Refactor (Recommended)
&lt;/h3&gt;

&lt;p&gt;Move &lt;code&gt;withdrawMoney()&lt;/code&gt; to its own &lt;code&gt;@Service&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="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentService&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;WalletService&lt;/span&gt; &lt;span class="n"&gt;walletService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Inject dependency&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;pay&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;walletService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withdrawMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// External 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;This is the cleanest solution. It fits SOLID principles, and makes unit testing much easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Self-Injection
&lt;/h3&gt;

&lt;p&gt;You can actually ask Spring to inject the proxy into the bean itself:&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;WalletService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Lazy&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;WalletService&lt;/span&gt; &lt;span class="n"&gt;self&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;pay&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withdrawMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Goes through the proxy&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 works, but feels weird. It also makes use of &lt;a href="https://dev.to/rajatarora/the-dependency-injection-dilemma-why-im-finally-ghosting-autowired-on-fields-5fba"&gt;Field Injection&lt;/a&gt;, which is not considered a best practice.&lt;/p&gt;

&lt;p&gt;This approach will not work at all if you use Constructor Injection (you will be hit with circular reference errors).&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Programmatic Transactions
&lt;/h3&gt;

&lt;p&gt;Why not introduce an explicit transaction?&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;transactionTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;withdrawMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&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;This is the easiest and simplest fix. It does add some boilerplate code, but clarity beats magic any day.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. AopContext.currentProxy()
&lt;/h3&gt;

&lt;p&gt;Force the method call through the AOP Proxy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;WalletService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;AopContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentProxy&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;withdrawMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will route the &lt;em&gt;internal&lt;/em&gt; method call through the proxy. This works, but it makes the AOP abstraction leaky. Your business logic is forced to learn framework details. Purists will frown at this, but it will also come in your way if you want to migrate to AspectJ later. Use sparingly.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. AspectJ Load-Time Weaving
&lt;/h3&gt;

&lt;p&gt;We've seen this earlier:&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;@EnableTransactionManagement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AdviceMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ASPECTJ&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is great if you want self-invocation across thousands of beans. But it introduces a lot of complexity, and is rarely worth it for a handful of cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The Proxy Paradox is a rite of passage for Spring developers. Just remember the flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;External Call&lt;/strong&gt; → Proxy → Aspects run → Logic runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal Call&lt;/strong&gt; → Raw &lt;code&gt;this&lt;/code&gt; object → Logic runs (No Aspects).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Re-organize your methods, self-inject if you must, or drop down to &lt;code&gt;TransactionTemplate&lt;/code&gt;—but never trust &lt;code&gt;@Transactional&lt;/code&gt; on a self-invoked method again.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sound Off:&lt;/strong&gt; What quirky Spring "gotcha" cost you the most debug minutes? Drop a comment below with the annotation that betrayed you!&lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The Dependency Injection Dilemma: Why I’m Finally Ghosting @Autowired on Fields</title>
      <dc:creator>Rajat Arora</dc:creator>
      <pubDate>Fri, 19 Dec 2025 11:41:47 +0000</pubDate>
      <link>https://forem.com/rajatarora/the-dependency-injection-dilemma-why-im-finally-ghosting-autowired-on-fields-5fba</link>
      <guid>https://forem.com/rajatarora/the-dependency-injection-dilemma-why-im-finally-ghosting-autowired-on-fields-5fba</guid>
      <description>&lt;p&gt;In the world of Spring Boot development, we are often seduced by "magic."&lt;/p&gt;

&lt;p&gt;We love the annotations that make 50 lines of boilerplate vanish. We love the auto-configuration that "just works." And for a long time, the poster child for this magic was the &lt;code&gt;@Autowired&lt;/code&gt; annotation sitting snugly atop a private field. It looks clean, it’s remarkably easy to write, and it feels like the pinnacle of modern Java productivity.&lt;/p&gt;

&lt;p&gt;But as I’ve spent more time in the trenches of large-scale enterprise architecture, I’ve realized that field injection is a siren song. It promises a shortcut but leads you straight into a rocky shore of un-testable code, hidden dependencies, and runtime nightmares.&lt;/p&gt;

&lt;p&gt;Today, I’m making the case for the "Old Reliable" of the Java world: &lt;strong&gt;Constructor Injection&lt;/strong&gt;. It’s time to stop using field injection, and it’s not just because the Spring documentation tells you to. It’s because your architecture deserves better.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Aesthetic Trap: Why we fell in love with Field Injection
&lt;/h2&gt;

&lt;p&gt;Before we tear it down, we have to acknowledge why we used it in the first place. Take a look at the following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;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;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&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;PaymentService&lt;/span&gt; &lt;span class="n"&gt;paymentService&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;InventoryClient&lt;/span&gt; &lt;span class="n"&gt;inventoryClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Business Logic...&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s undeniably sleek. There are no bulky constructors taking up half the screen. It feels like the "Spring Way." For years, this was the standard in tutorials and stack overflow answers. It allowed us to add a dependency with a single line of code.&lt;/p&gt;

&lt;p&gt;However, this "cleanliness" is a visual illusion. It’s like hiding a messy room by shoving everything into a closet. The room &lt;em&gt;looks&lt;/em&gt; clean, but you’ve actually made the system harder to manage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Case for Immutability
&lt;/h2&gt;

&lt;p&gt;As engineers, we should strive for Immutability. An object that cannot change after it is created is inherently safer, more predictable, and easier to reason about in a multi-threaded environment.&lt;/p&gt;

&lt;p&gt;When you use field injection, you cannot declare your dependencies as &lt;code&gt;final&lt;/code&gt;. Spring needs to be able to reach into your object after the constructor has run to inject those fields via reflection. This means your dependencies are technically mutable.&lt;/p&gt;

&lt;p&gt;By switching to Constructor Injection, you regain the ability to use the &lt;code&gt;final&lt;/code&gt; keyword:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;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;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&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;PaymentService&lt;/span&gt; &lt;span class="n"&gt;paymentService&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;InventoryClient&lt;/span&gt; &lt;span class="n"&gt;inventoryClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;OrderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
        &lt;span class="nc"&gt;PaymentService&lt;/span&gt; &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;InventoryClient&lt;/span&gt; &lt;span class="n"&gt;inventoryClient&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;userRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;paymentService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paymentService&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;inventoryClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inventoryClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, your class is "Born Ready." Once the &lt;code&gt;OrderService&lt;/code&gt; exists, you have a 100% guarantee that the &lt;code&gt;userRepository&lt;/code&gt; is there and will never be changed or set to &lt;code&gt;null&lt;/code&gt; by some rogue process. This is the foundation of thread safety and defensive programming.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Case for Unit Testing
&lt;/h2&gt;

&lt;p&gt;If you want to know how good your architecture is, look at your unit tests. If your test setup looks like a ritualistic sacrifice, your architecture is broken.&lt;/p&gt;

&lt;p&gt;Field injection makes unit testing unnecessarily difficult. Because the fields are private and Spring is doing the heavy lifting behind the scenes, you can’t simply instantiate the class in a test. You have two bad options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Spring in your tests&lt;/strong&gt;: You use &lt;code&gt;@SpringBootTest&lt;/code&gt; or &lt;code&gt;@MockBean&lt;/code&gt;. Now your "unit" test is starting a miniaturized version of the Spring Context. It’s slow, it’s heavy, and it’s no longer a unit test! (Hint: It's an integration test!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Reflection&lt;/strong&gt;: You use &lt;code&gt;ReflectionTestUtils&lt;/code&gt; to manually "shove" a mock into a private field. This is brittle. If you rename the field, your test breaks, but your compiler won't tell you why.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With Constructor Injection, testing is a breeze. Since the constructor is the only way to create the object, you just pass the mocks in 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="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldProcessOrder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;mockUserRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRepository&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;PaymentService&lt;/span&gt; &lt;span class="n"&gt;mockPaymentService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentService&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;InventoryClient&lt;/span&gt; &lt;span class="n"&gt;mockInventoryClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InventoryClient&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;// Standard Java. No magic. No Spring. Fast.&lt;/span&gt;
    &lt;span class="nc"&gt;OrderService&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;mockUserRepo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mockPaymentService&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mockInventoryClient&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Failing Fast: The 2:00 AM Production Bug
&lt;/h2&gt;

&lt;p&gt;We’ve all been there. You deploy a change, the app starts up fine, and everything looks green. Then, at 2:00 AM, a specific user hits an edge-case API endpoint, and the logs explode with a &lt;code&gt;NullPointerException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Why? Because with field injection, Spring allows the application to start even if a dependency is missing or circular. The field just remains &lt;code&gt;null&lt;/code&gt;. You don’t find out until the code actually tries to use that field.&lt;/p&gt;

&lt;p&gt;Constructor Injection is your early warning system. Because Spring must call the constructor to create the bean, it must satisfy all dependencies immediately. If a bean is missing, the &lt;code&gt;ApplicationContext&lt;/code&gt; will fail to load. The app won't even start on your machine, let alone in production.&lt;/p&gt;

&lt;p&gt;I’d much rather spend 5 minutes fixing a startup error on my local machine than 5 hours explaining to a stakeholder why the payment service crashed in the middle of the night.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Single Responsibility Principle
&lt;/h2&gt;

&lt;p&gt;The Single Responsibility Principle (SRP) states that a class should have one, and only one, reason to change.&lt;/p&gt;

&lt;p&gt;Field injection makes it too easy to violate this. Because each dependency is just one line of code, you don’t notice when a class starts doing too much. I’ve seen services with 15 &lt;code&gt;@Autowired&lt;/code&gt; fields that looked "neat" on the screen.&lt;/p&gt;

&lt;p&gt;When you use Constructor Injection, a class with 15 dependencies looks like a monster. The constructor is massive. It’s hard to read. It’s ugly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And that is exactly the point&lt;/strong&gt;. That "Constructor of Doom" is a signal. It’s the code telling you: &lt;em&gt;"Hey, I'm doing too much. Please refactor me into smaller, more focused services."&lt;/em&gt; Field injection is like a layer of makeup that hides a skin infection; Constructor Injection forces you to see the problem and treat it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Circular Dependencies: The Infinite Loop
&lt;/h2&gt;

&lt;p&gt;Circular dependencies (Service A needs B, and B needs A) are usually a sign of poor design. However, field injection allows them to happen almost unnoticed. Spring will try to resolve them using proxies, often leading to confusing behavior.&lt;/p&gt;

&lt;p&gt;Constructor Injection doesn't allow circular dependencies by default. If you try it, Spring will throw a &lt;code&gt;BeanCurrentlyInCreationException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While this might seem like a nuisance, it’s actually a guardrail. It forces you to rethink your service boundaries. Usually, a circular dependency means you need a third service (Service C) to hold the shared logic, or you need to move to an event-driven approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lombok Cheat Code
&lt;/h2&gt;

&lt;p&gt;The most common pushback I hear is: &lt;em&gt;"But I don't want to write and maintain constructors for 200 services!"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I agree. I’m a programmer; if I can automate a task, I will. This is where &lt;strong&gt;Project Lombok becomes your best friend&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By using the &lt;code&gt;@RequiredArgsConstructor annotation&lt;/code&gt;, you get the best of both worlds. You declare your fields as private final, and Lombok generates the constructor at compile time.&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="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;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;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&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;PaymentService&lt;/span&gt; &lt;span class="n"&gt;paymentService&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;InventoryClient&lt;/span&gt; &lt;span class="n"&gt;inventoryClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// No manual constructor needed!&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Professionalism is in the Details
&lt;/h2&gt;

&lt;p&gt;At the end of the day, using Constructor Injection is about &lt;strong&gt;intentionality&lt;/strong&gt;. It’s about making a conscious choice to write code that is framework-independent, easy to test, and architecturally sound. It’s about moving away from "Spring Magic" and moving toward "Java Excellence."&lt;/p&gt;

&lt;p&gt;If you’re working on a legacy codebase filled with &lt;code&gt;@Autowired&lt;/code&gt; fields, don't panic. You don't have to refactor everything tonight. But for every new service you write, try the constructor approach. Notice how your tests become simpler. Notice how your classes become smaller.&lt;/p&gt;

&lt;p&gt;Your code is a reflection of your craftsmanship. Don't let a shortcut like field injection be the thing that undermines it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What’s your take?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Are you a die-hard &lt;code&gt;@Autowired fan&lt;/code&gt;, or have you embraced the constructor? Let’s talk about it in the comments. If you found this helpful, consider sharing it with a junior dev who is still caught in the "Field Injection Trap."&lt;/p&gt;

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