12.2.2 Dynamic Proxy Explained
Dynamic Proxy in Java SE 11 is a powerful feature that allows the creation of proxy objects at runtime. These proxy objects can implement one or more interfaces dynamically, enabling advanced functionality such as method interception, logging, and security checks. Understanding Dynamic Proxy is crucial for developing flexible and maintainable Java applications.
Key Concepts
1. Proxy Class
A proxy class is a class that implements a set of interfaces specified at runtime. The proxy class acts as an intermediary between the client and the actual object, allowing additional logic to be executed before or after method calls.
Example
import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; interface MyInterface { void doSomething(); } class MyInvocationHandler implements InvocationHandler { private Object target; MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before method call"); Object result = method.invoke(target, args); System.out.println("After method call"); return result; } } public class DynamicProxyExample { public static void main(String[] args) { MyInterface target = new MyInterface() { @Override public void doSomething() { System.out.println("Doing something"); } }; MyInterface proxy = (MyInterface) Proxy.newProxyInstance( MyInterface.class.getClassLoader(), new Class[] { MyInterface.class }, new MyInvocationHandler(target) ); proxy.doSomething(); } }
2. InvocationHandler Interface
The InvocationHandler
interface is a key component of Dynamic Proxy. It defines a single method, invoke()
, which is called whenever a method is invoked on the proxy instance. This method allows you to define custom behavior before and after the actual method call.
Example
class MyInvocationHandler implements InvocationHandler { private Object target; MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before method call"); Object result = method.invoke(target, args); System.out.println("After method call"); return result; } }
3. Proxy.newProxyInstance() Method
The Proxy.newProxyInstance()
method is used to create a new proxy instance. It takes three arguments: the class loader, an array of interfaces to implement, and the InvocationHandler
instance. This method dynamically generates a proxy class that implements the specified interfaces and delegates method calls to the InvocationHandler
.
Example
MyInterface proxy = (MyInterface) Proxy.newProxyInstance( MyInterface.class.getClassLoader(), new Class[] { MyInterface.class }, new MyInvocationHandler(target) );
4. Method Interception
Dynamic Proxy allows you to intercept method calls on the proxy instance. This is useful for adding additional logic such as logging, security checks, or caching. The invoke()
method in the InvocationHandler
is where you can implement this interception logic.
Example
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("doSomething")) { System.out.println("Intercepting doSomething method"); } return method.invoke(target, args); }
5. Multiple Interfaces
Dynamic Proxy can implement multiple interfaces, allowing a single proxy instance to handle method calls for different types of objects. This is useful for creating generic proxies that can be used with various types of objects.
Example
interface AnotherInterface { void doAnotherThing(); } MyInterface proxy = (MyInterface) Proxy.newProxyInstance( MyInterface.class.getClassLoader(), new Class[] { MyInterface.class, AnotherInterface.class }, new MyInvocationHandler(target) );
Examples and Analogies
Think of Dynamic Proxy as a middleman who intercepts calls between a client and a service provider. For example, if you are ordering food online, the middleman (proxy) can log your order, check for any discounts, and then forward the order to the restaurant. Similarly, in Java, Dynamic Proxy can log method calls, perform security checks, and then invoke the actual method on the target object.
For instance, if you are developing a logging framework, Dynamic Proxy allows you to create a proxy for any object and log all method calls without modifying the original object's code. This makes your logging framework flexible and reusable across different types of objects.
By mastering Dynamic Proxy, you can create powerful and flexible Java SE 11 applications that can adapt to changing requirements and configurations, making your code more robust and maintainable.