欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

简单使用JDK的Proxy.newProxyInstance()方法

程序员文章站 2022-06-01 10:23:07
...

JDK的动态代理实现的原理其实是动态生成Proxy的.java文件,再动态编译.java文件成为对应的.class文件,再通过ClassLoader将字节码对象加载到内存中从而实现动态的效果。现在主要是测试一下如何使用JDK的动态代理,不做原理的分析。如果想了解原理可以观看马士兵的设计模式之动态代理深入剖析。

package cn.shaines.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;

/**
 * 定义一个接口
 */
interface MyInterface {
    int getInt(int i);
    void close();
}

/**
 * 接口实现类
 */
class MyInterfaceImpl implements MyInterface {
    @Override
    public int getInt(int i) {
        return i;
    }
    @Override
    public void close() {
        System.out.println("==>>close()");
    }

    public void otherMethod(){
        System.out.println("==>>otherMethod()");
    }
}

/**
 * 测试类JDK代理
 */
public class Test {

    /**
     * 反射执行方法
     * @param o 调用对象
     * @param methodName 方法名称
     * @param parameterTypes 参数类型.class
     * @param parameters 参数实体
     */
    public static <R> R methodInvoke(Object o, String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        return (R) ((parameterTypes == null) ? o.getClass().getMethod(methodName).invoke(o) : o.getClass().getMethod(methodName, parameterTypes).invoke(o, parameters));
    }

    // 入口main
    public static void main(String[] args) {

        // 使用JDK提供的动态代理方法步骤如下:
        // 步骤01: 创建需要代理的实体类对象
        MyInterfaceImpl myInterfaceImpl = new MyInterfaceImpl();
        // 步骤02: 获取实体类对象的Class对象
        Class<? extends MyInterfaceImpl> clazz = myInterfaceImpl.getClass();
        // 步骤03: 调用JDK提供的Proxy.newProxyInstance()方法
        Object proxyInstance = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 步骤04: 动态修改getInt()方法
                if (method.getName().equals("getInt")){
                    System.out.println("代理类收到的参数是:" + args[0]);
                    return 100;
                }
                // 步骤05: 注意这里的实际调用必须是实现类对象
                return method.invoke(myInterfaceImpl);
            }
        });

        // cn.shaines.test.MyInterfaceImpl
        System.out.println(clazz.getClass().getName());
        // java.lang.Class
        System.out.println(clazz.getName());

        // 步骤06: 使用代理对象(强制转换为接口对象MyInterface,不可以强制转换为MyInterfaceImpl,
        //         通过上面的打印可以知道proxyInstance的class和MyInterfaceImpl的class是不同的,强制转换会报错)
        // MyInterfaceImpl myInterfaceImpl2 = ((MyInterfaceImpl) proxyInstance);// 报错
        MyInterface myInterface1 = ((MyInterface) proxyInstance);
        int anInt = myInterface1.getInt(20);
        System.out.println("anInt:" + anInt);// anInt:100     被动态修改值
        myInterface1.close();

        // 放射执行方法,无需强制转为对象都可以使用proxyInstance调用任意方法
        try {
            int i = methodInvoke(proxyInstance, "getInt", new Class[]{int.class}, new Object[]{10});
            methodInvoke(proxyInstance, "close", new Class[]{}, new Object[]{});
            // methodInvoke(proxyInstance, "otherMethod", new Class[]{}, new Object[]{});
            // 这个方法会报错:java.lang.NoSuchMethodException: cn.shaines.test.$Proxy0.otherMethod()
            // 找不到该方法,原因很简单,该动态代理对象是实现接口(MyInterface),不是继承接口实现类(MyInterfaceImpl),所以只有接口的方法,没有具体实现对象(myInterfaceImpl)的方法
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

相关标签: 学习记录