Backend Development 45 min read

Understanding Java Reflection, Class Loading, and Dynamic Proxy Mechanisms

This article provides a comprehensive guide to Java's reflection mechanism, class loading process, ClassLoader usage, and dynamic proxy techniques, illustrating how to inspect class structures, create objects, access fields and methods, retrieve generic type information, and implement both static and dynamic proxies with practical code examples.

Wukong Talks Architecture
Wukong Talks Architecture
Wukong Talks Architecture
Understanding Java Reflection, Class Loading, and Dynamic Proxy Mechanisms

01. Overview of Java Reflection Mechanism

Reflection is considered a key feature of dynamic languages; it allows a program at runtime to obtain any class's internal information via the Reflection API and directly manipulate its fields and methods.

After a class is loaded, a Class object is created in the method area (each class has exactly one Class object). This object contains the complete structural information of the class, acting like a mirror that reflects the class's structure.

1. Dynamic Language

A dynamic language can change its structure at runtime – new functions, objects, or even code can be introduced, and existing functions can be removed. Examples include Objective‑C, C#, JavaScript, PHP, Python, Erlang.

2. Static Language

Static languages have immutable runtime structures, such as Java, C, C++.

Java is not a dynamic language, but it can be regarded as a "quasi‑dynamic" language because it provides certain dynamic capabilities through reflection and bytecode manipulation, making programming more flexible.

Functions provided by Java reflection: Determine the class of any object at runtime. Instantiate any class at runtime. Inspect members (fields, methods) of any class at runtime. Obtain generic type information at runtime. Invoke any object's fields and methods at runtime. Process annotations at runtime. Create dynamic proxies.

Key Reflection APIs: java.lang.Class : represents a class. java.lang.reflect.Method : represents a method. java.lang.reflect.Field : represents a field. java.lang.reflect.Constructor : represents a constructor.

Test Class
import org.junit.Test;

public class ReflectionTest {
    // Before reflection, operate on Person directly
    @Test
    public void test() {
        // 1. Create an object of Person
        Person p1 = new Person("jay", 21);
        // 2. Access and modify fields/methods directly
        p1.age = 15;
        System.out.println(p1.toString());
        p1.show();
        // Private members cannot be accessed directly
    }
}
Person Class
package github;

public class Person {
    private String name;
    public int age;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public Person() {}
    public Person(String name, int age) { this.name = name; this.age = age; }
    private Person(String name) { this.name = name; }
    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
    public void show() { System.out.println("你好,我是🔔"); }
    private String showNation(String nation) {
        System.out.println("喷子实在太多了!!!" + nation);
        return nation;
    }
}

1.1 Using Reflection to Perform the Same Operations

import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionTest {
    // After reflection, operate on Person
    @Test
    public void test2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        Class clazz = Person.class;
        // 1. Create Person via reflection
        Constructor cons = clazz.getConstructor(String.class, int.class);
        Object obj = cons.newInstance("Jon", 18);
        Person p = (Person) obj;
        System.out.println(p.toString());
        // 2. Access fields
        Field age = clazz.getDeclaredField("age");
        age.set(p, 10);
        System.out.println(p.toString());
        // 3. Invoke methods
        Method show = clazz.getDeclaredMethod("show");
        show.invoke(p);
    }
}

1.2 Powerful Reflection: Accessing Private Members

import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionTest {
    @Test
    public void test2() throws Exception {
        Class clazz = Person.class;
        // 1. Create Person via reflection
        Constructor cons = clazz.getConstructor(String.class, int.class);
        Object obj = cons.newInstance("Jon", 18);
        Person p = (Person) obj;
        System.out.println(p.toString());
        // 2. Access fields
        Field age = clazz.getDeclaredField("age");
        age.set(p, 10);
        System.out.println(p.toString());
        // 3. Invoke methods
        Method show = clazz.getDeclaredMethod("show");
        show.invoke(p);
        System.out.println("+++++++++++++++++++++++++");
        // Access private constructor
        Constructor cons2 = clazz.getDeclaredConstructor(String.class);
        cons2.setAccessible(true);
        Person p1 = (Person) cons2.newInstance("kalo");
        System.out.println(p1);
        // Access private field
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(p1, "Taoyao");
        System.out.println(p1);
        // Access private method
        Method showNation = clazz.getDeclaredMethod("LiNin", String.class);
        showNation.setAccessible(true);
        String nation = (String) showNation.invoke(p1, "FaceBook");
        System.out.println(nation);
    }
    /**
     * Question 1: When to use direct new vs. reflection?
     * Suggestion: Use direct new. Use reflection when dynamic behavior is required.
     * Question 2: Does reflection conflict with OOP encapsulation?
     * Answer: No conflict.
     */
}

