博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
什么是代理模式?
阅读量:6223 次
发布时间:2019-06-21

本文共 7235 字,大约阅读时间需要 24 分钟。

首先上一个自己的结论,带着结论看文章可能更好理解~

总结:动态代理最终生成的代理类会实现你传入的所有接口,并在每一个实现的接口方法中调用InvocationHandler的invoke方法,在这个方法中需要我们将自己所需要的逻辑加入进去,这样就给你每一个实现的方法都套用上了相同的逻辑,达到减少代码松耦合的效果。
当一个或多个接口的实现方法中都需要套用上相同的逻辑就可以直接使用动态代理模式,达到减少代码松耦合的效果。

1. 静态代理

常规的代理模式有以下三个部分组成:

  • 功能接口
interface IFunction {    void doAThing();}复制代码
  • 功能提供者(接口的实现类)
class FunctionProvider implement IFunction {    @Override    public void doAThing {        System.out.print("do A");    }}复制代码
  • 功能代理者
public class Proxy implements IFunction {    private IFunction provider;    Proxy(IFunction provider) {        this.provider = provider;    }    @Override    public void doAThing() {        //在这里可以添加自己需要给每个功能提供者都代理上的公用逻辑        doSomeThing();        provider.doAThing();    }    private void doSomeThing() {        System.out.println("This Time:" + (System.currentTimeMillis()));    }}复制代码

运行一下看最终结果

public class MyClass {    public static void main(String args[]) {        IFunction iFunction = new FunctionProvider(); //新建具体实现类        Proxy proxy = new Proxy(iFunction); //放入代理类        proxy.doAThing(); //执行最终的逻辑,给方法套用相同的逻辑    }}复制代码

可以看到如果使用静态代理,随着接口的增多,每新增或修改接口都需要改变代理类,这无疑是很不方便的。

2.动态代理

实现动态代理包括三步:

