Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Java Reflection and Dynamic Proxy Mechanisms Explained

Tech 1

Java Reflection System

Java reflection is defined as the ability to examine and modify the behavior of classes, methods, fields, and constructors at runtime. This mechanism enables programs to discover class information dynamically and invoke methods within those classes during execution.

Three primary approaches exist for obtaining a Class object:

  1. Using instance.getClass() - inherited from the Object class
  2. Accessing Type.Class property - available for all data types including primitives
  3. Employing Class.forName("fully qualified class name") - a method provided by the Class class

Manipulating Class Fields Through Reflection

package com.example.reflection;
import java.lang.reflect.Field;

class FieldExample {
    private String attribute = null;
    
    public static void main(String[] args) throws Exception {
        Class<?> targetClass = Class.forName("com.example.reflection.FieldExample");
        Object instance = targetClass.newInstance();
        
        Field fieldRef = targetClass.getDeclaredField("attribute");
        fieldRef.setAccessible(true);
        fieldRef.set(instance, "Reflection in Action");
        System.out.println(fieldRef.get(instance));
    }
}

Invoking Class Methods Through Reflection

package com.example.reflection;
import java.lang.reflect.Method;

class MethodExample {
    public static void main(String[] args) throws Exception {
        Class<?> targetClass = Class.forName("com.example.reflection.MethodExample");
        
        Method methodOne = targetClass.getMethod("executeFirst");
        methodOne.invoke(targetClass.newInstance());
        
        Method methodTwo = targetClass.getMethod("executeSecond", int.class, String.class);
        methodTwo.invoke(targetClass.newInstance(), 25, "John Doe");
    }
    
    public void executeFirst() {
        System.out.println("Executing first method via reflection");
    }
    
    public void executeSecond(int age, String name) {
        System.out.println("Executing second method via reflection");
        System.out.println("Age: " + age + ", Name: " + name);
    }
}

Dynamic Proxy Implementation

Understanding Dynamic Proxy AOP

The proxy pattern involves using one object to control access to another object. The controlling object serves as the proxy, while the controlled object represents the target or real subject. Proxy objects indirectly access corresponding methods in target objects through method invocation.

Key differences between static and dynamic proxies: Static proxies require defining separate proxy classes for each target class, whereas dynamic proxies eliminate the need for predefined proxy classes by utilizing the Proxy class from the reflection package to generate proxy instances dynamically.

In Java's dynamic proxy system, two components play crucial roles:

  • Proxy class: Creates proxy classes and objects dynamically
  • InvocationHandler interface: Handles method invocations on proxy instances

Every dynamic proxy instance must associate with an InvocationHandler implementation. When proxy methods are called, they automatically delegate to the associated handler's invoke method, which leverages reflection to call the target object's methods.

Classic Dynamic Proxy Example

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface ServiceInterface {
    void performService();
    void greet(String message);
}

class RealService implements ServiceInterface {
    @Override
    public void performService() {
        System.out.println("Providing service functionality");
    }

    @Override
    public void greet(String message) {
        System.out.println("Greeting: " + message);
    }
}

class ProxyHandler implements InvocationHandler {
    private Object targetObject;

    public ProxyHandler(Object target) {
        this.targetObject = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
        System.out.println("Before method execution");
        System.out.println("Invoking method: " + method.getName());
        
        Object result = method.invoke(targetObject, arguments);
        
        System.out.println("After method execution");
        return result;
    }
}

class Application {
    public static void main(String[] args) {
        ServiceInterface target = new RealService();
        ProxyHandler handler = new ProxyHandler(target);
        
        ServiceInterface proxyInstance = (ServiceInterface) Proxy.newProxyInstance(
            handler.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            handler
        );
        
        System.out.println(proxyInstance.getClass().getName());
        proxyInstance.performService();
        proxyInstance.greet("Dynamic Proxy World");
    }
}

Output:

com.sun.proxy.$Proxy0
Before method execution
Invoking method: performService
Providing service functionality
After method execution
Before method execution
Invoking method: greet
Greeting: Dynamic Proxy World
After method execution

Key Points:

  1. Dynamic proxies eliminate the need for predefined proxy classes; Proxy generates them at runtime
  2. All method calls on proxy objects redirect to the associated handler's invoke method
  3. The invoke method uses reflection internally to call corresponding methods on the target object
  4. Spring's AOP (Aspect-Oriented Programming) utilizes similar dynamic proxy concepts, where proxy objects contain all methods of the target object

AOP Application Example

Consider scenarios where common functionality needs to be applied across multiple methods without tight coupling. Dynamic proxies enable cross-cutting concerns to be woven into method execution.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface AnimalBehavior {
    void displayInfo();
    void move();
}

class Wolf implements AnimalBehavior {
    @Override
    public void displayInfo() {
        System.out.println("I am a wild wolf");
    }

    @Override
    public void move() {
        System.out.println("Running swiftly through forest");
    }
}

class UtilityMethods {
    public static void preExecution() {
        System.out.println("--- Pre-execution hook ---");
    }

    public static void postExecution() {
        System.out.println("--- Post-execution hook ---");
    }
}

class CustomHandler implements InvocationHandler {
    private Object targetObject;

    public void configureTarget(Object target) {
        this.targetObject = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] parameters)
            throws Throwable {
        UtilityMethods.preExecution();
        Object outcome = method.invoke(targetObject, parameters);
        UtilityMethods.postExecution();
        return outcome;
    }
}

class ProxyBuilder {
    public static Object createProxy(Object target) {
        CustomHandler handler = new CustomHandler();
        handler.configureTarget(target);
        
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            handler
        );
    }
}

public class AopDemo {
    public static void main(String[] args) {
        AnimalBehavior animal = (AnimalBehavior) ProxyBuilder.createProxy(new Wolf());
        animal.displayInfo();
        animal.move();
    }
}

Output:

--- Pre-execution hook ---
I am a wild wolf
--- Post-execution hook ---
--- Pre-execution hook ---
Running swiftly through forest
--- Post-execution hook ---

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.