springboot学习

学习整理摘自

http://www.yund.tech/zdetail.html?type=1&id=2b2a032bd98dfeb5e4113ef6624722d2



springboot启动原理


基本启动类

先看启动类注解:SpringBootApplication 
@SpringBootApplication =

@Configuration(SpringBootConfiguration)+

@EnableAutoConfiguration+

@ComponentScan。

@Configuration

@Configuration及@bean两个注解可以创建一个简单的spring的配置类,用来替代xml的配置文件

xml方式定义一个bean
注解方式定义一个bean

@Configuration的注解类标识这个类可以使用Spring IoC容器作为bean定义的来源。

@Bean注解告诉Spring,一个带有@Bean的注解方法将返回一个对象,该对象应该被注册为在Spring应用程序上下文中的bean。


@ComponentScan

功能是自动扫描符合加载条件的组件,比如(@Component)或者bean定义,最终将这些bean定义加载到ioc容器中

spring会默认从声明@componentScan的类的package包下开始扫面,所以springboot的启动类最好放在根目录下,因为默认不指定basePackages

@EnableAutoConfiguration

借助@import的支持,收集和注册特定场景相关的bean定义

类似EnableAutoScheduling是通过@import将spring调度框架相关的bean定义加载到ioc容器

类似EnableMBeanExport是通过@import将JMX相关的bean加载到IOC容器中

而@EnableAutoConfiguration 借助@Import(AutoConfigurationImportSelector.class)将符合自动装配的bean加载到ioc容器中。也会根据类路径中的jar依赖为项目自动装配;比如spring-boot-starter-web会自动添加tomcat和springmvc进行配置

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

关键在于AutoConfigurationImportSelector.class
1:AutoConfigurationImportSelector  中会调用SpringFactoriesLoader.loadFactoryNames
:2:然后会调用classloader.getresource将META-INF/spring.factories中每一个xxxAutoConfiguration文件都加载到容器中
3.读取的配置文件如下

每个配置文件一般都有以下的条件注解:

@ConditionalOnClass : classpath中存在该类时起效

@ConditionalOnMissingClass : classpath中不存在该类时起效

@ConditionalOnBean : DI容器中存在该类型Bean时起效

@ConditionalOnMissingBean : DI容器中不存在该类型Bean时起效

@ConditionalOnSingleCandidate : DI容器中该类型Bean只有一个或@Primary的只有一个时起效

@ConditionalOnExpression : SpEL表达式结果为true时

@ConditionalOnProperty : 参数设置或者值一致时起效

@ConditionalOnResource : 指定的文件存在时起效

@ConditionalOnJndi : 指定的JNDI存在时起效

@ConditionalOnJava : 指定的Java版本存在时起效

@ConditionalOnWebApplication : Web应用环境下起效

@ConditionalOnNotWebApplication : 非Web应用环境下起效

SpringFactoriesLoader做法:

主要功能是从指定的配置文件中spring.factories加载配置

SpringFactoriesLoader是一个抽象类,类中定义的静态属性定义了其加载资源的路径public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories",此外还有三个静态方法:

loadFactories:加载指定的factoryClass并进行实例化。

loadFactoryNames:加载指定的factoryClass的名称集合。

instantiateFactory:对指定的factoryClass进行实例化。


loadFactories方法

流程:先获取类加载器,然后调用loadFactoryNames方法获取所有的指定资源的名称集合,接着调用instantiateFactory方法实例化这些资源类并将其添加到result集合中。

总结: @EnableAutoConfiguration 自动配置就是从classpath中搜寻所有的META-INF/spring.factories配置文件,并将org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置通过反射实例化为对应了@Configuration的javaConfig形式的ioc容器类,然后加载到ioc容器中


讲完注解接下来讲run

启动类

一.首先实例一个SpringApplication然后执行run()

对于上下文的解释:

上下文,上下文代表了程序当下所运行的环境,联系你整个app的生命周期与资源调用,是程序可以访问到的所有资源的总和,资源可以是一个变量,也可以是一个对象的引用。-- 出自知乎

要做4件事情;

1.是否创建一个web类型的ApplicationContext通过deduceWebApplicationType()(主要是看dispatcherHandler和dispatcherServlet能不能被加载)

2.运用springFactoriesLoader在应用的classpath中加载所有可用的ApplicationContextInitializer

3.同样适用springFactoriesLoader加载classpath所有可用的ApplicationListener。将2.3步中获取的META-INF/spring.factories中的属性加载到springFactoriesLoader的cache中