02. Understanding the Class Object and Obtaining Class Instances

2.3 Understanding the Class Class

/**
 * About java.lang.Class
 * 1. Class loading process: .class files are generated by javac, then loaded by java runtime, becoming runtime classes represented by a Class instance.
 * 2. Each runtime class corresponds to a Class instance.
 */
Common Methods of Class

2.4 Four Ways to Obtain a Class Instance

import org.junit.Test;
import java.lang.annotation.ElementType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionTest {
    @Test
    public void test3() throws ClassNotFoundException {
        // Way 1
        Class c1 = Person.class;
        System.out.println(c1);
        // Way 2
        Person p1 = new Person();
        Class c2 = p1.getClass();
        System.out.println(c2);
        // Way 3
        Class c3 = Class.forName("www.gh110.com");
        System.out.println(c3);
        System.out.println(c1 == c2);
        System.out.println(c1 == c3);
        // Way 4
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class c4 = classLoader.loadClass("www.gh110.com");
        System.out.println(c4);
        System.out.println(c1 == c4);
    }
}

2.5 Explanation of Class Instance Structures

Which types can have Class objects?

class : top‑level, member, local, anonymous classes.

interface : interfaces.

[] : arrays.

enum : enums.

annotation and @interface : annotations.

primitivetype : primitive types.

void

import org.junit.Test;
import java.lang.annotation.ElementType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionTest {
    @Test
    public void test4() {
        Class s1 = Object.class;
        Class s2 = Comparable.class;
        Class s3 = String[].class;
        Class s4 = int[][].class;
        Class s5 = ElementType.class;
        Class s6 = Override.class;
        Class s7 = int.class;
        Class s8 = void.class;
        Class s9 = Class.class;
        int[] a = new int[10];
        int[] b = new int[100];
        Class s10 = a.getClass();
        Class s11 = b.getClass();
        System.out.println(s10 == s11);
    }
}

03. Understanding Class Loading and ClassLoader

3.6 Understanding the Class Loading Process

When a program actively uses a class that has not yet been loaded, the JVM performs three steps to initialize the class.
Explanation

Loading: load bytecode into memory, create a Class object.

Linking: combine binary code into JVM state. Verification: ensure class file conforms to JVM specifications. Preparation: allocate memory for static variables and set default values. Resolution: replace symbolic references with direct references.

Initialization: execute class constructors ( <clinit> ), initialize static fields, and ensure parent class initialization first.

3.7 When Does Class Initialization Occur?

Active references (always trigger initialization): JVM startup – initialize the class containing main . Creating a new instance. Accessing static members (except final constants). Using reflection via java.lang.reflect package. Initializing a subclass also initializes its superclass.

Passive references (do not trigger initialization): Referencing a superclass's static field via a subclass. Accessing a static field declared in a superclass. Referencing a class via an array type. Referencing a compile‑time constant.

3.8 Understanding ClassLoader

Purpose of ClassLoader: Load .class bytecode into memory and create a Class object. Cache loaded classes; the JVM GC can reclaim them.

JVM defines several types of class loaders.

import org.junit.Test;
/**
 * Understand ClassLoader
 */
public class ClassLoaderTest {
    @Test
    public void test1() {
        // System class loader for custom classes
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);
        // Parent is the extension class loader
        ClassLoader classLoader1 = classLoader.getParent();
        System.out.println(classLoader1);
        // Bootstrap class loader (null) cannot load custom classes
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);
        // String's class loader (bootstrap) is null
        ClassLoader classLoader3 = String.class.getClassLoader();
        System.out.println(classLoader3);
    }
}

3.9 Using ClassLoader to Load Configuration Files

import org.junit.Test;
import java.io.InputStream;
import java.util.Properties;
/**
 * Read configuration file using ClassLoader
 */
public class ClassLoaderTest {
    @Test
    public void test2() throws Exception {
        Properties pros = new Properties();
        // Use ClassLoader to load file from src directory
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
        pros.load(is);
        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        System.out.println("user = " + user + ",password = " + password);
    }
}

04. Creating Runtime Objects via Reflection

import org.junit.Test;
/**
 * Create an instance of a runtime class using reflection
 */
public class NewInstanceTest {
    @Test
    public void test() throws Exception {
        Class<Person> clazz = Person.class;
        // newInstance() invokes the no‑arg constructor
        Person obj = clazz.newInstance();
        System.out.println(obj);
    }
}

