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

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();
        }
    }

}

发布了46 篇原创文章 · 获赞 13 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览