likes
comments
collection
share

Java静态代理和动态代理

作者站长头像
站长
· 阅读数 38
  • 前言

再开始之前我们先不使用任何代理来实现一个网络请求的流程。

定义一个请求的接口:

public interface Request {
    void request();
}

使用OkHttp来实现这个接口

public class OkHttpImpl implements Request {
    @Override
    public void request() {
        System.out.println("OkHttp请求成功");
    }
}

现在我们的网络请求已经写好了,我们测试一下:

Request request = new OkHttpImpl();
request.request();

输出: OkHttp请求成功

看起来挺好用的,但是项目经理是个老程序员了,没有用过OkHttp,非要说Volley比OkHttp好用,让你把所有网络请求换成Volley框架

我们使用Volley来实现Request接口

public class VolleyImpl implements Request{
    @Override
    public void request() {
        System.out.println("Volley请求成功");
    }
}

重新测试测试一下:

Request request = new VolleyImpl();
request.request();

输出: Volley请求成功

现在项目经理又来了,说:“你网络请求怎么连个加载框都有没?”,这个时候又得去改代码了,但是公司网络框架已经封住好了,不让随便修改,这个时候没有办法了,只能这样写了:

showDialog(); //显示加载进度条

Request request = new VolleyImpl();
request.request();

hideDialog(); //隐藏加载进度条

看起来代码没问题,但是项目中有上百个网络请求,难道每次写网络请求都要手动加上进度条的代码吗?这个时候你去问项目经理,项目经理说:“你去看看Java静态代理和动态代理,或许能找到答案~”。

  • 静态代理

Java静态代理和动态代理 看起来用户不需要直接访问网络框架了,而是先访问一个代理类,由代理类去执行网络请求,那我们先新建一个代理类:

public class RequestProxy implements Request {

    private final Request mRequest;

    public RequestProxy(Request request) {
        mRequest = request;
    }

    public void before(){
        System.out.println("开始请求");
        showDialog(); //显示加载进度条
    }

    public void after(){
        System.out.println("请求完成");
        hideDialog(); //隐藏加载进度条
    }

    @Override
    public void request() {
        before();
        mRequest.request();
        after();
    }
}

现在我们来测试一下:

Request request = new VolleyImpl();
RequestProxy proxy = new RequestProxy(request);
proxy.request();

输出: 
开始请求
Volley请求成功
请求完成

静态代理优点:

  1. 可以在代理类中对目标类进行扩展。
  2. 用户只需要使用代理类的方法,不需要关心真正实现方法。
  3. 用户可以通过代理类实现与真正逻辑的解耦。

静态代理的缺点:

  1. 如果增加一个接口,还需要重新写一个代理类。
  • 动态代理

动态代理不需要写代理类,能很好的弥补静态代理的缺点

我们需要使用Java内部给我们提供好的**Proxy.newProxyInstance()**方法

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

newProxyInstance方法需要传入三个参数:

  1. loader: 类加载器
  2. interfaces: 要代理的接口
  3. InvocationHandler: 会回调动态代理的消息

我们先来实现一下动态代理:

Request request = new VolleyImpl();
Object o = Proxy.newProxyInstance(request.getClass().getClassLoader(), new Class[]{Request.class}, new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("请求前");
        method.invoke(request, args);
        System.out.println("请求后");
        return null;
    }
});

((Request) o).request();

输出: 
请求前
Volley请求成功
请求后
  • 动态代理代码解析

我们先把要代理的接口传入到newProxyInstance方法中,并拿到代理对象“o”。

Object o = Proxy.newProxyInstance(request.getClass().getClassLoader(), new Class[]{Request.class}, new InvocationHandler() {})

我们可以把代理类强转成我们要代理的接口,然后直接调用方法

((Request) o).request();

这样代理类的invoke()方法就会被回调,我们看一下invoke()的三个参数:

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    return null;
}
  1. proxy: 代理类的对象
  2. method: 代理类调用的方法
  3. args: 代理类调用方法传的参数

既然回调方法中有method参数了,我们就可以利用反射直接掉用method.invoke(request, args)来调用方法了,同时我们也可以在调用方法前后加上要扩展的代码。

转载自:https://juejin.cn/post/6983846546844418062
评论
请登录