4.1 Demonstrating the Dynamism of Reflection

import org.junit.Test;
import java.util.Random;
/**
 * Dynamically create objects based on random class names
 */
public class NewInstanceTest {
    @Test
    public void test2() {
        for (int i = 0; i < 100; i++) {
            int num = new Random().nextInt(3); // 0,1,2
            String classPath = "";
            switch (num) {
                case 0: classPath = "java.util.Date"; break;
                case 1: classPath = "java.lang.Object"; break;
                case 2: classPath = "www.java.Person"; break;
            }
            try {
                Object obj = getInstance(classPath);
                System.out.println(obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * Create an instance of the specified class.
     */
    public Object getInstance(String classPath) throws Exception {
        Class clazz = Class.forName(classPath);
        return clazz.newInstance();
    }
}

05. Obtaining the Complete Structure of a Runtime Class

5.1 Providing a Rich Person Class

1. Person class
@MyAnnotation(value="java")
public class Person extends Creature
implements Comparable
, MyInterface {
    private String name;
    int age;
    public int id;
    public Person() {}
    @MyAnnotation(value="C++")
    Person(String name) { this.name = name; }
    private Person(String name, int age) { this.name = name; this.age = age; }
    @MyAnnotation
    private String show(String nation) { System.out.println("我来自" + nation + "星系"); return nation; }
    @Override
    public void info() { System.out.println("火星喷子"); }
    public String display(String play) { return play; }
    @Override
    public int compareTo(String o) { return 0; }
}
2. Creature class
import java.io.Serializable;
public abstract class Creature
implements Serializable {
    private char gender;
    public double weight;
    private void breath() { System.out.println("太阳系"); }
    public void eat() { System.out.println("银河系"); }
}
3. MyInterface
public interface MyInterface { void info(); }
4. MyAnnotation
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation { String value() default "hello world"; }

5.2 Retrieving Field Structures

1. Person class
import github2.Person;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class FieldTest {
    @Test
    public void test() {
        Class clazz = Person.class;
        // getFields(): public fields of class and superclasses
        Field[] fields = clazz.getFields();
        for (Field f : fields) System.out.println(f);
        System.out.println("++++++++++++++++++");
        // getDeclaredFields(): all fields declared in the class
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f : declaredFields) System.out.println(f);
    }
    @Test
    public void test2() {
        Class clazz = Person.class;
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f : declaredFields) {
            int modifier = f.getModifiers();
            System.out.print(Modifier.toString(modifier) + "\t");
            Class type = f.getType();
            System.out.print(type.getName() + "\t");
            System.out.print(f.getName());
        }
    }
}

5.3 Retrieving Method Structures

1. Person class
package github2;
@MyAnnotation(value="java")
public class Person extends Creature
implements Comparable
, MyInterface {
    private String name;
    int age;
    public int id;
    public Person() {}
    @MyAnnotation(value="C++")
    Person(String name) { this.name = name; }
    private Person(String name, int age) { this.name = name; this.age = age; }
    @MyAnnotation
    private String show(String nation) { System.out.println("我来自" + nation + "星系"); return nation; }
    @Override
    public void info() { System.out.println("火星喷子"); }
    public String display(String interests, int age) throws Exception { return interests + age; }
    @Override
    public int compareTo(String o) { return 0; }
    @Override
    public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + '}'; }
}
2. Test class for methods
package github3;
import github2.Person;
import org.junit.Test;
import java.lang.reflect.Method;
public class MythodTest {
    @Test
    public void test() {
        Class clazz = Person.class;
        // getMethods(): public methods of class and superclasses
        Method[] methods = clazz.getMethods();
        for (Method m : methods) System.out.println(m + "****");
        System.out.println("++++++++++++++++++++++++++++");
        // getDeclaredMethods(): all methods declared in the class
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) System.out.println(m);
    }
}

5.4 Detailed Method Structure Information