4.推断并设置main方法的定义类

二.run()主要做了以下的工作:

run() 主要做了以下事情

主要流程:获取监听器 > 构造应用上下文环境 > 初始化应用上下文 > 刷新应用上下文前的准备工作 > 刷新应用上下文(做了ioc容器初始化过程) > 刷新后的拓展接口 

1.获取监听器

进入getRunListeners

主要通过getspringFactoriesInstance方法将Application初始化时候加载的监听器实例化,生成运行时监听器EventPublishingRunListener,然后启动监听器listener.starting(https://www.cnblogs.com/youzhibing/p/9603119.html  - 摘自)

2.构造上下文环境

构造环境方法

getOrCreateEnvironment:创建一个环境,判断webapplicationType是个什么玩意,如果是webApplicationType.SERVLET 那就创建一个 StandardServletEnvironment

Configuration():重排,移除应用环境中的PropertySource以及通过spring.profiles.avtive属性,在配置文件的处理期间进行其他的配置文件的激活,分别通过configurePropertySources()及configureProfiles()

listeners.environmentPrepared() :触发监听器,内部方法与listener.starting的实现一致(没有理解暂时不写)

bindToSpringApplication(environment) :将环境信息environment绑定到SpringApplication

总结:具体做了加载外部资源到environment中,包括命令行参数,serveltConfigInitParams,application.yml(.properties),初始化日志系统


3.初始上下文

之前有一个好玩的是打印banner,可以重新修改下自己玩

printBanner


createApplicationContext

总结:通过webApplicationType来获取对应的上下文,然后通过反射方式进行实例化(学习https://www.cnblogs.com/youzhibing/p/9686969.html)

什么是BeanDefinition: 

Spring容器里通过BeanDefinition对象来表示Bean,BeanDefinition描述了Bean的配置信息;根据BeanDefinition实例化bean,并放到bean缓存中。

spring bean配置方式:

有三种:基于XML的配置方式 、基于注解的配置方式和基于Java类的配置方式。

基于XML,这个我们都很熟,类似:

基于注解,这个我们也用的比较多,入@Component、@Service、@Controller等

基于java类,spring的推荐配置方式,@Configuration配合@Bean


4.刷新应用上下文前的准备工作

prepareContext(context, environment, listeners, applicationArguments, printedBanner);

将springApplication中的部分属性应用到上下文,springApplication中的environment,initializers,listener应用到spring上下文中


context.setEnvironment(environment)

将context中的environment替换成SpringApplication中创建的environment

postProcessApplicationContext(context);

由于当前SpringApplication实例的属性:beanNameGenerator和resourceLoader都为null,所以此方法目前相当于什么也没做。此方法可能是我们定制SpringApplication所用。

applyInitializers(context);

将SpringApplication中的initializers应用到context中


5.刷新上下文(*挺多的)


refresh

详细的refresh()流程:两个重点的一个是obtainFefeshBeanFactory 另一个是 finishBeanFactoryInitialization()

(重点)obtainFefeshBeanFactory()  这里面初始化了ioc并将bean注册到容器中

obtainFefeshBeanFactory() >>>>refeshBeanFactory()


从指定的xml中解析beanDefinition

首先了解下ioc初始化过程:

1.ioc : DefaultListableBeanFactory beanFactory = createBeanFactory();

1.Resource定位过程:指的是beanDefinition的资源定位,由ResourceLoader通过统一的Resource接口完成 > 通过getResourceByPath获取resource的定位

2.BeanDefination的载入:把用户定义好的bean表示成ioc容器内部的数据结构,这个容器内w2部的数据结构就是BeanDefinition > 通过loadBeanDefinitions(beanFactory)实现

3.向ioc容器注册beanDefinition:通过RegisterBeanDefinitions () 中的processBeanDefinition()  将 xml中的bean 转成 beanDefination 并加载容器中

....


....


(重点)finishBeanFactoryInitialization() :负责初始化所有singleton bean

初始化所有剩下的单例bean


进到getbean继续往下看doGetBean源码


doGet


doGet


doGet


doGet


doGet

6.刷新后的拓展接口 

spring 三级缓存


https://blog.csdn.net/qq_44836294/article/details/107795639





为什么三级缓存


读取spring的配置文件


zk


https://www.cnblogs.com/lsgspace/p/10508180.html

你可能感兴趣的:(springboot学习)