(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<?>对象