ProgrammingJava Architect

What is a proxy, types of proxies in Java, and how does it implement dynamic behavior of objects?

Pass interviews with Hintsage AI assistant

Answer.

Background:

Proxy objects and the Proxy pattern were introduced in Java to create substitute objects that can control access to the real object, modify its behavior, or inject cross-cutting concerns (security, logging, metrics). Since Java 1.3, support for standard dynamic proxies has been available in the java.lang.reflect package, and later popular libraries such as CGLIB and ByteBuddy came into play.

Problem:

It is not always possible or convenient to change the logic of an existing class directly. Often, it is required to transparently add behavior (such as logging, caching, transactions) without modifying the object's source code, which is impossible using standard inheritance.

Solution:

Proxy objects can be implemented statically (through manual subclassing) and dynamically (via reflection or bytecode mechanisms). A dynamic proxy allows on-the-fly creation of objects implementing the needed interface and delegating calls to the real object within the invoke() method, providing flexibility for injecting external behavior.

Code example:

import java.lang.reflect.*; interface Service { void doWork(); } class RealService implements Service { public void doWork() { System.out.println("Doing work!"); } } class LoggingInvocationHandler implements InvocationHandler { private final Object target; public LoggingInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Calling: " + method.getName()); return method.invoke(target, args); } } Service real = new RealService(); Service proxy = (Service) Proxy.newProxyInstance( real.getClass().getClassLoader(), new Class[] {Service.class}, new LoggingInvocationHandler(real)); proxy.doWork(); // Call is logged

Key features:

  • Static proxies require pre-defined code for each function
  • Dynamic proxies can be created on the fly at runtime for any interfaces
  • For classes without interfaces, third-party libraries are required (e.g., CGLIB)

Tricky questions.

Can the standard dynamic Proxy in Java work with classes that do not implement interfaces?

No. The standard Proxy in Java works only with interfaces. For classes without interfaces (e.g., if you want to proxy a regular class), external tools (e.g., CGLIB, ByteBuddy) are needed.

Can a proxy be created for an interface with private methods?

No. Interfaces in Java cannot contain private methods that need to be proxied. The dynamic proxy implements the public methods of the interface. Since Java 9, private default methods have been introduced, but they are not accessible through proxy.

What is the difference between InvocationHandler and MethodInterceptor (CGLIB)?

InvocationHandler is a standard JDK interface used for dynamic proxies. It handles method calls of the interface. MethodInterceptor is a CGLIB interface that allows interception of method calls in any classes through dynamic inheritance. The difference lies in applicability and level: JDK works only with interfaces, while CGLIB works with any classes.

Common mistakes and anti-patterns

  • Type error: attempting to use Proxy for a class that does not implement an interface
  • Implicit cyclic calls leading to StackOverflow
  • Proxying classes not meant for it or attempting to proxy final classes

Real-life example

Negative case

An engineer manually repeats logging code in every method of all services. When adding new methods, they constantly duplicate logic, often forgetting to include necessary calls.

Pros:

  • Transparent, easy to understand execution flow

Cons:

  • Huge time costs, lots of repetitive code, difficult to maintain

Positive case

AOP has been implemented in the project through a dynamic proxy: logging and transaction control are executed through wrapper substitutes, implemented centrally.

Pros:

  • Faster to implement and change any cross-cutting functionality, no duplication

Cons:

  • Need to understand how the proxy works, potential debugging difficulties