Lab 01: Dynamic Proxies & Reflection

Objective

Build runtime behaviour injection using java.lang.reflect.Proxy — automatic timing, caching, and logging for any interface without modifying the implementation. Master MethodHandles for faster reflective dispatch, and ParameterizedType for type token patterns.

Background

java.lang.reflect.Proxy creates an implementation of any interface at runtime. Every method call goes through a single InvocationHandler — making it trivial to inject cross-cutting concerns (timing, auth, caching, retry) around any service. This is the foundation of Spring AOP, JPA lazy-loading, and mocking frameworks like Mockito.

Time

30 minutes

Prerequisites

  • Practitioner Lab 12 (Reflection & Annotations)

Tools

  • Docker: zchencow/innozverse-java:latest


Lab Instructions

Steps 1–8: Timing proxy, caching proxy, class introspection, MethodHandles, type tokens, composing proxies, Capstone

💡 Proxy.newProxyInstance is how Spring creates @Transactional beans. When you inject a Spring bean, you're actually getting a proxy — the real object is wrapped in an InvocationHandler that starts a transaction before calling the real method and commits (or rolls back) after. The real class is never exposed directly. This is also how Mockito creates mocks at runtime without any code generation.

📸 Verified Output:


Summary

API
Use for

Proxy.newProxyInstance(loader, ifaces, handler)

Runtime interface implementation

InvocationHandler.invoke(proxy, method, args)

Intercept every method call

method.invoke(target, args)

Forward to real target

MethodHandles.lookup().findVirtual(cls, name, type)

Fast reflective dispatch

ParameterizedType.getActualTypeArguments()

Recover generic type args

Further Reading

Last updated