Spring入门理解(八)静态代理模式和动态代理模式详解

AOP是Spring的核心内容,理解代理是前提,理解代理的前提是具有扎实的Java反射基础。做好了这些准备,我们才会理解下文的AOP。当你对反射有了充分的认识,本文将会介绍在Spring中的静态代理和动态代理的应用以及区别。你会有畅通无阻。

学习经验
第一次接触代理时候,静态代理梳理了2天才真正明白。到了动态代理完全看不懂,恶补了Java反射的知识,第一遍检索资料梳理花了3天,Java深渊处的秘密(第一遍总结:通俗解释反射原理).第二遍系统的补习视频写下了梳理总结花了5天(视频看了两遍)Java深渊处的秘密(第二遍总结:通俗解释反射原理). 最后完善本文花了2天。
知识是查漏补缺,迎难而上的,加油!

1 静态代理模式

1.1 案例一:出租房屋

1.1.1 无代理模式

在这里插入图片描述

可以看出,客户想要租房子直接和房东接触
可是房东只想收钱,不想谈合同,扯嘴皮,和租客见面。
于是找到中介(代理),把这么破事交给中介去干,中介和租客接触

1.1.2 有代理模式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

构造参数创建对象:

在这里插入图片描述

1.1.3 代理模式代码分析

分析1:
在这里插入图片描述

在这里插入图片描述
为何使用组合的方式获取Host?
为何不使用继承获取Host?

分析2:
Clicent.java中为何写了两种获取proxy对象?有何区别?

分别使用了有参构造函数和set注入的方式获取对象
两者都可以,不过spring中建议使用set的方式

1.2 案例二:增删改查

先分析一下为何使用代理模式?
一个web项目中,我们从dao层开始设计,一层一层到前端
想在想要增加service层的一些功能,直接修改大概率会产性关联错误,于是我们借用代理模式,横向衍生,不影响纵向
这样问题就解决啦!

在这里插入图片描述

1.2.1 无代理模式

在这里插入图片描述
在这里插入图片描述

现在想要使输出的内容更丰富
比如输出 ”这是xx功能“,怎么做呢,是下图这样吗

在这里插入图片描述
那如果有1万个不同的增删改查,岂不是得修改源代码1万次,实际的项目中,该文件关联许多其他的文件,你一个实习生一过来就修改人家公司源代码,这是绝对不允许的,那怎么办呢?设置一个代理就可以了

1.2.2 代理模式

在这里插入图片描述
在这里插入图片描述

这样一来,我们有没有改动原本的代码,也会实现增加一个新功能需求
如果不满意,可以直接删掉我们的Proxy文件。

1.2.3 代理模式代码分析

Proxy.java 文件中,熟悉的套路

  • 组合方式获取实现类
  • 创建 set方法 或者 有参构造的方法
  • 重写接口

2 动态代理模式

2.1 案例一: 代码体验

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 逻辑分析

  1. 既然称之为动态代理,那么动态体现在哪里?


    回顾一下静态代理模式下,我们如何实现代理的:
    创建了一个专门负责出租房屋的代理类Proxy(自定义的名字),这个代理类Proxy干了什么事呢? Q:我们写下了一段功能代码(代理房东出租房屋),这个代理类才可以发挥作用。

    房东就想不跟租客见面,只想负责收钱,干嘛要房东在中介这里写什么代码。有没有一个办法自动生成中介,并且这个自动生成的中介,它自己就会实现这个功能(代理房东出租房屋)。
    在这里插入图片描述
    可以看到,测试代码中,我们调用代理类,代理类中写了 “代理房东出租房屋的代码”,后面注意动态代理是怎么做的!

在这里插入图片描述

那么就得这样去操作
先不用管这些代码为什么这样去写,先观察这些代码里面,好像真的没有写静态代理中我们手动写的那么一段功能代码(代理房东出租房屋)
在这里插入图片描述
在这里插入图片描述
可以发现,动态代理中,我们好像没有写什么功能代码,而仅仅只是调用了Proxy.newProxyInstance()这么一个方法。说明什么问题呢?
Q:说明动态代理中Proxy这个类(系统封装的,不可以修改名字)就相当于我们在静态代理中的那个傻傻的Proxy类(我们随意起的名字,可以修改为Proxy_Rent),
即Proxy的功能 == Proxy_Rent的功能。

再梳理一下,静态代理中我们创建了一个代理类,代理类的还需要我们手动的写代理功能;动态代理中,系统帮助我们封装好了一个代理类,我们只需要调用这个代理类,把房东作为参数传进去,这个家伙就会知道自己是要代理房东做事情。还知道是要代理房东出租房屋(因为房东Host中有方法rent())

这就是动态的初步理解!


2.3 代码分析

经过前面的梳理,我们从上帝的视角出发,知道了动态代理大概是怎么一回事:就是调用系统封装好的一个Proxy代理类,实现代理功能嘛。接下来我们具体分析一下代码,看看是简单的调用吗?为什么要这样调用,原理是什么?带着等等问题我们往下分析

在这里插入图片描述
在这里插入图片描述
这个图大致表达了各个方法之间的联系

思考:一
为什么要将Object类型强转为Rent接口类型?

可能大家不理解为何要转换类型,如果不转换类型,就是Object类型,Object的方法太多了我们不需要用到这些,我们只需要用到Host类的rent方法。

那么为什么不直接转为Host类型呢?


我们代理的目的就是不写Host,而是使用代理,如果直接转Host,前面的一切就毫无意义。所以我们java代码规范习惯要求,就转为接口。

那么转为接口需要注意什么?

  1. 接口的子实现类:接口引用指向子实现类的对象
  2. 格式:接口名 对象名=new 子实现类();
  3. 意义:只能调用重写方法的功能


思考 : 二
为什么可以跳转到public Object invoke()?

利用了反射,怎么利用的是底层逻辑暂时不去深究,但是在这里稍微点一下
我们可以打两个断点
在这里插入图片描述
进入invoke方法看一下,发现进入了反射类中,并且成功传入了接口Rent
在这里插入图片描述


思考 : 三

  1. Proxy.newProxyInstance(类加载器, 代理接口,一个InvocationHandler对象)的三个参数是什么意思?
    此处的类加载器:类.getClass().getClassLoader()
    关于类加载器的介绍在Java深渊处的秘密(第二遍总结:通俗解释反射原理).在这里插入图片描述
  2. 此处代理接口:类.getClass().getInterfaces()
    类.getClass就可以获得类对象
    在这里插入图片描述
  3. 一个InvocationHandler对象:this
    为何传的参数是this呢-------因为this代表的是InvocationHandler接口实现类本身,并不是真实的代理对象。proxy参数是代理类的真实代理对象
    一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。


思考:四
public Object invoke(Object proxy, Method method, Object[] args)


Java中InvocationHandler中第一个参数Proxy详解

  • 讲解前我们先列一下我们要说明的问题
  1. proxy代表什么意思
  2. proxy参数怎么用及什么时候用
  3. proxy参数运行时的类型是什么
  4. 为什么不用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中静态代理动态代理的简单应用在这块就介绍完了!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值