  1. 新建委托类;
  2. 实现InvocationHandler接口,这是负责连接代理类和委托类的中间类必须实现的接口;
  3. 通过Proxy类新建代理类对象。
  • 新建委托类
public interface IFunctionProxy {    void doAThing();    void doBThing();    void doCThing();}复制代码
public class IFunctionProxyImpl implements IFunctionProxy {    @Override    public void doAThing() {        System.out.println("I am handle doAThing Method ");    }    @Override    public void doBThing() {        System.out.println("I am handle doBThing Method ");    }    @Override    public void doCThing() {        System.out.println("I am handle doCThing Method ");    }}复制代码
  • 实现InvocationHandler并且通过Proxy类新建代理类对象。
public class MyClass {    public static void main(String args[]) {        final IFunctionProxyImpl functionProxy = new IFunctionProxyImpl();        Object proxyInstance = java.lang.reflect.Proxy.newProxyInstance(functionProxy.getClass().getClassLoader(), new Class[]{IFunctionProxy.class}, new InvocationHandler() {            @Override            public Object invoke(Object obj, Method method, Object[] objects) throws Throwable {            //method表示代理对象被调用的方法。             //objects表示代理对象被调用的方法的参数。//                if (method.getName().equals("doAThing")) {//                    System.out.print("do A:" + System.currentTimeMillis());//                }                System.out.println("Start:" + System.currentTimeMillis());                method.invoke(functionProxy, objects); //主动调用方法                System.out.println("End:" + System.currentTimeMillis());                return obj;            }        });        IFunctionProxy iFunctionProxy = (IFunctionProxy) proxyInstance;        iFunctionProxy.doAThing();        iFunctionProxy.doBThing();        iFunctionProxy.doCThing();    }}复制代码

看下运行的结果:

当然你还可以直接传入接口而不传入委托类去生成代理对象,但这样的话就无法在invoke方法中调用method.invoke了(因为没有具体的实现方法),Retrofit框架用的就是这种生成代理对象的方法.

Object proxyInstance = java.lang.reflect.Proxy.newProxyInstance(IFunctionP.class.getClassLoader(), new Class[]{IFunctionP.class, IFunctionProxy.class}, new InvocationHandler() {    @Override    public Object invoke(Object obj, Method method, Object[] objects) throws Throwable {        System.out.println("Start:" + System.currentTimeMillis());        System.out.println("End:" + System.currentTimeMillis());        return obj;    }});IFunctionProxy iFunctionProxy = (IFunctionProxy) proxyInstance;iFunctionProxy.doAThing();iFunctionProxy.doBThing();iFunctionProxy.doCThing();IFunctionP iFunctionProxy1 = (IFunctionP) proxyInstance;iFunctionProxy1.doIFunctionP();复制代码

可能看到此处还是一脸懵逼,下面让我用一下伪代码实现最终的类,以上方接口为例子

public class Proxy implements IFunctionP, IFunctionProxy {    InvocationHandler invocationHandler = new InvocationHandler() {        @Override        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {            System.out.println("Start:" + System.currentTimeMillis());            System.out.println("End:" + System.currentTimeMillis());            return null;        }    };    @Override    public String doIFunctionP() {        try {            Method method = IFunctionP.class.getMethod("doIFunctionP");            return (String) invocationHandler.invoke(this, method, null);        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (Throwable throwable) {            throwable.printStackTrace();        }        return null;    }    @Override    public void doAThing() {        try {            Method method = IFunctionProxy.class.getMethod("doAThing");            invocationHandler.invoke(this, method, null);        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (Throwable throwable) {            throwable.printStackTrace();        }    }    @Override    public void doBThing() {        try {            Method method = IFunctionProxy.class.getMethod("doBThing");            invocationHandler.invoke(this, method, null);        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (Throwable throwable) {            throwable.printStackTrace();        }    }    @Override    public void doCThing() {        try {            Method method = IFunctionProxy.class.getMethod("doCThing");            invocationHandler.invoke(this, method, null);        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (Throwable throwable) {            throwable.printStackTrace();        }    }}复制代码

可以看到最终生成的代理类会实现你传入的所有接口,并在每一个实现的接口方法中调用InvocationHandler的invoke方法,这个方法中需要我们自己将自己所需要的逻辑加入进去,这样就给你每一个实现的方法都套用上了相同的逻辑,这样就达到减少代码,松耦合的效果。

使用场景

一个或多个接口的实现方法中都需要套用上相同的逻辑就可以直接使用动态代理模式去生成对象,达到减少代码松耦合的效果。

  • 使用动态代理前伪代码如下:
Dao {    insert() {        判断是否有保存的权限;        开启事务;        插入;        提交事务;    }    delete() {        判断是否有删除的权限;        开启事务;        删除;        提交事务;    }}复制代码

使用动态代理的伪代码如下:

// 使用动态代理,组合每个切面的函数,而每个切面只需要关注自己的逻辑就行,达到减少代码,松耦合的效果invoke(Object proxy, Method method, Object[] args)                    throws Throwable {    判断是否有权限;    开启事务;    Object ob = method.invoke(dao, args);    提交事务;    return ob;}复制代码
  • Retrofit框架
ublic 
T create(final Class
service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(service); } return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class
[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); private final Object[] emptyArgs = new Object[0]; @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } return loadServiceMethod(method).invoke(args != null ? args : emptyArgs); } });}复制代码

要注意的是Retrofit并没有委托类,它只是很巧妙的运用了动态代理可以给所有执行的方法都套用上相同逻辑的特性,以此生成最终的Call类。

转载于:https://juejin.im/post/5c87c21df265da2dcd7a1ea6

你可能感兴趣的文章
利用Python实现卷积神经网络的可视化
查看>>
【译】Java、Kotlin、RN、Flutter 开发出来的 App 大小,你了解过吗?
查看>>
你不得不知的Event Loop
查看>>
canvas 时钟
查看>>
clipboard.js代码分析(3)- good-listener
查看>>
如何解决C语言,函数名与宏冲突
查看>>
C 标准库 - string.h之strpbrk使用
查看>>
Java开发
查看>>
百万英雄,芝士超人,冲顶大会等答题助手
查看>>
WPF:Graphics图画--Brushes画刷--VisualBrush可视画刷
查看>>
Spring Boot 中使用 MongoDB 增删改查
查看>>
【362天】跃迁之路——程序员高效学习方法论探索系列(实验阶段120-2018.02.02)...
查看>>
关于Android Gradle你需要知道这些(4)
查看>>
【友盟+】首创SDK自动化测试框架,解决SDK测试痛点
查看>>
程序的基本形状
查看>>
常用css3整理
查看>>
算法(第四版) 自学笔记 1
查看>>
【Chrome扩展开发】定制HTTP请求响应头域
查看>>
Android-IM从零开始开发一个即时通讯项目
查看>>
你不知道的JSON.stringify()妙用
查看>>