spring 动态代理模式趣解

网上有很多关于 spring 动态代理模式的解释还有实现的代码,但是对于初学者来说都不太容易理解。所以这篇文章我想采用一种比较简洁生动的描述来简单的说一下动态代理模式,如果你是初学者或者小白,这篇文章或许会对你有所帮助。

什么是动态代理模式

官方解释这里就不提了。

这么说吧,咱们每个人可能都会遇到租房的情况,我们作为租房的客户唯一的目的就是租到房子,搬进去住。但是我们是直接找到房子交钱然后就齐活的吗?恐怕大部分情况是在入住之前会有一个中介屁颠屁颠的领着我们先去看房,看完房之后如果满意,然后再找房东签订合同,咱们交钱入住,他们收费闪人。

有人会问了,这和动态代理有什么关系呢?可以这么理解,把租房看成一个方法,在我们执行这个方法的时候,表面上我们只执行了这一个方法,实际上在运行该方法之前我们还运行了另外一个方法,即看房,然后我们才签了合同才算租房成功。只不过这个看房的方法是动态的放在我们租房方法之前执行的。

这就叫动态代理,不知道大家能否理解?也可以这么理解,就是说,只要我们一触发租房的方法,必然会先运行看房的方法,然后再运行租房的方法。

代码实现

以下是我写的实现上面所述动态代理的代码。

  • 租房的方法(抽象方法):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 租房的接口
    * 抽象的方法
    */
    public interface IRent
    {
    /*
    * 租房
    */
    void rent();
    }
  • 真实角色房东:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /**
    * 房东
    * 真实角色
    */
    public class Landlord implements IRent
    {
    @Override
    public void rent()
    {
    System.out.println("=====Landlord====rent====签合同===");
    }
    }
  • 动态代理类,实现 InvocationHandler 接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    public class MyDynProxy implements InvocationHandler
    {
    /*
    * 指明为谁做代理,target 为真实角色
    * */
    private Object target;//这里是房东;
    public void setTarget(Object target)
    {
    this.target=target;
    }
    public Object getTarget()
    {
    return target;
    }
    /**
    * 专门生成代理角色(中介)
    * IRent agency = new Agency(landlord);
    * @return
    */
    public Object newTargetProxy()
    {
    /**
    * 参数1:代理类的类加载器
    * 参数2:代理类要实现的接口;中介就是代理类,实现IRent接口,可以通过 target.getClass.getInterfaces(获取所有的接口)
    * 参数3:需要传入一个 InvocationHandler,传入 this指的是 MyDynProxy.
    */
    return Proxy.newProxyInstance(this.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
    }
    /*
    * 当代理角色的方法被执行时,会执行这个 invoke 方法;当 执行到 MyDynClient 中的 rent.rent(); 处,会调到此处执行该方法
    * */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
    System.out.println("=========invoke=======");
    this.seeHouse();
    /*
    * 会调用真实角色(比如:房东)的方法
    *
    * 调用对象的方法
    * 参数1:对象
    * 参数2:方法的参数,可以从 invoke 的参数中获取
    * */
    Object object = method.invoke(this.getTarget(), args);
    this.fee();
    return object;
    }
    private void fee()
    {
    System.out.println("=====收费====");
    }
    private void seeHouse()
    {
    System.out.println("======看房=====");
    }
    }
  • 客户,也就是我们自己:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /**
    * 客户
    */
    public class MyDynClient
    {
    public static void main(String[] args)
    {
    Landlord landLord=new Landlord();//创建真正的房东;
    /*创建一个对象,该对象能生成动态代理角色(也就是中介)*/
    MyDynProxy dynProxy=new MyDynProxy();
    /*设置真实角色*/
    dynProxy.setTarget(landLord);
    /*
    * 利用上面生成的对象创建代理类
    * 返回抽象角色,也就相当于中介
    * */
    IRent rent=(IRent)dynProxy.newTargetProxy();
    /*调用抽象接口中的方法,也就是租房方法*/
    rent.rent();
    }
    }

首先,运行 MyDynClient 中的 main 方法,得到结果如下:

运行结果

代码中写了比较详细的解释,如果对这段代码的运行不是很清楚,可以自己试着打个断点运行一下。

如果对您有所帮助,实在是很开心,记得关注哦。