0%

【设计模式】Dynamic Proxy Pattern动态代理模式/JDK代理

动态代理模式的理解以及使用

首先请移步文章《代理模式》了解静态代理模式

动态代理

什么是动态代理

  动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。

动态代理对象

  代理类在程序运行期间,创建的代理对象称之为动态代理对象。这种情况下,创建的代理对象,并不是事先在Java代码中定义好的。而是在运行期间,根据我们在动态代理对象中的“指示”,动态生成的。也就是说,你想获取哪个对象的代理,动态代理就会为你动态的生成这个对象的代理对象。动态代理可以对被代理对象的方法进行功能增强。有了动态代理的技术,那么就可以在不修改方法源码的情况下,增强被代理对象的方法的功能,在方法执行前后做任何你想做的事情。

本质

利用反射机制在运行时创建代理类。

如何理解

动态代理也是遵循 《代理模式类图》 中通用的代理模式类图关系,与静态代理相比:

  1. 具体代理类($Proxy0)的生成是在运行期动态产生的,而非编译期就已经静态存在
  2. 具体代理类($Proxy0)与被代理类的代理关系($Proxy0持有Target的引用),是Proxy想办法动态注入进入$Proxy0;
  3. 具体代理类($Proxy0)对被代理类的功能的代理是在动态生成的代理类内部,是InvocationHandler想办法去动态的调用被代理类(Target)的对应方法的。
  • 无论是具体代理类的动态产生,还是与被代理类的关系建立,以及对被代理类方法的代理调用,这中间,都用到了两个关键的中间媒介,即Proxy和InvocationHandler。
    • Proxy类,其中提供了动态生成代理类的静态方法,并持有实现了InvocationHandler接口的引用。同时,所有生成的代理类也都是Proxy类的子类。
    • InvocationHandler接口,只包含一个抽象出来的方法名:invoke,使得实现InvocationHandler接口的类去具体实现,在实现中通过持有被代理类实体($Proxy0),并通过反射,去调用对应的实体方法。

因此,动态代理总体上的执行流程为
当客户端通过Proxy的静态方法生成动态代理类后,调用动态代理类对应的接口方法时,内部会调用其内部持有的InvocationHandler接口的实例对象的invoke方法,并得以调用到实际被代理实体的相应方法。

实现

  1. 接口
    Person.java
    1
    2
    3
    4
    public interface Person {
    public void listenNumber(String number);
    }

  2. 真实角色
    Foreigners.java
    1
    2
    3
    4
    5
    6
    7
    public class Foreigners implements Person {

    @Override
    public void listenNumber(String number) {
    System.out.println("听到的是:" + number);
    }
    }
  3. 代理角色
    DynamicProxy.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;

    public class DynamicProxy implements InvocationHandler {
    private Person person;

    public void setPerson(Person person) {
    this.person = person;
    }

    public Object getProxy() {
    return Proxy.newProxyInstance(this.getClass().getClassLoader(), person.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object invoke = method.invoke(person, args);
    return invoke;
    }
    }

  4. 调用者
    Me.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Me {
    public static void main(String[] args) {
    new Me().sayNumber("一");
    new Me().sayNumber("二");
    new Me().sayNumber("九");
    }

    public void sayNumber(String number){
    Foreigners foreigners = new Foreigners();

    DynamicProxy dynamicProxy = new DynamicProxy();
    dynamicProxy.setPerson(foreigners);
    Person person = (Person) dynamicProxy.getProxy();

    person.listenNumber(number);
    }
    }
  5. 结果
    1
    2
    3
    听到的是:1
    听到的是:2
    听到的是:9

感谢查阅