1:前言

回顾探索Spring框架

1.spring ioc

IoC其实有两种方式,一种就是DI,而另一种是DL,即Dependency Lookup(依赖查找),前者是当前软件实体被动接受其依赖的其他组件被IoC容器注入,而后者则是当前软件实体主动去某个服务注册地查找其依赖的那些服务,概念之间的关系如图2-1所示可能更贴切些。

那我们还是回过头来继续说Spring IoC容器的依赖注入流程吧!Spring IoC容器的依赖注入工作可以分为两个阶段:

阶段一:收集和注册

第一个阶段可以认为是构建和收集bean定义的阶段,在这个阶段中,我们可以通过XML或者Java代码的方式定义一些bean,然后通过手动组装或者让容器基于某些机制自动扫描的形式,将这些bean定义收集到IoC容器中。

阶段二:分析和组装

当第一阶段工作完成后,我们可以先暂且认为IoC容器中充斥着一个个独立的bean,它们之间没有任何关系。但实际上,它们之间是有依赖关系的,所以,IoC容器在第二阶段要干的事情就是分析这些已经在IoC容器之中的bean,然后根据它们之间的依赖关系先后组装它们。如果IoC容器发现某个bean依赖另一个bean,它就会将这另一个bean注入给依赖它的那个bean,直到所有bean的依赖都注入完成,所有bean都“整装待发”,整个IoC容器的工作即算完成。

正文

我们开发任何一个Spring Boot项目,都会用到如下的启动类

package com.dongk.chapter001;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Chapter001Application {public static void main(String[] args) {SpringApplication.run(Chapter001Application.class, args);}
}

我们一起看看这个唯一的注解@SpringBootApplication 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {...}

虽然定义使用了多个Annotation进行了原信息标注,但实际上重要的只有三个Annotation:

  • @Configuration(@SpringBootConfiguration点开查看发现里面还是应用了@Configuration)
  • @EnableAutoConfiguration
  • @ComponentScan

@Configuration

这里的@Configuration对我们来说不陌生,它就是JavaConfig形式的Spring Ioc容器的配置类使用的那个@Configuration,SpringBoot社区推荐使用基于JavaConfig的配置形式,所以,这里的启动类标注了@Configuration之后,本身其实也是一个IoC容器的配置类。
举几个简单例子回顾下,XML跟config配置方式的区别:

1.表达形式层面
基于xml的配置方式是这样:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.1.xsd">
</beans>

而基于JavaConfig的配置方式是这样的:
@Configuration
public class MockConfiguration{//bean 定义
}

任何一个标注了@Configuration的java类定义都是一个JavaConfig配置类。
2.定义bean定义层面
基于xml的配置形式是这样的:
<bean id="mockService" class="..MockServiceImpl">...
</bean>

而基于JavaConfig的配置形式是这样的:
@Configuration
public class MockConfiguration{@Beanpublic MockService mockService(){return new MockServiceImpl();}
}

任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器中,方法名将默认为该bean定义的id。
3.表达依赖注入关系层面
为了表达bean与bian之间的依赖关系,在xml中一般是这样的:
<bean id="mockService" class="..MockServiceImpl"><property name="dependencyService" ref="dependencyService"/>
</bean>
<bean id="dependencyService" class="DependencyServiceImpl"/>

而在JavaConfig中是这样的:
@Configuration
public class MockConfiguration{@Beanpublic MockService mockService(){return new MockServiceImpl(dependcyService());}@Beanpublic DependcyService dependcyService(){return new DependcyServiceImpl();   } }

如果是一个bean的定义依赖其他的bean,则直接调用对应的JavaConfig类中依赖的bean的创建方法就可以。

@ComponentScan

@ComponentScan这个注解在Spring中很重要,它对应XML配置中的元素,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。

我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。

@EnableAutoConfiguration

Spring框架提供的各种名字为@Enable开头的Annotation定义?比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和做事方式其实一脉相承,简单概括一下就是,借助@Import的支持,收集和注册特定场景相关的bean定义

  • @EnableScheduling是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器。
  • @EnableMBeanExport是通过@Import将JMX相关的bean定义加载到IoC容器。

而@EnableAutoConfiguration也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器,仅此而已!

@EnableAutoConfiguration作为一个复合Annotation,其自身定义关键信息如下:

其中,最关键的要属@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。就像一只“八爪鱼”一样

借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置功效才得以大功告成!

自动配置幕后英雄:SpringFactoriesLoader详解
SpringFactoriesLoader属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories加载配置。

public abstract class SpringFactoriesLoader {//...public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {...}public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {....}
}

配合@EnableAutoConfiguration使用的话,它更多是提供一种配置查找的功能支持,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类

流程简图如下

流程详解

SpringApplication的run方法的实现是我们本次旅程的主要线路,该方法的主要流程大体可以归纳如下:

1) 如果我们使用的是SpringApplication的静态run方法,那么,这个方法里面首先要创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的实例方法。在SpringApplication实例初始化的时候,它会提前做几件事情:

  • 根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
  • 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer。
  • 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener。
  • 推断并设置main方法的定义类。

2) SpringApplication实例初始化完成并且完成设置后,就开始执行run方法的逻辑了,方法执行伊始,首先遍历执行所有通过SpringFactoriesLoader可以查找到并加载的SpringApplicationRunListener。调用它们的started()方法,告诉这些SpringApplicationRunListener,“嘿,SpringBoot应用要开始执行咯!”。

3) 创建并配置当前Spring Boot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile)。

4) 遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”。

5) 如果SpringApplication的showBanner属性被设置为true,则打印banner。

6) 根据用户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添加ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,当然,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用。

