基于JDK的动态代理模式

前言

学习呢,在我看来有输入就要有输出,所谓的输入就是你看的视频,所谓的输出就是当你学完这个课程,你自己对这个视频的理解以及感受,简单地讲,我自己写博客,是为了记录自己学习的过程,当然,如果能给其他人带来帮助,那就更好不过了,旨在对自己学习的知识进行一个有效的输出,不然,看了白看!可能说有一点夸张,但是一点也不为过,举个我自己的例子,我曾经花费了一个多月的时间每天看一个有关于Java8的视频还有Git操作的视频,但是到现在为止,Java8只能说是简单的理解,因为脱离了实际,并且当时只是跟着写了代码案例,看完之后,自己的项目中也没有用到过,很快就忘记一些细节,甚至是以前很常规的操作。现在我在学习的时候,不再追求视频的速度,打个比方: 每天看一个Java8视频还有Git视频或者Spring源码视频,反正每天至少两个视频,首先呢,自己学着也很累,也很费时间,其次,过了一段时间之后就会发现,我特么上个月学了什么玩意?看到的知识竟然跟新的没什么区别!我总结了一下其本质原因在于缺乏自己的思考,以及输出的过程,现在我已经把步调慢了下来,哪怕是两天看一个我也心甘情愿!因为自己会有所输出,或者说深入思考一个程序或者设计模式(实际上用不了这么长时间),下面回归正题,说一下我对于JDK的动态代理模式是怎么样一个理解.

JDK动态代理模式的本意

首先说一下子我自己的理解: 首先我所在的项目用到了Zookeeper + Dubbo 这个服务注册与发现的中间件,其中Zookeeper是一个注册中心,假定我们是一个RPC(Remote Procedure Call),大概说一下这个RPC风格,在我现在所处的项目中分为三个模块,如下图:

VJh6z9.png

项目的架构如图所示:

  • 1.cs_api:存放的是实体类对象,就是我们常说的Entity或者Module类
  • 2.cs_consumer:从名字上作为一个消费者,那么它就是真正调用服务的,里面一般存放的是MVC架构中C—Controller层的东西
    • M:model一般使我们所说的实体类
    • V:view视图层,前端发过来请求,后端返回数据,将数据展示给前端
    • C:Controller我认为是请求处理层,前端发出请求,之后又Controller进行接收(中间省略了HandlerMapiing映射的过程),之后再交由DAO层进行数据请求
  • 3.cs_provider:一般是我们接口真正实现的地方,结合前面的cs_api与cs_consumer,调用过程如下图:

VJhJ2j.png

其中调用关系是:当客户端发出请求后,首先会经过CS_Consumer,Cs_Consumer会去Zookeeper上面寻找时候所调用的服务,也就是我们的CS_Provider是否将服务注册到了Zookeeper上面,如果说CS_Provider将服务注册到了Zookpper上面通过Dubbo,那么这个服务就算完成了,值得重视的一点是RPC风格是跨进程的,也就是说不在一个TOMCAT上面,其实说了这么多就是想说明一个问题:这件事CS_Consumer很想自己去完成,但是他自己完成不了,跨进程了所以他只能通过Zookeeper+Dubbo这种服务注册与发现的机制去完成,其中就用到了代理模式,他自己想做却做不了,只能通过别人去做,就是这样子一个道理

具体的细节性剖析,等我们将JDK的动态代理讲完,再回来仔细剖析下Zookeeper + Dubbo所使用的代理模式

我们以三种方式来阐述代理模式

假设我们阐述下面这个例子:
某男子去相亲,我们在这里就管他叫小王吧,小王年龄大了,整个人日渐消瘦,原因是:想找媳妇了,但是奈何职业的原因,没有时间,那么就需要按照如下去定义,为了通用性,不单单是给小王吧,我们给广大单身男性创造一个所通用的接口

  • 1.Person如下图

VJ4QyR.png

不使用代理模式

先明白一个道理:谁想要去干嘛? —> 小王想要找寻找真爱,从这句话中我们可以分析出几个元素

  • 1.小王
  • 2.寻找真爱

所以我们的代码,按照如下规格去定义

Person接口:

/**
 * @author Zerox
 * @date 2019/6/1 19:23
 * 首先这是一个接口,为了干什么呢?给广大单身男性提供方便的
 */
public interface Person {

    /**
     * 寻找真爱,
     */
    public void findTrueLove();

}

Xiaowang类:


/**
 * @author Zerox
 * @date 2019/6/1 19:34
 */
public class XiaoWang implements Person{

    private String name = "小王";

    private String sex = "男";
    /**
     * 小王寻找真爱
     */
    public void findTrueLove() {

        System.out.println("我的名字是" + this.name +  ",性别是:" + this.sex);
        System.out.println("我想要做的事情是寻找真爱!" );
        System.out.println("我的要求是: 肤白貌美大长腿");
    }
}

测试类BlogMains

/**
 * @author Zerox
 * @date 2019/6/1 19:38
 */
