太强了!这是我见过最通俗易懂的一篇 Spring 知识点总结
由于 Spring 家族的东西很多,一次性写完也不太现实。所以这一次先更新 Spring「最核心」的知识点:AOP 和 IOC
无论是入门还是面试,理解 AOP 和 IOC 都是非常重要的。在校招的时候,我没被问过 Mybatis/Hibernate/Struts2 这样的框架,而 Spring 就经常会被问到。
作为阅读福利,我整理 spring 相关的学习资料(包含了手写 pdf、脑图、面试真题)有 spring boot、spring cloud、spring Ioc、spring aop 等,现在免费分享给阅读到本篇文章的 Java 程序员朋友们,需要的点击下方链接领取~
为什么要用 Spring
当年的我,刚学 Spring 的时候,会想:『这 IOC 和 AOP』是什么鬼玩意啊?一大堆的名词「控制反转」「依赖注入」「面向切面编程」。这是在给我搞笑的吧。
在最开始学的 IOC 折腾了一大堆的玩意,结果就是在管「创建对象」的事??逗我呢???我直接 new 一个对象出来不香吗?
有这种想法这种明显就是「代码写得少了,想得多了」
我们写代码,不仅仅是要能实现功能,实现完了以后我们还得对写过的代码「维护」。如果我们的代码写得很烂,那「维护」的成本就很高。
维护实际上是做什么事?
出了问题需要找到是哪块的代码有问题
在原有的基础上加入一些新的功能(也就是所谓的迭代)
面对重复的/繁琐的非业务代码:
如果程序出了问题,我们得看吧?谁也保证不了重复的代码就没有问题。
我们要想加一个新的功能,还得按原来的方式写吧?代码量会越来越多,越来越多….
上一期的「Mybatis」教程也讲到了,我们的 JDBC 写得好好的,运行的效率也是杠杠的。但是 JDBC 需要我们「自行」处理的细节太多了,我们需要在里边添加各种「重复」的代码。
我们使用 ORM 框架,那么我们就可以更加「专注」去实现本身的业务,ORM 框架把「重复」的代码都屏蔽掉,代码维护起来就比 JDBC 要方便。
Spring IOC 解决的是 对象管理和对象依赖的问题。
Spring AOP 解决的是 非业务代码抽取的问题。
(这里要是没基础的同学,可能看不太懂,下面再来解释解释一下应该就没问题了)
Spring IOC
提到 Spring IOC,随便去网上一搜,我们就可以看到「依赖注入」「控制反转」这两个词。
很多人都会试图要把这两个词给解释清楚,但是太难了,这两个词真的是太难给解释清楚了。
Spring IOC 解决的是对象管理和对象依赖的问题。本来我们的对象都是 new 出来的,而我们如果使用 Spring 则把对象交给「IOC 容器」来管理。
三歪这逼搞事情了。「依赖注入」和「控制反转」都没讲,现在还来了个「IOC 容器」。
「IOC 容器」是什么?我们可以理解为是一个「工厂」,我们把对象都交由这个「工厂」来管理,包括对象的创建和对象之间的依赖关系等等。等我们要用到对象的时候,就从这个「工厂」里边取出来。
「控制反转」指的就是:本来是「由我们自己」new 出来的对象,现在交给了 IOC 容器。把这个对象的「控制权」给「他方」了。「控制反转」更多的是一种思想或者说是设计模式,把原有由自己掌控的事交给「别人」来处理。
「依赖注入」更多指的是「控制反转」这个思想的实现方式:对象无需自行创建或管理它们的依赖关系,依赖关系将被**「自动注入」**到需要它们的对象当中去。
最简单理解「依赖注入」和「控制反转」:本来我们的对象都是「由我们自己」new 出来的,现在我们把这个对象的创建权限和对象之间的依赖关系交由「IOC 容器」来管理。
悄悄话:我个人本身是不太喜欢琢磨每个词的含义的,很多时候大佬们也很难解释清楚。如果是初学的同学,也不用太纠结每个名词的具体含义,深究下去也没有太大的必要。
现在问题又来了,为什么我们要把对象给「IOC 容器」来管理呢?要理解这个,我建议可以先去看看我写过的「工厂模式」
理论上,我们可以把「IOC 容器」也当做是一个「工厂」,使用 IOC 的好处就是:
将对象集中统一管理,便于修改
降低耦合度(调用方无需自己组装,也无需关心对象的实现,直接从「IOC 容器」取就好了)
IOC 需要学什么?
我们在使用 Spring 的时候,首先我们要学习的就是怎么把对象交给「IOC 容器管理」
Spring 提供了四种方式:
注解
XML
JavaConfig
基于 Groovy DSL 配置
总的来说:我们以 XML 配置+注解来装配 Bean 比较多,其中注解这种方式占大部分。
把对象放到「IOC 容器」了以后,对象与对象之间是有关系的,我们需要把对象之间的依赖告诉 Spring,让它来帮我们解决掉对象的依赖关系。
「对象之间的关系」别想得太复杂了。在日常开发中其实很多时候就是 A 对象里边有 B 对象的属性而已。
一般来说我们会通过构造器或者属性(setting 方法)的方式来注入对象的依赖
**举个例子:**日常开发中,我们很多时候用 @Component 注解标识将对象放到「IOC 容器」中,用 @Autowired 注解将对象注入
下面这张图就很好总结了以各种方式来对 Bean 的定义和注入。
Spring AOP
AOP:Aspect Object Programming 「面向切面编程」,听起来是不是很牛逼。
Spring AOP 主要做的事情就是:「把重复的代码抽取,在运行的时候往业务方法上动态植入“切面类代码”」
举个例子,现在我们有以下的代码:
上面的代码其实最核心的就一行代码:「保存 user 对象到数据库中」
我们的数据库表肯定不止 user 一张表,对数据库的增删改也肯定不止 add()方法一个。所以我们可以想象到:对数据库的每次操作,都要写「开启事务」和「关闭事务」这种代码。
这种代码对我们来说是重复的,于是我们会想把这种代码给「抽取」出来。
如果我们单纯用 OOP(面向对象)的思想去把代码给优化掉,最终我们的效果可能是这样的:
即使这样看起来代码已经很少了,但我们细想一下会发现:update()/delete()方法同样也会有 aop.begin()这样的重复代码的。
我们想要「消灭」掉这些重复代码,可以怎么做?这个时候我们应该能想到「动态代理」,通过动态代理,我们可以把对象「增强」,将非业务代码写在要「增强」的逻辑上。
完了以后,我们就可以通过「增强后的对象」去调用方法,最终屏蔽掉「重复代码」
效果可能会如下:
上面是我们手动写的代理来实现对「非业务代码」的抽取,类似这样的场景会有很多:比如我们要做权限控制,要对参数进行校验等等。
Spring 支持了 AOP,让我们可以不用自己「手动」去写代理对象,达到将「非业务代码」的抽取的效果。
我们可以体验一波 Spring AOP 是怎么弄的,跟上面的对比对比:
效果如下:
总结
建议:在学习 IOC 之前,可以先看看「工厂模式」。在学习 AOP 之前,可以先看看「代理模式」
理解了「工厂模式」那就知道为什么我们不再直接 new 对象,理解了「代理模式」,我们就知道 Spring AOP 的底层技术其实就是「动态代理」,这样学习 IOC 和 AOP 的时候,就会轻松很多。
还要一点就是不要被「名词」给吓唬了,之前不懂某个技术的时候,听别人讲一些名词,我对此完全不懂。那就可能会认为这个技术会很牛逼,其实等真正接触下来,学习完了以后,其实发现也不过如此嘛。
评论