浅谈Spring的相关概念性问题 IOC DI AOP 工厂模式 单例

在我的理想观点中,软件的开发分为前端开发和后端开发;前端开发就是用Vue、Ext等JavaScript框架做出各种华丽的界面,直接面向用户,把用户的相关操作转化成指定形式,发给后端;后端开发就是从前端接取数据,对数据库进行增删改查。

其实一年前老师就让我们接触一下SSM框架,可那时的我还在沉迷Java的文件读写、GUI那一块,还有就是微信公众号。我在前几天看着视频学者搭建了SSM的开发环境,大致看懂了代码,然后翻博客,找知乎,初步理解了SSM中一些概念性问题,这里做一个整理。

Spring本质上是一个库,它提供了软件框架的功能,使软件之间的逻辑更加清晰,配置更灵活,Spring使用AOP和IoC,而AOP和IoC是一种思想。

在总结的时候可能用到其他博客的内容,参考网址写在最后面。

 

IOC 控制反转

书本定义

原先需要实现的对象创建、维护对象间的依赖关系,反转给容器帮忙实现。

看不懂很正常,请接着看下去

应用背景

采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。

例如我们家里挂的时钟,秒针转一圈之后,分针转一小格;同理分针转一圈,时针转一大格。

在面向对象编程中,即当秒针转了一圈的时候,秒针对象就要new一个分针对象,然后让分针的值+1,然后秒针的值归零。我们可以看出,秒针对象的正常运行需要分针对象,我们可以说是一种依赖关系,即秒针依赖于分针。(假设对象为单例)

如果我们打开时钟的后盖,就会看到与上面类似的情形,各个齿轮分别带动时针、分针和秒针顺时针旋转,从而在表盘上产生正确的时间。上图中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同工作,共同完成某项任务。我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整个齿轮组的正常运转。

面向对象编程中的“耦合关系”,就好比齿轮组中齿轮之间的啮合关系。对象之间的耦合关系是无法避免的,也是必要的,这是协同工作的基础。但是,伴随着编程开发的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,对象之间耦合度过高的系统,必然会出现牵一发而动全身的情形。

所以我们必须要想办法优化这一个方面,即所谓实现对象之间的“解耦”,它是为了解决对象之间的耦合度过高的问题。好了,IOC这就来了。

IOC是什么

借助于“第三方”实现具有依赖关系的对象之间的解耦

spring IOC容器负责创建Bean,并通过容器将Bean注入到需要Bean的对象上。

还是刚刚的例子,由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系。

这时候,A、B、C、D这4个对象之间已经没有了耦合关系了,秒针转了一圈,只需要告诉IOC容器,我转了一圈了,IOC就会把分针的值加1;这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。所以,如果真能实现IOC容器,对于系统开发而言,参与开发的每一成员只要实现自己的事情就可以了,别人的跟我没有任何关系

具体实现

还是刚刚的例子,设对象A为时钟的秒针,对象B是时钟的分针。

软件系统在没有引入IOC容器之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。在引入IOC容器之后,这种情形就完全改变了。由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了。


就比如,我们是如何找女朋友的?大学里,我们会到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、微信、电话……,想办法认识她们,投其所好送其所要,然后嘿嘿……这个过程是很繁琐的,我们要在需要谈恋爱的时候,去手动new一个出来。传统的编程开发也是这样,在一个对象中,如果要使用另外的对象,就必须自己new一个,使用完之后还要将对象销毁。

那么有了IOC之后,有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚介。婚介管理了很多男男女女的资料,我可以向婚介告知一个需求,告诉它我想找个什么样的女朋友,比如身高一米七,等等等等,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。

DI 依赖注入

通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。

通俗来讲,在软件系统运行过程中,对象A需要依赖对象B的时候,IOC容器动态的向对象A传输它需要的对象B这个传输的过程叫做注入,注入了什么?就是注入了依赖,所以全称叫做依赖注入。

比如说对象A某个时候需要连接数据库(A需要依赖Connection),原本需要自己new一个Connection对象,有了IOC之后,我们只需要告诉IOC,我需要Connection;IOC会在适当的时候创建Connection对象,至于什么时候创建,则么创建,不需要让对象A知道。那么IOC在向对象A传递Connection对象,我们叫做注入,就好比打针一样,把Connection对象注入到对象A中。

还有一个概念——反射:它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性。

spring就是通过反射来实现依赖注入的。

单例模式

即一个类实例化的对象唯一,例如Windows中的任务管理器,只能打开一个。具体可通过相关代码来实现,比如在类内部实例化私有对象,通过public方法调用该对象。

简单工厂模式

实质是由一个工厂类根据传入的参数, 动态决定应该创建哪一个产品类,就是暴力的if-else。原先是通过new方法实例化,现在只需要实例化一个工厂类,传入一个参数告诉工厂类你要什么,就可以获取你要的对象。比如传入一个"dog"字符串,返回给你一个狗对象。

工厂模式

假设有10个产品,那么该工厂模式有1个抽象父类工厂Factory(可以是接口、抽象类、具体类),该父类包含未实现工厂方法;接着有10个具体工厂子类,一一对应这10个产品类,因为父类工厂Factory未实现的工厂方法由子类来负责实现,不同具体工厂子类可以创建不同具体产品。工厂模式使得一个类的实例化延迟到其子类。

Spring Bean 的创建是典型的工厂模式, 这一系列的 Bean 工厂, 也即 IOC 容器为开发者管理对象间的依赖关系提供了很多便利和基础服务, 在 Spring 中有许多的 IOC 容器的实现供用户选择和使用。

 

AOP面向切面编程

书面定义

AOP就好比一把刀,在程序运行的时候,可以随意的插入和拔出,在插入拔出的位置(切面)可以为所欲为,比如记录日志等。利用AOP可以实现对业务逻辑的各个部分进行分离,降低耦合度。

解析

就比如上图,当我们在手机银行APP进行取款、查询、转账的时候,都会先让你验证身份吧,我们可以把这个“验证身份”过程提取出来,即画一个类似“切面”的绿线。即在一系列纵向的控制流程中,把那些相同的子流程提取成一个横向的面

那么我们能不能把这个公共功能提取出来,包装一下呢?有了AOP之后,我们可以先把主要流程写完,然后反过来在另一个地方写验证身份的代码,然后告诉Spring要插入到哪些地方即可,而不需要你自己Copy过去。

AOP的主要思想是先实现程序的整体框架,然后再具体的编写每个部分的详细代码,最后插到整体框架里面


比如1个main函数调用了100个方法,现在要求在执行调用方法之前输出一句日志

最暴力的方法就是每个方法复制粘贴syso即可。

采用面向对象思想,就是编写一个日志打印方法,该方法执行这些日志打印操作,然后在每个业务方法之前加入这句方法调用

但是如果要求我们在业务方法结束时再打印一些日志呢,是不是还要去每个业务方法结束时加一遍?这样始终不是办法,而且我们总是在改业务方法,在业务方法里面掺杂了太多的其他操作,侵入性太高。这时候AOP就起到作用了,我们可以编写一个切面类(Aspect),在其中的方法中来编写横切逻辑(如打印日志),然后通过配置或者注解的方式来声明该横切逻辑起作用的位置,从而不需要改变原先代码即可实现所需要的功能。

 

实现方式

Spring AOP采用的是JDK动态代理,在运行期间对业务方法进行增强,所以不会生成新类。

 

参考网址列表:

参考网址1

参考网址2

参考网址3

posted @ 2020-02-06 15:23  郑为中  阅读(307)  评论(0编辑  收藏  举报