public class BlogMain {

    public static void main(String[] args) {

        Person xiaowang = new XiaoWang();

        System.out.println("当前类为:" + xiaowang.getClass());

        System.out.println("--- --- --- --- --- --- ---");
        xiaowang.findTrueLove();;
    }
}

输出结果为:
VJhoJe.png

我们可以看到一个东西:—> 即: 当前类为:class blog.XiaoWang,这里我们先打一个问号

使用代理模式

先明白一个道理:谁想要去干嘛? —> 小王想要找寻找真爱,但是小王没时间,所以他打算让媒婆去帮他寻找真爱,我们都知道媒婆有一个资源库(萌妹子库),他需要拿到小王的信息,然后,根据小王的要求,去一个一个寻找,直到寻找到一个合适的,从上面这段话,我们可以大概分析出以下的信息:

  • 1.小王
  • 2.媒婆
  • 3.媒婆需要拿到小王这个对象
  • 4.小王想寻找真爱,然后小王没时间,只能让媒婆去帮他找

与上面进行比较,我们少了哪一些过程呢?

  • 1.缺少媒婆对象
  • 2.媒婆需要拿到小王所有的资料信息
  • 3.这次寻找真爱,是媒婆接收了小王的委托,所以才寻找的,所以究其根本,这次寻找对象的人是媒婆代小王寻找,那么下面我们去实现一下

Person接口:

/**
 * @author Zerox
 * @date 2019/6/1 19:23
 * 首先这是一个接口,为了干什么呢?给广大单身男性提供方便的
 */
public interface Person {

    /**
     * 寻找真爱,
     */
    public void findTrueLove();

}

Xiaowang类:


/**
 * @author Zerox
 * @date 2019/6/1 19:34
 */
public class XiaoWang implements Person{

    private String name = "小王";

    private String sex = "男";
    /**
     * 小王寻找真爱
     */
    public void findTrueLove() {

        System.out.println("我的名字是" + this.name +  ",性别是:" + this.sex);
        System.out.println("我想要做的事情是寻找真爱!" );
        System.out.println("我的要求是: 肤白貌美大长腿");
    }
}

MeiPo类


/**
 * @author Zerox
 * @date 2019/6/1 20:00
 */
public class Meipo implements InvocationHandler {

    /**
     * 拿到小王这个对象
     */
    private Person xiaoWang;

    /**
     *
     * @param xiaowang 被代理的对象
     * @return 代理类
     */
    public Object getInstance(Person xiaowang) {

        this.xiaoWang = xiaowang;

        Class<?> clazz = xiaowang.getClass();

        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);

    };

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("我是媒婆.我来给你们找小妹妹,嘿嘿嘿~ ");
        xiaoWang.findTrueLove();
        System.out.println("筛选中。。。");
        System.out.println("匹配成功!");
        return null;
    }
}

测试类


/**
 * @author Zerox
 * @date 2019/6/1 19:38
 */
public class BlogMain {

    public static void main(String[] args) {

        Person person  = (Person)new Meipo().getInstance(new XiaoWang());

        System.out.println("当前调用类为:" + person.getClass());

        person.findTrueLove();

    }
}

输出结果为:
VJhLLt.png

我们可以看到一个东西:—> 即: 当前类为:class com.sun.proxy.$Proxy0g

下面我们来仔细分析一个这个动态代理模式,所涉及到的东西,其本质在于MeiPo类,首先MeiPo这个类他实现了一个接口InvocationHandler,我们来点进去看一下方法的简介如下图:

是这个样子的,她说的是一个代理对象方法的调用过程和他的返回结果,这个方法被调用是当代理对象调用所关联的方法的时候,在我们这里就是当我们生成如下代码:


		Person person  = (Person)new Meipo().getInstance(new XiaoWang());

        System.out.println("当前调用类为:" + person.getClass());

        person.findTrueLove()

    1. 第一行是生成代理对象,就是我们这个InvocationHandler的第一个参数proxy,当我们用proxy去调用findTrueLove的时候,就跟我们上面所描述的是一个样子的,但是我们不禁会问什么时候生成的代理对象?

在我们这里是geiInstance()方法会返回一个代理类,其根本原因是我们调用了这样子的一条语句:Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);,我们跟进去看一下,如下图,这个比较简单,但是我们不知道她什么时候去调用的Invoke方法?反正我是不知道的,下面我们再去找一找,如下图所示代码:
VJ48w6.png

反编译之后,如下图:
VJ4dld.png

VJ4YFO.png

很明显的说明了我们的调用过程: 当新生成的代理对象去调用我们的方法的时候,代理对象会去调用他所重新编码和分配的去调用,在我们这里就是调用了invoke方法,讲到这里这个简单的的动态代理模式就差不多到这里结束了,但是有点意犹未尽的感觉,为什么这么说呢!因为哦,最重要的如何生成代理对象的我们不知道!在下一篇博客中,我们将会继续阐述~如有问题,请联系xshlxx@126.om

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值