Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
Sicherheitslücken (CVE)DSA-6533-1 firefox-esr - security update(30.09.2026 um 02:00 Uhr)
•
Linux Tipps & HardeningDSA-6532-1 tor - security update(30.09.2026 um 02:00 Uhr)
••••
Sichere ProgrammierungDeploying Umami - Open-Source Analytics Platform(30.09.2026 um 21:54 Uhr)
•
Sichere ProgrammierungDeploying Fluxer - An Open Source Instant Messaging and VoIP Platform(30.09.2026 um 21:54 Uhr)
••
Sichere ProgrammierungI Stopped Trusting VPN Ads and Built My Own (Then Automated It) :D(30.09.2026 um 21:59 Uhr)
••
Sicherheitslücken (CVE)DSA-6533-1 firefox-esr - security update(30.09.2026 um 02:00 Uhr)
•
Linux Tipps & HardeningDSA-6532-1 tor - security update(30.09.2026 um 02:00 Uhr)
••••
Sichere ProgrammierungDeploying Umami - Open-Source Analytics Platform(30.09.2026 um 21:54 Uhr)
•
Sichere ProgrammierungDeploying Fluxer - An Open Source Instant Messaging and VoIP Platform(30.09.2026 um 21:54 Uhr)
••
Sichere ProgrammierungI Stopped Trusting VPN Ads and Built My Own (Then Automated It) :D(30.09.2026 um 21:59 Uhr)
••
Intelligence View
⚡ tsecurity.de Intelligence

Magic in the Wild: How Java Giants like Spring, Hibernate, and Mockito use Dynamic Proxies

Welcome to the second installment of the series: Java Proxies Unmasked. In the previous post, we learned about the classic Proxy pattern. We built a Static…

Beitrag
0
Seite
0
↗ Quelle (dev.to)
Social ReaktionenReagiere als Erste:r — dein Feedback zählt!

Welcome to the second installment of the series: Java Proxies Unmasked. In the previous post, 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.



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".



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.



If you've ever felt that these frameworks do magic, today is the day we reveal their secrets.






Spring AOP: The @Transactional Onion



The most common place you'll encounter a proxy in Spring Framework is with the @Transactional 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 @Transactional, you aren't actually calling your code directly. You are calling a proxy that manages the lifecycle of a database connection.



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






Discovery & Pointcut Matching



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




  1. Does this bean have a "Pointcut" match? (e.g., Is it annotated with @Transactional?)


  2. What "Advice" should I apply? (In this case, the TransactionInterceptor).







The Creation Phase (The Wrapper)



Once Spring decides a proxy is needed, it uses a ProxyFactory. Depending on your configuration and class structure, it chooses one of two paths:




  1. JDK Dynamic Proxy: If your service implements an interface (e.g., UserServiceImpl implements UserService), Spring creates a proxy using the standard Java reflect.Proxy API.


  2. CGLIB Proxy: If your service is a concrete class with no interface, Spring uses CGLIB to generate a subclass of your bean at runtime.




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.






The Call in Action



When a client calls your service, it doesn't hit your code first. It hits the Proxy's invoke() or intercept() methods. Here's how the sequence of events looks:



Proxies in action in Spring's @Transactional



The Secret Sauce: TransactionAspectSupport



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



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






Hibernate: When Loading is Lazy



Hibernate uses proxies to solve a massive performance problem: Lazy Loading. Imagine a User entity that has a List<Order>. 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, your database would crawl to a halt.



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






The birth of a Proxy



Hibernate uses Byte Buddy to generate a new class at Runtime that extends your entity. If you have an Order class, Hibernate generates a class that looks something like Order$HibernateProxy$Q4X0SwcL.



This generated subclass contains a special field: LazyInitializer. This is the "brain" of the proxy. It stores:




  1. The Entity ID, which is knows immediately

  2. A reference to the Hibernate Session, to fetch data later

  3. Overridden Accessor Methods. These trigger SQL queries when they are accessed.


  4. Lazy Initialization Logic.






The Call in Action



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.



How Hibernate's Lazy Loading feature uses dynamic proxies






The Secret Sauce: ProxyConfiguration



If you want to see where Hibernate configures this bytecode "sorcery", check out the ByteBuddyProxyFactory.java 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 LazyInitializer.






Mockito's Secret Agent: The spy()



A Mockito Spy is a special type of test double that wraps a real object. 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.



In simple words, if you don't tell the spy what to do, it simply passes the call through to the real method.




List<String> list = new ArrayList<>();
List<String> spyList = spy(list); // Create a proxy around a real list

// This call is intercepted by the proxy, but since
// we didn't stub it, it delegates to the REAL ArrayList.size()
spyList.size();

// Now we "stub" the proxy to lie to us
doReturn(100).when(spyList).size();
spyList.size(); // Returns 100









Subclassing the Real Thing



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



If your class is PaymentService, Mockito creates PaymentService$MockitoMock$cG76HxJ8v. 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!






The Brain: MockMethodInterceptor



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






The Call in Action: To Real or Not to Real?



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



Mockito's spy() using proxies






The "Gotcha": when() vs. doReturn()



This proxy mechanism explains a famous Mockito trap.




  • If you use when(spy.get(0)).thenReturn("foo"), the proxy actually calls the real get(0) method once before the stubbing is applied. if the list is empty, it throws an IndexOutOfBoundsException!


  • If you use doReturn("foo").when(spy).get(0), you are talking to the proxy's "settings" directly. The real method is never called.




The Secret Sauce: InvocationContainer



If you want to see how Mockito tracks these calls, look at InvocationContainerImpl.java. It’s the ledger that stores every method call made to the proxy, which is what allows you to later call verify(spy).add(anyString()).






In Conclusion



Whether it's Spring managing your transactions, Hibernate saving you memory, or Mockito helping you test, the secret ingredient is Interception.



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 Declarative Programming: you declare the intent (via annotations), and the proxy handles the mechanics.






What’s Next?



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.



Part 3: The Native Way is where we write our first InvocationHandler. Get your IDE ready!

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Magic in the Wild: How Java Giants like Spring, Hibernate, and Mockito use Dynamic Proxies

Thematisch verwandte Begriffe: Magic, Wild, Java, Giants · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag