吊打面试官系列之– 吃透 spring ioc 和 aop (上)

目录

如何选择框架

Spring 家族体系

Spring框架经历的几个阶段

Spring IOC原理

依赖注入(Dependency Inversion)

IOC、DI、DL的关系

依赖注入的方式

依赖倒置原则、IOC、DI、IOC容器的关系

控制反转容器IOC container

IOC容器的优势

Spring IOC的应用

Spring IOC支持的功能

Spring IOC容器的核心接口

BeanDefination

BeanDefinationRegistry

BeanFactory

BeanFactory体系结构

BeanFactory与ApplicationContext的比较

ApplicationContext的功能

实战演练

@component 和 @componentScan

@Autowired


框架知识考点

如何选择框架

几乎所有的框架都拥有总结的生态即拥有自己的生态开发者社区。

1.对应的开发者社区是否有名、是否活跃

2.框架的模块是否不断迭代

(因为有名就代表大家比较认可,活跃和不断迭代就表明框架是在健康成长的,越来越多人都在贡

献自己的代码。框架也会越来越满足实际的需要,同时也能在较长的时间内存活。spring正式满足

上述的要求,并且即便有很多公司的框架是自研的,但还是基于spring开发或者借鉴了里面的思

想。)


Spring 家族体系

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

        从最先出现了服务于企业及程序开发的spring core。安全方面的spring security到后来作为各

种数据桥梁的spring data。以及在后面呢,发展到最近几年比较火的spring boot。还有最近推出

的,正在蓬勃发展的spring court。右侧非class部分列的是功能,像日志管理呀,环境管理。而左侧

的cloud部分。虽然逐渐比较繁杂,但是结构呢,已经较先前版本清晰很多。

        很多时候呢,我们写一个业务,把逻辑写死,写出来是比较容易的,但是把这个逻辑提取成

模式,进而打包成一个框架来给大家使用。这是比较困难的,因为我们只有经历过足够多的场景之

后呢,才能提取出普适的功能框架。大部分人才能用上,而且我们需要针对核心功能开放出可配置

的部分,满足小部分人进一步定制和扩展功能的需要。


Spring框架经历的几个阶段

第个阶段

推出了spring court、spring security以及spring data。把单体应用开发服务好,不仅仅提供了便捷

的数据库访问。web mvc等必要功能,通过aop IOC两大利器,让我们的程序能够做到低偶合可扩

第二阶段

        推出了spring boot,它的意义不仅仅是加速了开发效率,而且能让我们的程序呢,从可用变

为好用。

        通过这两个阶段不难看出spring core、spring mvc以及spring boot 三者的关系,spring core

最初利用的是工厂模式,就是所谓的di和代理模式aop,用来解偶应用组件。那大家一开始呢,觉

得是挺好用的,于是按照这种方式呢,搞了一个mvc的框架,用来作为web应用的开发。这就是我

们所熟知的spring mvc,然后又发现每次开发都需要写很多样板代码,比如说我们的SSM的整合。

都是千篇一律的,那么为了简化工作流程呢是就开发出了一些懒人整合包及starter,这些懒人

整合包的集合呢是spring boot了。

第三阶段

        推出的spring cloud了,它的意义在于推动了微服务架构的落地,让不具备开发微服务基础套

件的小型互联网公司也能享受到免费的开箱即用的。微服务解决方案,其实很多人不是看了微服务

的架构思想去寻找解决方案,而是了解到了spring cloud才去了解微服务思想从而落地的,这也证

明了spring court的影响力。

第四阶段

        就是现在,正在大力发展cloud dataflow加容器的模式,data flow的思想是不管是做实时消息

处理的服务,还是临时运行的任务,都可以认为是服务的组件。如果可以有一套dsl来定义这些主

线之间的交互方式,然后在容器中进行自由组合部署伸缩,那么架构会非常的灵活。

        spring的发展可以看到,互联网架构的发展spring给我们带来了相当多的技术启发。从软件设

计模式的启发,慢慢到了架构的启发,甚至可以说spring是为JAVA开发打造了架构风格的模板。

spring框架几乎涉及到了JAVA企业级服务开发的所有方面,也几乎针对所有开发常用的模式,中间

件数据库进行了整合适配。

Spring IOC原理

IOC(Inversion of  Control):控制反转

1.Spring Core最核心的部分

控制反转可以说是spring最核心的部分,是spring家族任意组建的基本。IOC本身,并不能算为一

种技术,而是一种思想。它使你从繁琐的对象交互中解脱出来,进而专注于对象本身更进一步突出

面向对象

2.需要先了解依赖注入(Dependency Inversion)

依赖注入(Dependency Inversion)

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

假设我们设计一个行李箱,首先呢,我们就需要设计轮子,根据轮子大小呢来设计底盘。再根据底

盘来设计箱体。最后呢,就根据箱体设计好整个行李箱。

这里就出现了一个依赖关系,行李箱依赖于箱体,箱体呢赖于底盘,底盘呢赖于轮子。

这样的设计看起来是okay的,但是可维护性却很低

通过代码观察:

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

假设现在我们要改变轮胎类的尺寸,我们就需要将Tire的参数的动态化。

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