1. Person class
@MyAnnotation(value="java")
public class Person extends Creature
implements Comparable
, MyInterface {
    private String name;
    int age;
    public int id;
    public Person() {}
    @MyAnnotation(value="C++")
    Person(String name) { this.name = name; }
    private Person(String name, int age) { this.name = name; this.age = age; }
    @MyAnnotation
    private String show(String nation) { System.out.println("我来自" + nation + "星系"); return nation; }
    @Override
    public void info() { System.out.println("火星喷子"); }
    public String display(String interests, int age) throws Exception { return interests + age; }
    @Override
    public int compareTo(String o) { return 0; }
    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + '}';
    }
}
2. Test class for detailed method info
package github3;
import github2.Person;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class MythodTest {
    /**
     * Show method signature details
     */
    @Test
    public void test2() {
        Class clazz = Person.class;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            // Annotations
            Annotation[] annos = m.getAnnotations();
            for (Annotation a : annos) System.out.println(a + "KKKK");
            // Modifiers
            System.out.print(Modifier.toString(m.getModifiers()) + "\t");
            // Return type
            System.out.print(m.getReturnType().getName() + "\t");
            // Method name and parameters
            System.out.print(m.getName() + "(");
            Class[] pTs = m.getParameterTypes();
            if (pTs != null && pTs.length != 0) {
                for (int i = 0; i < pTs.length; i++) {
                    System.out.print(pTs[i].getName() + " args_" + i);
                    if (i != pTs.length - 1) System.out.print(",");
                }
            }
            System.out.print(")");
            // Exceptions
            Class[] eTs = m.getExceptionTypes();
            if (eTs.length > 0) {
                System.out.print(" throws ");
                for (int i = 0; i < eTs.length; i++) {
                    System.out.print(eTs[i].getName());
                    if (i != eTs.length - 1) System.out.print(",");
                }
            }
            System.out.println("TQA");
        }
    }
}

5.5 Retrieving Constructor Structures

package github3;
import github2.Person;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class OtherTest {
    /**
     * Get constructor structures
     */
    @Test
    public void test() {
        Class clazz = Person.class;
        // public constructors
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor c : constructors) System.out.println(c);
        System.out.println("************************");
        // all declared constructors
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor c : declaredConstructors) System.out.println(c);
    }
}

5.6 Retrieving Superclass and Generic Information

package github3;
import github2.Person;
import org.junit.Test;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class OtherTest {
    @Test
    public void test2() {
        Class clazz = Person.class;
        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
    }
    @Test
    public void test3() {
        Class clazz = Person.class;
        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
    }
    @Test
    public void test4() {
        Class clazz = Person.class;
        ParameterizedType paramType = (ParameterizedType) clazz.getGenericSuperclass();
        Type[] actualTypeArguments = paramType.getActualTypeArguments();
        System.out.println(((Class)actualTypeArguments[0]).getName());
    }
}

5.7 Retrieving Interfaces, Packages, and Annotations

package github3;
import github2.Person;
import org.junit.Test;
import java.lang.annotation.Annotation;
public class OtherTest {
    @Test
    public void test5() {
        Class clazz = Person.class;
        Class[] interfaces = clazz.getInterfaces();
        for (Class c : interfaces) System.out.println(c);
        System.out.println("++++++++++++++++++++++");
        Class[] superInterfaces = clazz.getSuperclass().getInterfaces();
        for (Class c : superInterfaces) System.out.println(c);
    }
    @Test
    public void test6() {
        Class clazz = Person.class;
        System.out.println(clazz.getPackage());
    }
    @Test
    public void test7() {
        Class clazz = Person.class;
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation ann : annotations) System.out.println(ann);
    }
}

06. Invoking Specific Structures of a Runtime Class

6.1 Accessing Specified Fields

1. Person class
package github2;
@MyAnnotation(value="java")
public class Person extends Creature
implements Comparable
, MyInterface {
    private String name;
    int age;
    public int id;
    // constructors and methods omitted for brevity
}
2. Test class
import github2.Person;
import org.junit.Test;
import java.lang.reflect.Field;
/**
 * Invoke fields, methods, constructors via reflection
 */
public class ReflectionTest {
    /**
     * Simple field access (public field)
     */
    @Test
    public void testField() throws Exception {
        Class clazz = Person.class;
        Person p = (Person) clazz.newInstance();
        Field id = clazz.getField("id");
        id.set(p, 1001);
        int pId = (int) id.get(p);
        System.out.println(pId);
    }
    /**
     * Access private field (needs setAccessible)
     */
    @Test
    public void testField1() throws Exception {
        Class clazz = Person.class;
        Person p = (Person) clazz.newInstance();
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(p, "Jam");
        System.out.println(name.get(p));
    }
}

6.2 Invoking Specified Methods

package github3;
import github2.Person;
import org.junit.Test;
import java.lang.reflect.Method;
public class ReflectionTest {
    @Test
    public void testMethod() throws Exception {
        Class clazz = Person.class;
        Person p = (Person) clazz.newInstance();
        // Invoke private method "show"
        Method show = clazz.getDeclaredMethod("show", String.class);
        show.setAccessible(true);
        Object returnValue = show.invoke(p, "CCA");
        System.out.println(returnValue);
        System.out.println("+++++++++Calling static method+++++++++++");
        Method showDesc = clazz.getDeclaredMethod("showDown");
        showDesc.setAccessible(true);
        Object returnVal = showDesc.invoke(Person.class);
        System.out.println(returnVal);
    }
}

