skip to content

What is a dynamic proxy in Java, and how do you create one with java.lang.reflect.Proxy?

level: middleimportance: must knowfreq 55%

answer

  1. Proxy.newProxyInstance(loader, interfaces, handler)
  2. InvocationHandler.invoke(proxy, method, args)
  3. Interfaces only — extends Proxy, single inheritance
  4. $Proxy0 generated at runtime
  5. Spring AOP / mocks / RMI use it

basics

~20 s

A dynamic proxy is a class Java builds at runtime that implements one or more interfaces. You create it with Proxy.newProxyInstance, passing a class loader, the interfaces, and an InvocationHandler whose invoke method runs for every call.

solid answer

~40 s

A dynamic proxy is an object generated at runtime that implements a given set of interfaces, without you writing the implementation class. You call Proxy.newProxyInstance(classLoader, interfaces, handler). It returns an object you can cast to any of those interfaces. Every method call on that object is routed to your InvocationHandler.invoke(proxy, method, args), where you decide what to do: forward to a real object, log, check security, return a cached value, etc. The proxy reflects the method via a java.lang.reflect.Method argument and the call arguments via an Object array. This is the JDK mechanism behind many frameworks (Spring AOP for interface beans, mocking libraries, RMI stubs). The key constraint: it works only for interfaces, not concrete classes; for classes you need bytecode tools like CGLIB or ByteBuddy.

code

java · 15 lines
java
interface Greeter { String hello(String name); }

Greeter real = name -> "Hi " + name;

Greeter proxy = (Greeter) Proxy.newProxyInstance(
    Greeter.class.getClassLoader(),
    new Class<?>[]{ Greeter.class },
    (p, method, args) -> {
        long t = System.nanoTime();
        Object result = method.invoke(real, args); // forward
        System.out.println(method.getName() + " took " + (System.nanoTime() - t) + "ns");
        return result;
    });

proxy.hello("Ann"); // logs timing, returns "Hi Ann"

go deeper

for a junior

Can state that a dynamic proxy is built at runtime, implements interfaces, and that calls go to an InvocationHandler.

for a middle

Can write Proxy.newProxyInstance correctly, implement invoke, forward to a target, and explain the interface-only limitation.

for a senior

Explains the generated-class-extends-Proxy mechanism, exception wrapping (UndeclaredThrowableException), Object-method routing, and when to reach for CGLIB/ByteBuddy instead.

for a principal

Discusses proxy performance and caching, framework design trade-offs (JDK vs bytecode proxies), and module-system/classloader implications of generating classes at runtime.

## The problem dynamic proxies solve Sometimes you want an object that behaves like an implementation of an interface, but you don't want to (or can't) write that implementation by hand. Examples: wrapping every method call with logging, generating a mock in a test, or forwarding calls over a network. Writing one wrapper class per interface is tedious and rigid. A **dynamic proxy** lets the JVM synthesize the implementing class for you **at runtime**. ## Key terms (defined from scratch) - **Interface**: a Java type that declares method signatures but no bodies (e.g. `interface Repository { User find(long id); }`). - **Reflection** (`java.lang.reflect`): the JDK API that lets code inspect and invoke types/methods at runtime instead of at compile time. - **Class loader**: the object that loads classes into the JVM. The generated proxy class needs one to be defined in. - **`InvocationHandler`**: an interface with one method, `Object invoke(Object proxy, Method method, Object[] args)`. This is *your* code — the brain of the proxy. Every call on the proxy is funneled here. - **`Method`**: a reflective handle to the method being called (its name, parameter types, return type). ## How to create one ```java InvocationHandler h = (proxy, method, args) -> { System.out.println("calling " + method.getName()); return null; // or forward to a real target }; Repository repo = (Repository) Proxy.newProxyInstance( Repository.class.getClassLoader(), new Class<?>[]{ Repository.class }, h); ``` `Proxy.newProxyInstance` does three things: (1) finds or generates a class that implements all the given interfaces, (2) instantiates it with your handler, (3) returns it as `Object`, which you cast to one of the interfaces. The generated class is named something like `$Proxy0`. ## What happens on a call When you call `repo.find(5)`, the generated `find` method body simply calls `h.invoke(this, <Method for find>, new Object[]{5})`. Your handler decides the outcome and the return value is passed back to the caller (auto-unboxed if the return type is primitive). If your handler throws, that exception propagates — but only checked exceptions declared by the method are allowed; anything else gets wrapped in `UndeclaredThrowableException`. ## The interface-only constraint The generated class **extends `java.lang.reflect.Proxy`** and **implements** your interfaces. Because Java has single inheritance, it cannot also extend an arbitrary concrete class. So JDK dynamic proxies can only proxy **interfaces**. To proxy a concrete class you need a bytecode library (CGLIB, ByteBuddy) that generates a subclass. ## Common use cases - **AOP / cross-cutting concerns**: logging, transactions, security checks wrapped around real calls (Spring uses JDK proxies for interface-based beans). - **Mocking frameworks**: produce fake implementations in tests. - **Transparent decorators / remoting**: RMI stubs, lazy loading, caching. Three special methods are always handled specially and routed to your handler too: `equals`, `hashCode`, and `toString` from `Object` — you usually need to implement sensible behavior for them.

  • Why can JDK dynamic proxies only proxy interfaces?
    The generated class already extends java.lang.reflect.Proxy, and Java allows only single inheritance, so it cannot also extend a target concrete class — it can only implement interfaces. Class proxying needs a subclass-generating library like CGLIB or ByteBuddy.
  • What does invoke receive and return?
    It receives the proxy instance, a reflective Method object for the called method, and an Object[] of arguments (null if none). It returns the value to hand back to the caller, auto-(un)boxed to match the declared return type.

saying these in an interview costs you the question

  • Claiming JDK proxies can proxy concrete classes (they can't — interfaces only)
  • Confusing the proxy instance with the InvocationHandler
  • Saying the proxy class is written at compile time
  • Forgetting that equals/hashCode/toString also flow through invoke

context