由于每个主线都依赖于下层的主线构造函数里呢,都是new出来的,因此呢,都得加入一个size的

参数。由此我们可以看到仅仅是为了修改轮胎的构造函数,这种设计却需要修改整个上层所有类的

构造函数。在软件工程中,这样的设计几乎是不可维护的。

而在实际工程项目中,有的类可能会是几千个类的底层。如果每次修改这个类,我们都要修改所有

依赖它的类。

换种思路

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

此时只需要改动轮子的设计。而不需要去动底盘,箱体,行李箱的设计了。

咱们需要进行控制反转,即上层控制下层,而不是下层控制上层,用依赖注入就是dependency

injection,这种方式呢来实现控制反转。

所谓的依赖注入含义:把就是把底层类作为参数传入上层类,实现上层类对下层类的控制。

 通过代码分析:

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

这里我们只需要修改轮胎里的代码就可以了,不用修改其他任何上层类。这显然是更容易维护的代码。

不仅如此,在实际的工程中,这种设计模式还有利于协同合作和单元测试。

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

上面咱们采用的是构造函数传入的方式进行的依赖注入,其实还有另外的别的方法,比如说setter

传递和接口传递的,核心思路都是一样的,都是为了实现控制反转。正是上述这种以依赖注入即di

的方式实现的IOC,给我们带来如此大的便利。

IOC、DI、DL的关系

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

        其实IOC还有另外的一种实现方式,它就是dl即依赖查找 dependency lookup ava LAN和

ejb,就是利用dl来实现的ioc。DL呢,它相对于DI而言呢,是一种更为主动的方法,它会在需要的

时候呢,通过调用框架提供的方法来获取对象。获取时呢,需要提供相关的配置文件,路径,key

等信息来确定获取对象的状态。DL已经被抛弃,因为它需要用户自己去使用API。进行查找资源和

主张对象极有侵入性

而DI是spring以及谷歌的使用的方式,负责组件的装配,是当今IOC的主流实现。

依赖注入的方式

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

1.setter实现特定属性的public setter方法,让IOC容器调用注入所依赖类型的对象。

2.基于interface,也就是接口的,实现特定的接口以供IOC容器注入所依赖类型的对象。

3.基于constructor即构造函数的。实现特定参数的构造函数,在创建对象时呢,让IOC注入所依赖

类型的对象。

4.annotation基于注解的,它是通过JAVA的注解机制来让IOC容器注所依赖类型的对象,例如

spring框架里面的auto wire这一类的标签,都能够实现注解的功能。

上述这些呢,是属于DI的一些用法。

依赖倒置原则、IOC、DI、IOC容器的关系

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

依赖倒置原则呢,是一种思想。它大致含义是高层模块不应该依赖低层模块,两者都应该依赖其抽

,那正是依赖倒置原则的指导呢,才有了IOC的思路。而要实现这个思路呢,则离不开依赖注入

之类的支撑。spring等框架基于IOC才提出了容器的概念,对于IOC来说,最重要的就是容器了,

容器管理着bean的生命周期,控制着bean的依赖注入。

控制反转容器IOC container

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

对luggage类进行初始化的那段代码,发生的地方就是控制反转容器所做的事情了。

IOC容器的优势

1.避免再各处使用new来创建类,并且可以做到维护统一。

因为采用了依赖注入在初始化的过程中,就不可避免的会写大量的new,这里IOC容器呢,就解决

了这个问题。这个容器可以自动对代码进行初始化,你只需要维护一个configuration,可以是XML

或者可以是一段代码,而不用每次初始化一个行李箱都要亲手去写一大堆初始化的代码。

2.创建实例的时候不需要了解其中的细节

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

在上面的例子中,我们自己手动创建一个luggage instance的时候,是从底层往上层去扭的。

在这个过程中呢,我们需要了解整个luggage framework bottom tire类构造函数是怎么定义的,

才能一步一步的去new,也就是去注入。

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

         IOC container,在进行这个工作的时候是反过来的,它先从最上层开始往下去查找依赖关

系。从luggage到tire,那么在到达最底层之后,再往上一步一步的去new,有点像深度优先便利。

IOC container呢,可以直接隐藏具体的创建实例的细节,这里的蓝色部分是被隐藏了的细节,在

我们来看,它就像是一个工厂。我们呢,就像是工厂的客户,我们只需要向工厂请求一个luggage

实例,他就给我们按照config去创建一个luggage实例,并返回给我们,我们完全不用管这个

luggage实例是怎么一步一步被创建出来的。

        实际项目中,有的service class,可能是十几年前写的,有几百个类作为它的底层。假设,

我们新写了一个API,需要实例化这个service。我们总不可能回头去搞清楚这几百个类的构造函

数。IOC container这个特性呢,就很完美的解决了这类问题。因为这个架构要求你在写class的时

候,需要编写相应的config文件,所以你要初始化很久以前的service类的时候呢,前人都已经写

好了config文件了。你直接在需要用的地方注入这个service就可以了,这大大增加了项目的可维护

性,降低了开发难度。


Spring IOC的应用

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

