黑马程序员--09.动态与代理AOP--05【推理动态代理类内部结构II】【动态代理类运行原理】

动态代理与AOP—-5

推理动态代理类内部结构II

动态代理类运行原理

———– android培训java培训、java学习型技术博客、期待与您交流! ————

上次课讨论了动态代理类的内部基本结构以及InvocationHandler的来历。这次我们继续讨论InvocationHandler接口的实现类如何与动态代理类进行结合以及动态代理类的运行原理。

1.    推理动态代理类内部结构II

1). 推断动态代理类的内部结构3—–从融合接口InvocationHandler类和动态代理类角度考虑

(1). InvocationHandler实现类怎样融合到动态代理类中

[1]. 假设InvocationHandler的实现类(设为MyInvocationHandler类)代码如下

public class MyInvocationHandler {
    private ArrayList target =new ArrayList();
public invoke(Object proxy, Method method,Object...args){
       //交叉业务
       method.invoke(target, args);
       //交叉业务
    }
}

现在的问题就是:独立出来的InvocationHandler的实现子类MyInvocationHandler如何起到原来$Proxy类中invoke的作用?

[2]. InvocationHandler实现子类$Proxy的结合

{1}. InvocationHandler实现子类$Proxy结合的可行性

$Proxy0是动态产生的,不存在真实的文件系统的字节码文件。所以不能直接动态代理类$Proxy0直接结合

{2}. InvocationHandler实现子类$Proxy直接父类Proxy类结合的可行性

由于$Proxy类的直接父类Proxy不是动态产生的字节码文件,所以可以想办法将动态代理类的直接父类Proxy类InvocationHandler的实现子类进行组合。

{2}1. 以继承的方式组合这两个类么?不可以,因为两个类之间不具备父子关系,所以不能写成继承关系。

{2}2. 如果让Proxy类直接实现InvocationHandler接口,可以么?也不行。因为Proxy是Java的核心类,所有的方法都是写好的。但是InvocationHandler的invoke方法就是用来存放用户自定义的交叉业务的存储区域,所以也不能把Proxy类作为InvocationHandler的实现子类。

{2}2. 那就把InvocationHandler接口的引用聚合的方式组装到Proxy中。也就是将InvocationHandler类型的引用以Proxy成员变量的形式和Proxy类组合。

Proxy动态生成的动态代理类的子类的时候,动态代理类就会自动继承父类InvocationHandler属性了。

因此注意到Proxy源代码中,InvocationHandler类型的属性访问修饰符就是protected类型不是private类型

public class Proxy implements java.io.Serializable {
    //...
protected InvocationHandler h;
//...
}

(2). 初始化Proxy类的InvocationHandler成员的方式

[1]. 常用初始化类的成员变量的方式

{1}. 采用显示初始化方式

就在声明成员变量的位置直接进行赋值。

注意】这种方式用到Proxy的InvocationHandler类型的成员属性上并不可取!因为如果直接进行显示初始化的话,必须去对InvocationHandler的实现子类进行new但是Proxy类在定义的时候也不知道InvocationHandler的子类是谁,所以这种显示初始化的方式不可以

{2}. 在指定的构造方法中通过对构造方法传参进行指定成员变量的初始化

通过子类构造调用父类构造可以实现子类 (动态代理类实例) 实例在继承了父类的InvocationHandler的基础之上又通过调用的父类构造方法实现了对InvocationHandler属性的初始化。这种方式可行,下面详细阐述。

(3). 实例化动态代理类需要调用的父类Proxy的构造方法解析

[1]. 子类构造方法的特点【知识点回顾

{1}. 任何子类构造方法直接或者间接在其第一行调用了父类的构造方法

{1}1. 如果父类的所有的构造方法中非私有化空参的构造方法,并且子类构造方法第一行也没有显示指定,那子类构造第一行一定是调用父类非私有化空参构造方法

{1}2. 如果父类的构造方法中不满足{1}1中的条件,此时子类构造方法必须显示在其第一行指定调用的父类构造方法

[2]. Proxy构造方法解释

{2}. $Proxy0的父类Proxy的构造方法有两个

{2}1. private无参构造

private Proxy() {}

这个构造方法私有化完全是为了成全Proxy想成为工具类的愿望斯必须做的。但是这样一来,这个构造方法对Proxy的子类就是不可见的。所以$Proxy0的构造方法的第一行就必须指定一个父类其他的非私有的构造方法才可以。因此有了下面的第二个构造方法。

{2}2. protected有参构造

protected InvocationHandler h;
protected Proxy(InvocationHandler h) {this.h = h;}

因此推断的动态代理类的构造方法必须写成:

protected $Proxy0(InvocationHandler h) {
    super(h);
}

分析】这样当Proxy类通过自身的newProxyInstance(ClassLoaderloader, Class<?>[] interfaces, InvocationHandler h) 或者直接通过反射的形式proxyClass.getConstructor(newInvocationHandler(){

});的方式动态生成代理类的实例的时候,就会在自身的构造方法中调用super(h);以达到对Proxy的InvocationHandler的属性进行初始化的效果。

(4). 总结java.lang.reflect.Proxy的作用

[1]. 以工具类的身份出现:所有的public方法全部静态化并且空参构造私有化

—-主要作用直接通过getProxyClass( )生成没有字节码的子类Class对象

[2]. 以动态代理类的直接父类出现

—-主要作用存储动态代理类要调用的含有交叉业务代码目标类对象的invoke方法。

2.    动态代理类的工作原理

知道了InvocationHandler实现子类的如何在动态代理类中起作用之后,可以分析一下动态代理类运行的原理了。

1). 用代理类实例运行的原理图

《黑马程序员--09.动态与代理AOP--05【推理动态代理类内部结构II】【动态代理类运行原理】》

图中的圈1,圈2,圈3,圈4分别代表动态代理类的运行步骤的四个步骤

2). 动态代理类的运行步骤

(1). 将InvocationHandler实现子类的实例聚合到Proxy的成员属性上

聚合方式有两种:

[1]. 向动态代理类Class对象getConstructor()方法传入InvocationHandler子类对象

通过Proxy类的getProxyClass()方法获取动态代理类Class对象

[2]. 直接Proxy.newProxyInstance()方法传入InvocationHandler子类对象

结论】生成了动态的代理类内存字节码并且存储交叉业务+ 对目标类方法的调用的代码聚合到了动态代理类实例对象中。

(2). 客户端Client方法调用代理类实例某个某几个方法

(3). 代理类实例的各个方法会将客户端对自己方法的请求指派给从父类继承的InvocationHandler引用invoke方法

(4). InvocationHandler引用invoke方法将对代理类各个方法的请求转发给目标类对象相应的方法

———– android培训java培训、java学习型技术博客、期待与您交流! ————

    原文作者:AOP
    原文地址: https://blog.csdn.net/benjaminzhang666/article/details/10175655
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