美文网首页
Java中的代理模式

Java中的代理模式

作者: 几行代码 | 来源:发表于2019-02-11 17:42 被阅读0次

因为Retrofit剖析源码的时候会用到ava中的代理模式,所以这篇就先回忆一下代理设计模式。
代理模式分为两种:
代理模式解释:为其他对象提供一种代理,用以控制对这个对象的访问。(直白一点就是代替别人去做一些我们想要做的事情)
1.静态代理(抽象类)


image.png

代码实现:

/**
 * 被目标对象和代理对象同时继承的抽象类
 */
public abstract class AbstractObject {
    protected abstract void operation(); // 经营预算
}

被代理对象:

/**
 * 目标对象 (被代理对象)
 */
public class RealObject extends AbstractObject{

    private static final String TAG = RealObject.class.getSimpleName();

    @Override
    public void operation() {
        Log.e(TAG,"do operation......");
    }
}

代理对象:

/**
 * 代理类
 */
public class ProxyObject extends AbstractObject {

    private static final String TAG = ProxyObject.class.getSimpleName();
    // 对目标类的引用
    private RealObject mRealObject;

    public ProxyObject(RealObject mRealObject) {
        this.mRealObject = mRealObject;
    }

    @Override
    public void operation() {
        Log.e(TAG,"do something before real operation......");
        if (mRealObject == null) {
            mRealObject = new RealObject();
        }
        mRealObject.operation();
        Log.e(TAG,"do something after real operation......");
    }
}

测试:

public static void main(String[] args) {
        ProxyObject proxyObject = new ProxyObject(new RealObject());
        proxyObject.operation();
    }

do something before real operation......
do operation......
do something after real operation......

2.动态代理(JDK实现/CJLib继承)

  • 概念解释:代理类在程序运行时创建的代理方式。
  • 相比于静态代理:动态代理可以很方便的去改变代理类的函数进行统一的处理,而不用去修改每一个代理类的函数,根据你相应的业务逻辑
  • 优点:无侵入式的扩展代码

JDK动态代理:Java内部的反射机制来实现的,这个机制在生成类的时候比较高效。(必须要针对接口进行代理)

  • 在不改变原来代码的情况下,在调用方法的前后,插入我们自己想要的逻辑。(例子)

  • 动态代理和静态代理最大的不同,动态代理的代理类是不需要手动生成的,是根据我们的配置在运行时动态生成的。(是在运行时生成的代理)

  • 需要用到InvocationHandler接口和Proxy类

代码示例:
被目标对象和代理对象都要实现的接口

/**
 * 动态代理
 * 被目标对象和代理对象都要实现的接口
 */
public interface InterfaceObject {
    void shopping();
}

被代理类 (目标类):

/**
 * 动态代理
 * 被代理类 (目标类)
 */
public class BeRepresent implements InterfaceObject {
    private static final String TAG = BeRepresent.class.getSimpleName();
    @Override
    public void shopping() {
        System.out.println("买点东西回来");
    }
}

代理类是由JDK动态创建的:

/**
 * 动态代理
 * 代理类:每个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接口的实现
 * 当使用者调用了代理对象,所实现的代理对象的接口时,这个调用的信息就会传递到InvocationHandler
 * 中的invoke方法中
 */
public class ProxyF implements InvocationHandler {

    private static final String TAG = ProxyF.class.getSimpleName();
    private Object target; // 要代理的真实对象

    public ProxyF(Object target) {
        this.target = target;
    }

    /**
     * 相当于一个拦截的方法
     * @param proxy   代理对象
     * @param method  代理方法
     * @param objects 代理方法中的参数
     * @return 返回值会返回给使用者
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
        System.out.println("代理对象:" + proxy.getClass().getName());
        System.out.println("代理方法中的参数:" + (objects != null && objects.length > 0 ? objects[0] : null));
        System.out.println("代理方法:" + method);
        System.out.println(" before ");
        method.invoke(target,objects);
        System.out.println(" after ");
    }
}

测试:

public static void main(String[] args) {
        InterfaceObject mBeRepresent = new BeRepresent();
        ProxyF proxy = new ProxyF(mBeRepresent);
        // java.lang.reflect.Proxy.newProxyInstance(....)方法获得真实对象的代理对象 (反射)
        InterfaceObject mInterfaceObject = (InterfaceObject) Proxy.newProxyInstance(mBeRepresent.getClass().getClassLoader()
                , mBeRepresent.getClass().getInterfaces(), proxy);
        // 通过代理对象调用真实对象相关接口中实现的方法,这个时候就会跳转到这个代理对象所关联的InvocationHandler
        // 的invoke方法中
        mInterfaceObject.shopping();
        // 获得真实对象的代理对象所对应的class对象的名称,用字符串表示
        System.out.println(mInterfaceObject.getClass().getName());
}

结果:

代理对象:com.sun.proxy.$Proxy0
代理方法中的参数:null
代理方法:public abstract void dynamicproxy.InterfaceObject.shopping()
 before 
买点东西回来
 after 
com.sun.proxy.$Proxy0

注意:被代理对象的类必须自己定义时就实现接口,从该类的祖辈类上继承的接口是无效的。
总结:
JDK实现原理:

1.拿到被代理对象的引用,然后获取它实现的接口
2.JDK重新生成一个类,同时实现获取到被代理对象所实现的接口
3.在代理类的静态构造块中,代理类通过反射获取了被代理类的详细信息
4.重新生成一个class字节码
5.然后编译
JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。

还有一种是CGlib实现的动态代理:
cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。

静态代理是通过在代码中显式定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法;
JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;
CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理;

最后,抛出两个问题:

1.retrofit为什么要使用动态代理 ?
答案:
因为1个静态代理只服务1种类型的目标对象,若要服务多类型的目标对象,则需要为每种目标对象都实现一个静态代理对象 ,在目标对象较多的情况下,若采用静态代理,则会出现 静态代理对象量多、代码量大,从而导致代码复杂的问题,而动态代理只需要1个动态代理类就可以解决创建多个静态代理的问题,避免重复、多余代码 更强的灵活性设计动态代理类(DynamicProxy)时,不需要显式实现与目标对象类(RealSubject)相同的接口,而是将这种实现推迟到程序运行时由JVM来实现,在使用时(调用目标对象方法时)才会动态创建动态代理类 & 实例,不需要事先实例化。

2.动态代理的缺点是什么?
答案:
效率低
相比静态代理中直接调用目标对象方法,动态代理则需要先通过Java反射机制 从而 间接调用目标对象方法。

应用场景局限
因为Java 的单继承特性(每个代理类都继承了 Proxy 类),即只能针对接口 创建 代理类,不能针对类 创建代理类即只能动态代理 实现了接口的类。

相关文章

  • java代理模式的那些事

    java代理模式-登场 什么是代理模式? 代理模式是java中的一种设计模式,它其实就是设置一个中间环节来代理你要...

  • java动态代理(JDK和cglib)(转载自http://ww

    java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是...

  • java设计模式之代理模式(静态代理)

      今天给大家分享的是java设计模式之代理模式中的静态代理模式,动态代理模式将在后面文章中给出。如有不足,敬请指...

  • Kotlin-强大的委托

    委托也叫代理,是一种可以以代理方式控制目标对象的访问,设计模式中成为-代理模式。 Java中,我们实现一个代理模式...

  • 代理模式——远程代理(Java RMI)

    代理模式——远程代理(Java RMI) @(设计模式) 一、远程代理——大使 在日常开发中,我们经常会有本地服务...

  • 连工厂模式都不知道,别说你会设计模式

    设计模式文章陆续更新 java单例模式java代理模式java状态模式 在Java面向对象编程中,我们通常会new...

  • Java代理模式之JDK动态代理

    了解什么是动态代理模式,可参考Java设计模式之代理模式 简介 JDK动态代理是java.lang.reflect...

  • 静态/动态代理模式

    代理, 顾名思义就是让别人替你完成或处理事情。 在Java设计模式中,代理模式又可分为静态代理和动态代理模式。静态...

  • Spring AOP详解

    AOP AOP的实现一般都是基于 代理模式 ,在JAVA中采用JDK动态代理模式,但是我们都知道,JDK动态代理模...

  • java之代理技术

    java之代理模式 直接聊技术! 描述 代理模式是常用的java设计模式,代理类主要负责为委托类预处理消息、过滤消...

网友评论

      本文标题:Java中的代理模式

      本文链接:https://www.haomeiwen.com/subject/lwoqeqtx.html