spring启动时,读取应用程序提供的bean配置信息。并在spring容器中生成一份相应的bean配置注

册表。然后根据这张注册表,去实例化bean,装配好bean之间的依赖关系,为上层提供准备就绪

的运行环境。spring提供一个配置文件,描述bean还有bean之间的依赖关系。利用JAVA语言的

射功能,实例化bean,并建立bean之间的依赖关系。

 Spring IOC支持的功能

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

注:支持回调某些方法,需要实现自定义接口,这样的一种实现方式呢,是略带有侵入性的,应谨

慎使用。

Spring IOC容器的核心接口

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

BeanDefination

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

主要是用来描述bean的定义的spring容器,在启动的时候会将XML或者注解里的bean的定义,解析成spring内部的bean definition。

BeanDefinationRegistry

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

在BeanDefinitionRegistry的源码里面呢,我们可以看到有一个registerBeanDefinition这个方法。

它主要就是用来将我们的BeanDefinition 给注册到BeanFactory接口的实现类 DefaultListableBeanFactory 中的beanDefinitionMap里。

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

那它是一个ConcurrentHashMap, spring将bean的定义解析成definition的时候会通过

definitionRegister。以BeanName为key ,BeanDefinition为value存储到beanDefinitionMap里面,

同时还将beanName存入到beanDefinitionNames里,以便后续bean的实例化。

BeanFactory

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

BeanFactory呢,包含了各种bean的定义,以便在接收到客户端请求时,将对应的bean实例化,

Beanfactory还能在实例化对象之时,建立对象之间的依赖关系。此举将并自身从bean客户端的配

置中解放出来。

 BeanFactory体系结构

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

spring有个比较显著的特点,就是通过看接口之间的继承关系呢,以及它们的名字就能大概得出它

们的作用和含义。

为了增加对BeanFactory的理解呢,咱们来阅读其源码:

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

首先呢,我们是看到了多个getBean方法。这也是spring容器最重要的方法之一,它的意义是从

spring容器中获取bean,那从多个getBean方法中可以看到,它有按类型来获取bean的,也有按

名称来获取bean的,这意味着在spring IOC容器中,允许我们按类型或者名称去获取bean。

inSingleton方法呢,则判断 bean 是否在spring IOC中为单例

这里需要记住的是,在spring IOC中默认的情况下,bean都是以单例存在的,也就是使用getBean

方法返回的大多数情况下都是同一个对象

与isSingleton方法相反的是isPrototype,如果它返回的是true,那么当我们使用getBean方法去获

取bean的时候,spring容器会创建一个新的bean去返回给调用者。

BeanFactory与ApplicationContext的比较

由于BeanFactory的功能还不够强大,因此spring在BeanFactory的基础上呢,还设计了一个更为高

级的接口即ApplicationContext,它是BeanFactory的子接口之一,在spring的体系中,

BeanFactory和ApplicationContext,是最为重要的接口设计。在我们使用spring IOC容器时,大部

分都是ApplicationContext接口的实现类。

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

如果将spring容器比作一辆汽车,那么BeanFactory就是汽车的发动机,而ApplicationContext则

是一辆完整的汽车,它不但包括发动机,还包括离合器,变速器以及底盘等其他组件。

 

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

 ApplicationContext的功能

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

它继承以上这么多的接口,

咱们通过图示来展示整个容器的顶级uml关系:

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

在ApplicationContext下面,我们还看到了springboot经常用到的AnnotationConfigServiceWeb

ServerApplicationContext,这个ApplicationContext的实现子类。spring boot默认的ioc容器类正式

用到了它。

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

 spring boot自带的启动类,在main函数里面有个run方法,点进去,找到一个叫做createApplicationContext,

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

它会去判断webApplicationType,如果type servlet的话,它就会调用咱们的这个AnnotationConfig ServletWebServerApplicationContext,也就是咱们刚刚说的,ApplicationContext的实现。

设置断点,以debug方式启动 :

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

实战演练

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

定义一个JAVA的配置文件,它也是个类,给它命名叫做ApplicationConfig创建,在config这个

package下面,该类的作用呢,就是主要去告诉IOC容器如何装配上面的person。

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

那给它打上了@Configuration的这个标签,它就会注入到容器里面,那我们的spring容器就会根据

这一些配置呢来生成IOC容器去装配对应的bean。

@Bean是将initPerson方法返回的实体类呢,装配到IOC容器当中。

接下来咱们便可以通过springboot默认的AnnotationConfigServletWebServerApplicationContext

这个application context的实现子类,来获取person这个Bean的实例了。

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

我们可以看见 run方法返回configurableApplicationContext,configurableApplicationContext也是

继承自ApplicationContext,

吊打面试官系列之-- 吃透 spring ioc 和 aop (上)

 拿到了ApplicationContext的实例了之后,通过它的getBean的方法去获取我们的person实例,

这个Bean的我们可以通过类型来获取。

  1. package com.imooc.framevork;
  2. import com.imooc.framevork.ioc.eneity.Person;
  3. import org.springframewo来源:什么时候养猫猫

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年10月22日
下一篇 2022年10月22日

相关推荐