【11】动态代理原理

(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)好好活就是做有意义的事情.
(8)亡羊补牢,为时未晚
(9)科技领域,没有捷径与投机取巧。
(10)有实力,一年365天都是应聘的旺季,没实力,天天都是应聘的淡季。
(11)基础不牢,地动天摇
(12)写博客初心:成长自己,辅助他人。当某一天离开人世,希望博客中的思想还能帮人指引方向.
(13)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~

动态代理原理

1.静态代理

(1)代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

(2)通俗的来讲代理模式就是我们生活中常见的中介。比如你按照小卡片上的电话打过去寻求服务,一般不是由本人,可能是一个成年雄性接听电话,然而真正做事情的可能是另一个小姐姐。

1.1目的

(1)通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性;

(2)通过代理对象对访问进行控制;

1.2代理模式一般会有三个角色

在这里插入图片描述

1.2.1抽象角色

指代理角色和真实角色对外提供的公共方法,一般为一个接口。

1.2.2真实角色

需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。也就是真正的业务逻辑在此。

1.2.3代理角色

需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。将统一的流程控制都放到代理角色中处理!

1.3静态代理的缺陷

(1)静态代理在使用时,需要定义接口或者父类,被代理对象(真实对象)与代理对象一起实现相同的接口或者是继承相同父类。

(2)一般来说,被代理对象(真实对象)和代理对象是一对一的关系,当然一个代理对象对应多个被代理对象(真实对象)也是可以的。

(3)静态代理,一对一则会出现静态代理对象量多、代码量大,从而导致代码复杂,可维护性差的问题,一对多则代理对象会出现扩展能力差的问题。

(4)静态代理对象只能为一个接口进行服务,如果要代理其他服务,需要创建其他的代理对象,即多一个服务,就要多创建一个代理类。这样就会产生很多的代理类。

2.动态代理

一个代理类,实现全部的代理功能,此时就需要使用到动态代理。

(1)在运行时再创建代理类和其实例,因此显然效率更低。

(2)要完成这个场景,需要在运行期动态创建一个Class。JDK提供了Proxy 来完成这件事情。

  • Proxy可以帮我们动态创建代理对象

  • Proxy.newProxyInstance()
    第一个参数是一个ClassLoader,类加载器。
    第二个参数是一个数组,JDK实现的动态代理,只能够帮我们代理接口,而且可以代理多个接口。
    第三个参数是InvocationHandler

  • 在使用的时候,真实对象实现了第二个参数中指定的多个接口。

  • 这个代理对象如何调用到真实对象的方法呢?

  • InvocationHandler接口,它在这里起到什么作用呢?起到一个回调的作用。

  • 当动态代理对象去调用真实对象的方法的时候,就会由InvocationHandler监听到调用了哪个方法,将其传递到invoke中去。

(3)基本使用如下:

//抽象角色
interface Api {
	void test(String a);
}


//真实角色
class ApiImpl{

    @Override
    public void test(String a) {
  	  System.out.println("真实实现:" + a);
    }
    
}


//创建真实角色实例
ApiImpl api = new ApiImpl();

//JDK动态代理:
Object o = Proxy.newProxyInstance(getClass().getClassLoader(),

new Class[]{Api.class}, //JDK实现只能代理接口

new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //执行真实对象方法
        return method.invoke(api, args);
    }
});

//转换代理对象
Api api = (ApiImpl) o;
//用代理对象调用真实对象方法,此时InvocationHandler中的invoke()方法将会被回调
//public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
//参数1 Object proxy用于指定通过哪个代理对象回调真实对象的方法。
//参数2 Method表示动态代理对象回调哪一个被代理的方法。
//参数3 Object[] args表示代理对象回调被代理方法时所需要传递的参数。
api.test();

(4)实际上, Proxy.newProxyInstance 会创建一个Class,与静态代理不同,这个Class不是由具体的.java源文件编译而来,即没有真正的文件,只是在内存中按照Class格式生成了一个Class。

String name = Api.class.getName()+"$Proxy0";
//生成代理指定接口的Class数据
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{Api.class});
FileOutputStream fos = new FileOutputStream("lib/" + name+".class");
fos.write(bytes);
fos.close();

(5)然后可以在生成的文件中查看我们的代理类:

在这里插入图片描述
(6)在初始化时,获得method 备用。而这个代理类中所有方法的实现变为:

在这里插入图片描述

(7)这里的h 其实就是InvocationHandler 接口,所以我们在使用动态代理时,传递的InvocationHandler 就是一个监听,在代理对象上执行方法,都会由这个监听回调出来。

3.代理模式的应用场景

3.1网络请求

(1)早期使用Volley框架
(2)现在又使用了OkHttp框架,想把Volley切换成OkHttp
(3)如果把使用Volley框架的地主切换成OkHttp框架,会非常的麻烦。
在这里插入图片描述

3.2将其做一个代理模式的改造

(1)在Volley与OkHttp之间添加一个隔离层
(2)这个隔离层它实现了一个Interface,有一个get方法进行get请求,有一个post方法实现post请求。
(3)然后在使用到某一个具体框架的时候,也请行一个封装,该封装层也实现Interface。
(4)在隔离层里面给一个Interface的成员,这里就可以把隔离层看成是代理模式中的代理对象。
(5)真实对象就是具体网络请求框架的封装层
(6)程序当中,要进行网络请求的地方,直接操作隔离层就可以了。
(7)当隔离层当中需要使用Volley的时候,就将Volley的封装层赋值给隔离层里面的HttpRequest
(8)如果要将Volley切换成OkHttp,就可以为OkHttp创建一个封装层
(9)我代码当中的网络请求,不需要关心真正的网络请求到底是谁实现的,我只需要通过隔离层去发请求就可以了。只需要隔离层对象切换成OkHttp框架封装层对象就可以了。
在这里插入图片描述

4.类的完整生命周期

4.1一个类是怎么来的?

(1)一个类是编译一个Java源文件
(2)经过编译为Java字节码文件
(3)字节码文件经过类加载器转画成为JVM中的Class对象
(4)然后通过实例化,生成实例对象。
(5)实例对象不用了,则由JVM垃圾回收器进行回收卸载。
在这里插入图片描述

4.2字节码是怎么来的呢?

(1)有一个实实在在的文件,来自于硬盘。

4.3动态代理它的一个Class是什么呢?

(1)它是由内存来的,在内存中生成的,没有一个真正的文件去对应的。

4.4动态代理的Class对象里面长什么样子?

(1)在Proxy里面有一个ProxyClassFactory类,会利用这个类去生成动态代理类的class。
(2)即byte[] var22 = ProxyGenerator.generateProxyClass(var23,var2,var17);
(3)这个生成出来的class数据就是一个byte[]数组
(4)然后将这个byte[]数组数据变成一个Class<?>对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值