7) ApplicationContext创建好之后,SpringApplication会再次借助Spring-FactoriesLoader,查找并加载classpath中所有可用的ApplicationContext-Initializer,然后遍历调用这些ApplicationContextInitializer的initialize(applicationContext)方法来对已经创建好的ApplicationContext进行进一步的处理。

8) 遍历调用所有SpringApplicationRunListener的contextPrepared()方法。

9) 最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。

10) 遍历调用所有SpringApplicationRunListener的contextLoaded()方法。

11) 调用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序。

12) 查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。

13) 正常情况下,遍历执行SpringApplicationRunListener的finished()方法、(如果整个过程出现异常,则依然调用所有SpringApplicationRunListener的finished()方法,只不过这种情况下会将异常信息一并传入处理)

转载于:https://www.cnblogs.com/mongo/p/8336326.html

SpringBoot工作机制相关推荐

  1. Hadoop框架:DataNode工作机制详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.工作机制 1.基础描述 DataNode上数据块以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是数据块元数据包括长度.校验.时 ...

  2. JavaWeb技术内幕二:Java IO工作机制

    IO问题是当今web应用所面临的主要问题之一,因为数据在网络中随处流动,在这个流动过程中都涉及IO问题,并且大部分应用的瓶颈都是IO瓶颈. 本章将从IO的角度出发,介绍IO类库的基本架构,磁盘IO的工 ...

  3. 2021年大数据HBase(十四):HBase的原理及其相关的工作机制

    全网最详细的大数据HBase文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 HBase的原理及其相关的工作机制 一.HBase的flus ...

  4. java语言的实现机制_JAVA语言之Java NIO的工作机制和实现原理介绍

    本文主要向大家介绍了JAVA语言之Java NIO的工作机制和实现原理介绍,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 前言 本文只简单介绍NIO的原理实现和基本工作流程 I/O和 ...

  5. docker用gpu的参数_从零开始入门 K8s | GPU 管理和 Device Plugin 工作机制

    导读:2016 年,随着 AlphaGo 的走红和 TensorFlow 项目的异军突起,一场名为 AI 的技术革命迅速从学术圈蔓延到了工业界,所谓 AI 革命从此拉开了帷幕.该热潮的背后推手正是云计 ...

  6. MapReduce1和Yarn的工作机制

    Hadoop中的MapReduce的工作机制分为两种: MapReduce 1 也就是Hadoop 2.0之前的工作机制 YARN MapReduce 1 构成 MapReduce 1最主要的其实就是 ...

  7. 从源码分析Hystrix工作机制

    作者:vivo互联网服务器团队-Pu Shuai 一.Hystrix解决了什么问题? 在复杂的分布式应用中有着许多的依赖,各个依赖都难免会在某个时刻失败,如果应用不隔离各个依赖,降低外部的风险,那容易 ...

  8. mysql的proxy机制_MySQL Proxy工作机制浅析

    MySQL Proxy处于客户端应用程序和MySQL服务器之间,通过截断.改变并转发客户端和后端数据库之间的通信来实现其功能,这和WinGate之类的网络代理服务器的基本思想是一样的.代理服务器是和T ...

  9. 第6章-MapReduce的工作机制-笔记

    为什么80%的码农都做不了架构师?>>>    作业的提交 可以只用一行代码来运行一个MapReduce作业: JobClient.runJob(conf). 作业的调度 Hadoo ...

  10. JVM结构、GC工作机制详解

    题外话:最近在应聘阿里2015暑期实习,感触颇多.机会总是留给有准备的人的,所以平常一定要注意知识的巩固和积累.知识的深度也要有一定的理解,不比别人知道的多,公司干嘛选你?关于JVM和GC,我相信学j ...

最新文章

  1. 黑龙江智能车邀请赛中的单车比赛
  2. 047_Divider分割线
  3. 开课吧怎么样_开课吧数据产品经理课程包括什么?开课吧培训的怎么样
  4. java session使用_java学习之web基础(8):使用session实现带验证码的登录功能
  5. PHP 利用Mail_MimeDecode类提取邮件正文
  6. ABP入门系列(13)——Redis缓存用起来
  7. Angular之ngx-permissions的路由使用
  8. 如何在Ubuntu 14.04上使用Percona XtraBackup创建MySQL数据库的热备份
  9. JAVA EE配TOMCAT
  10. 脚本自动安装rkhunter检查rootkit
  11. 管理感悟:每次争吵后要有进步
  12. Matlab图形的线型、标记、颜色
  13. 3D打印:我的打印机使用经验技巧记录
  14. Markdown基本语法(摘录)
  15. B站接口获取图片资源出现403的解决方案
  16. 【职业规划】该如何选择职业方向?性能?自动化?测开?学习选择python、java?
  17. 工具分享--IDM下载工具利器,让下载速度提升一百倍
  18. tensorflow2.0——预测泰坦尼克号旅客生存概率(Keras应用实践)
  19. VPP系统 接口启用DHCP
  20. 01-MySQL 创建数据库

热门文章

  1. 什么才是真正的架构设计?
  2. 阿里面试官居然问我如何设计一个本地缓存
  3. 阿里员工:只有两百万现金和一套房,这样干着没意思
  4. python矩阵运算与线形代数_Python 执行矩阵与线性代数运算
  5. sql left join on 多条件_SQL深入理解|关系代数、简单查询、连接
  6. Nginx使用GeoIP模块来限制地区访问
  7. nginx实现共享以及实现原理
  8. python的N个小功能(图片预处理:打开图片,滤波器,增强,灰度图转换,去噪,二值化,切割,保存)...
  9. HDU2095find your present (2)【hash】
  10. gson将JSON字符串转成Java对象