6.3 Invoking Specified Constructors

import github2.Person;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class ReflectionTest {
    @Test
    public void testConstructor() throws Exception {
        Class clazz = Person.class;
        // private Person(String name)
        Constructor constructor = clazz.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);
        Person per = (Person) constructor.newInstance("Tom");
        System.out.println(per);
    }
}

07. Applications of Reflection: Dynamic Proxy

7.1 Proxy Pattern and Dynamic Proxy

Proxy design pattern wraps an object with a proxy that decides when to forward method calls to the original object.

Static proxy requires compile‑time knowledge of both proxy and target classes, leading to many proxy classes.

Dynamic proxy creates proxy objects at runtime, allowing a single proxy class to handle multiple interfaces.

Typical uses: debugging, remote method invocation, AOP.

7.2 Static Proxy Example

/**
 * Static proxy example – the proxy and target are fixed at compile time.
 */
interface ClothFactory { void produceCloth(); }
// Proxy class
class PersonTest implements ClothFactory {
    private ClothFactory factory;
    public PersonTest(ClothFactory factory) { this.factory = factory; }
    @Override
    public void produceCloth() {
        System.out.println("造纸厂开始做一些准备工作");
        factory.produceCloth();
        System.out.println("造纸厂做一些后续收尾工作");
    }
}
// Target class
class NeckTest implements ClothFactory {
    @Override
    public void produceCloth() { System.out.println("造纸厂计划生产一批卫生纸"); }
}
public class StaticProxyTest {
    public static void main(String[] args) {
        ClothFactory real = new NeckTest();
        ClothFactory proxy = new PersonTest(real);
        proxy.produceCloth();
    }
}

7.3 Dynamic Proxy Example

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Moon { String getBelief(); void Object(String Moon); }
// Target class
class Venus implements Moon {
    @Override public String getBelief() { return "The only planet in the solar system without a magnetic field."; }
    @Override public void Object(String MinMoon) { System.out.println("周围有很多" + MinMoon); }
}
/**
 * Utility to create a dynamic proxy for any object.
 */
class BookTest {
    public static Object getProxyInstance(Object obj) {
        DeskTest handler = new DeskTest();
        handler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
    }
}
class DeskTest implements InvocationHandler {
    private Object obj;
    public void bind(Object obj) { this.obj = obj; }
    @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // Common pre‑processing
        SunTest util = new SunTest();
        util.Star();
        Object returnValue = method.invoke(obj, args);
        // Common post‑processing
        util.Star2();
        return returnValue;
    }
}
class SunTest { public void Star() { System.out.println("====================通用方法一===================="); }
               public void Star2() { System.out.println("====================通用方法二===================="); } }
public class ProductTest {
    public static void main(String[] args) {
        Venus real = new Venus();
        Moon proxy = (Moon) BookTest.getProxyInstance(real);
        String belief = proxy.getBelief();
        System.out.println(belief);
        proxy.Object("面试突击");
        System.out.println("+++++++++++++++++++");
        NeckTest fox = new NeckTest();
        ClothFactory ween = (ClothFactory) BookTest.getProxyInstance(fox);
        ween.produceCloth();
    }
}

7.4 AOP and Dynamic Proxy Example

Dynamic proxy can be used to implement AOP by inserting common behavior before and after method execution.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * Demonstrates AOP style dynamic proxy.
 */
class BookTest {
    public static Object getProxyInstance(Object obj) {
        DeskTest handler = new DeskTest();
        handler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
    }
}
class DeskTest implements InvocationHandler {
    private Object obj;
    public void bind(Object obj) { this.obj = obj; }
    @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        SunTest util = new SunTest();
        util.Star(); // before
        Object returnValue = method.invoke(obj, args);
        util.Star2(); // after
        return returnValue;
    }
}
class SunTest { public void Star() { System.out.println("====================通用方法一===================="); }
               public void Star2() { System.out.println("====================通用方法二===================="); } }
// The rest of the code (interfaces, target classes, and main) is the same as in section 7.3.
JavaaopReflectionGenericsClassLoaderannotationDynamicProxy
Wukong Talks Architecture
Written by

Wukong Talks Architecture

Explaining distributed systems and architecture through stories. Author of the "JVM Performance Tuning in Practice" column, open-source author of "Spring Cloud in Practice PassJava", and independently developed a PMP practice quiz mini-program.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.