动态代理实战

程序为什么需要代理?
当一个对象要做的事情过多,可以通过代理来转移一部分职责。
对象有什么方法想要被代理,代理就一定有对应的方法。

动态代理

动态代理它可以直接给某一个目标(被代理 对象)对象(实现了某个或者某些接口)生成一个代理对象,而不需要代理类存在。
动态代理与代理模式原理是一样的,只是它没有具体的代理类,直接通过反射生成了一个代理对象。

JDK中提供的动态代理生成

1、Java.lang.reflect.Proxy类可以直接生成一个代理对象

Proxy.newProxyInstance方法参数介绍

//参数1:
//ClassLoader:用于指定一个类加载器,通常是当前类.class.getClassLoader()
//参数2:
//Class[] interfaces:
//指定生成的代理接口的类,即需要实现哪些方法,可以接收一个或多个接口
//InvocationHandler:
//用来指定生成的代理要干什么事情

//返回值:
该方法返回object对象,需要进行强转成需要的代理对象。
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

2、InvocationHandler方法参数介绍

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

invoke回调方法,是动态代理模式实现的核心。
每当创建的代理对象调用声明的接口方法时,就会去触发这个invoke回调方法,将代理对象、当前方法、和参数都回调到invoke,内部要做的事情就需要自主实现。并将该方法进行返回,invoke会返回object来作为任何方法的返回值。

Object proxy:代理对象
Method method:被代理对象当前被调用的方法(当前被调用的接口方法)
Object[] args:接口定义方法的参数数组

实战示例:
实现一个明星类可以唱歌跳舞,需要生成代理来实现准备话筒,准备场地的事情。


1.创建接口用来定义好被代理类需要代理出去的方法

public interface Star {
    //接口用来定义好被代理类需要代理出去的方法

    String sing(String name);

    void dance(String name);

}

2.创建需要进行代理的类,并实现如上接口

public class BigStar implements Star {
    //需要实现需要代理方法创建的接口Star接口,去做真实的实现
    private String name;

    public BigStar(String name) {
        this.name = name;
    }

    @Override
    public String sing(String song) {
        System.out.println("唱一首" + song);
        return "谢谢";
    }

    @Override
    public void dance(String dance) {
        System.out.println("跳一个" + dance);
    }
}

3.创建代理生成类,内部实现用Proxy.newProxyInstance创建代理对象,并定义好invoke方法:

public class ProxyUtil {

    //定义生成代理对象方法
    //方法传入接口来定义生成哪个接口的代理,并返回实现该接口的对象
    public static Star createProxy(Star bigStar) {
        Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //对各个调用事件进行判断分别处理
                        if (method.getName().equals("sing")) {
                            Log.i("minfo", "收钱20w");
                        } else if (method.getName().equals("dance")) {
                            Log.i("minfo", "收钱100w");
                        }
                        return method.invoke(bigStar, args);  //这里再使用反射调用被代理对象的当前方法
                    }
                });
        return starProxy;
    }
}

4.执行测试:

         Star bigStar = new BigStar("Lisa");
        Star starProxy = ProxyUtil.createProxy(bigStar);
        String result = starProxy.sing("solo"); //代理来唱歌
//        starProxy.dance("惊鸿舞"); //代理来跳舞

        Log.i("minfo", "sing结果:" + result);

5.调用结果:


实现场景2

Retrofit进行网络请求,每当调用ApiService的某个请求方法是,会在动态代理中回调该方法,Retrofit会统一使用反射获取method所携带的请求类型注解信息,请求返回类型和泛型类型,进行对象解析,返回类型转换,并且封装成ServiceMethod,传递给okhttp进行真实请求。

参考:
https://www.bilibili.com/video/BV1ue411N7GX?p=1&vd_source=40c24e77b23dc2e50de2b7c87c6fed59

Github参考代码:

https://github.com/running-libo/DesignPatten

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容