目录
1 静态代理模式
1.1 案例一:出租房屋
1.1.1 无代理模式
1.1.2 有代理模式
1.1.3 代理模式代码分析
分析1:
为何使用组合的方式获取Host?
为何不使用继承获取Host?
分析2:
Clicent.java中为何写了两种获取proxy对象?有何区别?
1.2 案例二:增删改查
1.2.1 无代理模式
那如果有1万个不同的增删改查,岂不是得修改源代码1万次,实际的项目中,该文件关联许多其他的文件,你一个实习生一过来就修改人家公司源代码,这是绝对不允许的,那怎么办呢?设置一个代理就可以了
1.2.2 代理模式
1.2.3 代理模式代码分析
Proxy.java 文件中,熟悉的套路
- 组合方式获取实现类
- 创建 set方法 或者 有参构造的方法
- 重写接口
2 动态代理模式
2.1 案例一: 代码体验
2.2 逻辑分析
这就是动态的初步理解!
2.3 代码分析
经过前面的梳理,我们从上帝的视角出发,知道了动态代理大概是怎么一回事:就是调用系统封装好的一个Proxy代理类,实现代理功能嘛。接下来我们具体分析一下代码,看看是简单的调用吗?为什么要这样调用,原理是什么?带着等等问题我们往下分析
这个图大致表达了各个方法之间的联系
思考 : 二
为什么可以跳转到public Object invoke()?
利用了反射,怎么利用的是底层逻辑暂时不去深究,但是在这里稍微点一下
我们可以打两个断点
进入invoke方法看一下,发现进入了反射类中,并且成功传入了接口Rent
思考 : 三
- Proxy.newProxyInstance(类加载器, 代理接口,一个InvocationHandler对象)的三个参数是什么意思?
此处的类加载器:类.getClass().getClassLoader()
关于类加载器的介绍在Java深渊处的秘密(第二遍总结:通俗解释反射原理). - 此处代理接口:类.getClass().getInterfaces()
类.getClass就可以获得类对象
- 一个InvocationHandler对象:this
为何传的参数是this呢-------因为this代表的是InvocationHandler接口实现类本身,并不是真实的代理对象。proxy参数是代理类的真实代理对象
一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。
思考:四
public Object invoke(Object proxy, Method method, Object[] args)
Java中InvocationHandler中第一个参数Proxy详解
- 讲解前我们先列一下我们要说明的问题
- proxy代表什么意思
- proxy参数怎么用及什么时候用
- proxy参数运行时的类型是什么
- 为什么不用this代替proxy
- proxy代表什么意思
proxy是真实对象的真实代理对象,invoke方法可以返回调用代理对象方法的返回结果,也可以返回对象的真实代理对象(com.sun.proxy.$Proxy0)。
- proxy参数怎么用及什么时候用
proxy参数是invoke方法的第一个参数,通常情况下我们都是返回真实对象方法的返回结果,但是我们也可以将proxy返回,proxy是真实对象的真实代理对象,我们可以通过这个返回对象对真实的对象做各种各样的操作
- proxy参数运行时的类型是什么
上面我们已经打印出了proxy的类型是:com.sun.proxy.$Proxy0真实的代理对象
- 为什么不用this替代
因为this代表的是InvocationHandler接口实现类本身,并不是真实的代理对象。
2.4 案例二:代码体验
如法炮制
2.5 案例二:功能拓展
模仿刚才的代码,我们再一次成功实现了使用动态代理
接口定义了四个方法:增删改查
接下来我们拓展一下:
UserService定义了增删改查的方法,代理帮助实现了增删改查
但是代理自己还想增加一个输出日志(打印调用了哪个方法)的功能。这属于私自拓展的,(规范要求)不能修改接口和实现类中原来的代码,于是我们只能在代理类中进行操作
具体怎么操作往下看
回顾一下静态代理中,我们如何在代理类中实现增加输出日志的功能
在动态代理中
不清楚method.getName()的建议参考Java深渊处的秘密(第二遍总结:通俗解释反射原理).
至此Spring中静态代理动态代理的简单应用在这块就介绍完了!