项目中常用到代理模式,本篇文章带大家回顾一下基本的操作以及动态代理生成的类。
1. 定义
代理模式: 为其它对象提供代理,带你对象挟持原对象类的引用,也称委托模式。 作用:可以在不修改原对象的功能前提下,对原对象在功能进行扩展。(通俗讲就是在当你原对象封装完毕或者你没办法修改,但是有一些增加的新的功能的时候,就可以在代理类上增加 符合“开闭原则”)
2. 代理的方式
静态代理
使用:手动创建源代码,在对其编译。 缺点:代理类跟原对象类实现一样的接口,所以会有很多代理类。并且,当接口增加方法,目标对象与代理对象都要对应修改。(怎么解决?改用动态代理。)
动态代理
使用:在程序运行时,利用反射机制动态创建。
3. 基本方式
- 静态代理的使用方式 (下面以高低端电脑的例子展示一下基本使用方式)
- 定义接口
- 分别定义两个被代理对象
- 创建静态代理类
- 使用方式
- 动态代理的使用方式
- 创建动态代理类
动态代理需要实现的是
InvocationHandler
接口,并重写invoke
方法,同样也是要挟持被代理类的对象。 在invoke
方法中可以看到,使用的method.invoke(mComputer,args);
传入对象跟args
便可以实现方法被调用时自动调用。在这个地方,其实你可以做的事情很多,比如你想知道方式的执行时间,你可以在
method.invoke()
的关键点1
跟关键点2
,加上时间,根据两个时间差来计算一下这个方法的大致运行时间。(实现AOP(面向程序切面编程))
- 使用
关键代码1:是看人家网上说的可以将代理类生成的一句代码,等下再贴一下代理类的代码 关键代码2:这里可以看到
Proxy.newProxyInstance
传入了三个参数。第一个参数
ClassLoader loader
:被代理的类的类加载器,通过它生成代理的class文件。第二个参数
Class<?>[] interfaces
:被代理类实现的所有接口字节码,代理类需要知道并实现第三个参数
InvocationHandler h
:调用处理程序调度方法调用,也就是第一步我们定义好的那个ComputerDynamicPro
实现了InvocationHandler
接口的动态代理类。
我们来看一下关键代码1中为我们生成的代理类的代码吧
可以看到上面
class $Proxy0 extends Proxy implements Computer
也是要实现我们的接口。在代码最下面可以看到静态代码块中,使用了反射将所有方法获取到。 每个方法中都调用super.h.invoke()
这样的一个代码 并且传入三个参数this
,反射获取的方法
,参数数组
。super.h
实际上父类的h
也是$Proxy0
中的InvocationHandler
,在构造函数的时候传递上去的public $Proxy0(InvocationHandler var1) throws { super(var1); }
。 这里你就可以明白了为什么我们要动态代理类要实现InvocationHandler
并实现invoke
方法,并且inovke
方法的三个参数是什么时候传递进来的。
总结一下:
静态代理跟动态代理的区别: 静态代理:需要自己手动生成类文件,并且被代理类跟代理类都需要实现同样的接口,当接口改变时代理类跟被代理类都需要修改。 动态代理:只需实现
InvocationHandler
,并重写invoke
方法。不需要知道也用不着实现接口,当接口改变的时候也只需要改变invoke
中的逻辑便可以。