Springboot 启动加载机制
Spring boot最大的好处就是遵从了java 约定大于配置 不用面对一大堆的配置文件,spring boot是根据你用的包来决定提供什么散孝滚配置。
springBoot的启动可以分为两个部分,第一部分:SpringApplication的实例化;第二部分:调用该实例运行run方法(springboot初始化)。
ApplicationContextInitializer:当springboot上慎段下文Context初始化完成后会调用
ApplicationListener:当springboot启动时事件change后都会触发
spring boot 初始化内容还是很多的,但是总结起来就四点:
即, 初始化BeanFactory,加载bean,启冲余动内置web容器;
发布ContextRefreshedEvent事件;
spring boot自动装配原理@EnableAutoConfiguration
1、spring boot启动会加载大量的自动配弯弊盯置类:(在下面的spring.factories文件中)
2、通过@ConditionalOnXXX判断我们是否导入了相关的功能(卜键就是pom文件中的starter),如果导入了,就会自动配置。
4、给容器中添加自动配置类的时候,埋和会从XXXProperties类中获取某些属性。我们只需要在配置文件中指定这些属性即可,如果没指定就会用默认值。
XXXA
比如:server.port
最后,通过配置:debug=true
可以查看失效和未生效的类(spring.factories文件中的)
SpringBoot运行原理
SpringBoot是一个基于Spring开发,集成了大量第三方库配置的javaweb开发框架
pom.xml
父依赖
其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件。以后我们导入依赖默认是不需要写版本的。
启动器spring-boot-starter
springboot-boot-starter-xxx:spring-boot的场景启动器郑御
spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件。
springBoot将所有的功能场景都抽取出来,做成一个个的starter(启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会被引进来,我们要用什么功能就导入什么样的场景启动器即可。
@SpringBootApplication
作用:标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot运行这个类的main方法来启动SpringBoot应用。
进入这个注解,里面包含了很多其他注解
@ComponentScan作用:自动扫描并加载符合条件的组件或者bean,将这个bean定义加载到IOC容器中。
@SpringBootConfiguration作用:SpringBoot的配置类,标注在某个类上,表示这是一个姿咐SpringBoot的配置类。
进入@SpringBootConfiguration注解查看,这里的@Configuration说明这是一个配置类,配置类对应Spring的xml配置文件。
继续查看@SpringBootConfiguration包含的其他注解
@EnableAutoConfiguration:开启自动配置功能
进入@EnableAutoConfiguration注解查看
@AutoConfigurationPackage自动配置包
@import:Spring底层注解@import,给容器中导入一个组件
@Import({AutoConfigurationImportSelector.class})给容器导入组件
AutoConfigurationImportSelector:自动配置导入选择器。那么它导入哪些组件的选择器呢
这个类中有这样一个方法:getCandidateConfiguration,而在这个方法中有调用了SpringFactoriesLoader类的静态方法loadFactoryNames()方法
进入loadSpringFactories方法
根据全局搜索Spring.factories,打开后是自动配置的文件。
随便打开一个其中的自动配置类看,它们都喊册岩是javaConfig配置类,都注入了一些Bean
所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中对应的org.springframework.boot.autoconfigure包下的配置项通过反射实例化为对应标注了@Configuration的javaConfig形式的IOC容器配置类,然后将这些都汇总成为一个实例并加载到IOC容器中。
结论:
1.SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
2.将这些值作为自动配置类导入容器,自动配置类就生效,帮我们进行自动配置工作。
3.整个J2EE的整体解决方案和自动配置都在springboot-autoConfigure的jar包中。
4.它会给容器中导入非常多的自动配置类(xxxAutoConfiguration),就是给容器中导入这个场景需要的所有组件,并配置好这些组件。
5.有了自动配置类,免去了我们手动编写配置注入功能组件等的工作。
SpringApplication
这个类主要做了以下四件事
1.推断应用的类型是普通的项目还是web项目
2.查找并加载所有可用初始化器,设置到initializers属性中
3.找出所有的应用程序监听器,设置到listeners属性中
4.推断并设置main方法的定义类,找到运行的主类
springboot加载自定义properties原理
springboot自定义属性文件通过value注解引入,和@autowired不同的是,它是由ConfigurationClassPostProcessor这个BeanDefinitionRegistryPostProcessor来处理,属性文件的读取和注入是在BeanDefinition级别,对象实例化之前。
我们建一个简单的类的梳理一下。
调用堆栈 从refresh开始,主要走了这几个方法:
invokeBeanFactoryPostProcessors
invokeBeanDefinitionRegistryPostProcessors
ConfigurationClassPostProcessor-processConfigBeanDefinitions
ConfigurationClassParser-doProcessConfigurationClass
ConfigurationClassParser-processPropertySource
ConfigurationClassParser-addPropertySource
ConfigurationClassParser主要方法:
doProcessConfigurationClass-processPropertySource-addPropertySource
逻辑主要集中在doProcessConfigurationClass方法圆带
doProcessConfigurationClass负责解析橘庆芦@PropertySource,@Import annotations,@ComponentScan等注解 。
1 调用processPropertySource处理自身差族的propertySource
2 扫描类上的ComponentScan,对扫出的类继续调用parse
3 处理@Import annotations等其他标签
processPropertySource结构很简单:
1根据注解里的location属性载入配置文件
2调用addPropertySource处理每个属性文件
addPropertySource这个类才是真正处理@value属性:
1把用户定义的properties文件加到Eniverment中去
2如果有相同name的属性文件,需要合并
CompositePropertySource 的场景其实是你有两个不同的文件,但是 @PropertySource中设置同样的name属性,这样CompositePropertySource 会做一个合并,按加入的时间顺序取。
增加一个product2,PropertySource name都设置为myprod
debug到addPropertySource,newSource和existing已经不一样了。
environment的propertySources里也有两份文件了。
面试官必问题:SpringBoot自动装配原理?!
首先会通过import导入DeferredImportSelector.
为什么要导入DeferredImportSelector呢,这是因为为了顺序州做的一个考虑,它的加载顺序是最后的,把它放到最后呢才能进行定制我们自己的,而不是以返迹前它的Bean优先
然后去扫描所有jar包中的spring.factories文件,把其中所有全类限定名封装成一个list,然后进行排序返回给Spring,然后Spring会漏清将它们注册是BeanDeifnition放到BeanDefinitionMap中去,然后Spring就能管理到这些Bean了