思维导图
- Spring
- 容器启动的过程
- FactoryBean原理
- Bean的创建过程
- Bean的生命周期
- 循环依赖及三级缓存
- Spring boot 自动装配原理
流程类图
容器启动过程
@startuml 'spring boot启动过程'
class "SpringApplication" as sapp {
- Set<Class<?>> primarySources
- Set<Class<?>> sources
- ConfigurableEnvironment environment
- WebApplicationType webApplicationType
- List<ApplicationContextInitializer<?>> initializers
- List<ApplicationListener<?>> listeners
- ApplicationContextFactory applicationContextFactory
- Class<?> mainApplicationClass
+ SpringApplication(Class<?>... primarySources)
+ SpringApplication(ResourceLoader, Class<?>... primarySources)
+ Collection<T> getSpringFactoriesInstances(Class<T> type)
- DefaultBootstrapContext createBootstrapContext()
# ConfigurableApplicationContext createApplicationContext()
- void prepareContext(DefaultBootstrapContext,ConfigurableApplicationContext,...)
# void applyInitializers(ConfigurableApplicationContext)
- void refreshContext(ConfigurableApplicationContext)
+ {static} ConfigurableApplicationContext run(Class<?> primarySource, String... args)
+ {static} ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args)
+ ConfigurableApplicationContext run(String... args)
}
note left of sapp::getSpringFactoriesInstances
类似JavaSPI机制,提供拓展功能
BootstrapRegistryInitializer与
ApplicationContextInitializer还
有ApplicationListener可以通过这
种方式直接优先配置
end note
note left of sapp::createBootstrapContext
创建DefaultBootstrapContext
并应用BootstrapRegistryInitializer
end note
note left of sapp::createApplicationContext
通过applicationContextFactory创
建应用上下文
end note
note left of sapp::prepareContext
应用上下文的处理:
1.注册一些启动特殊单例bean
2.加载应用主类primarySources
end note
note left of sapp::applyInitializers
对应用上下文调用
ApplicationContextInitializer初始化方法
end note
note left of sapp::refreshContext
1.调用shutdownhook
2.最后实际调用applicationContext.refresh
end note
note left of sapp::run
常用启动方式,静态方法,返回容器
上下文,核心调用refreshContext
最后callRunner
end note
interface "ApplicationContextFactory" as acf {
+ ApplicationContextFactory DEFAULT
+ ConfigurableApplicationContext create(WebApplicationType)
}
note right of acf::DEFAULT
根据不同的应用类型创建对应
的上下文实例
end note
interface "ConfigurableApplicationContext" as cacxt {
+ void refresh()
+ ConfigurableListableBeanFactory getBeanFactory()
}
note left of cacxt::refresh
核心接口方法声明
end note
abstract class "AbstractApplicationContext" as aac{
- List<BeanFactoryPostProcessor> beanFactoryPostProcessors
- ResourcePatternResolver resourcePatternResolver
- LifecycleProcessor lifecycleProcessor
- ApplicationEventMulticaster applicationEventMulticaster
- final Set<ApplicationListener<?>> applicationListeners
- Set<ApplicationListener<?>> earlyApplicationListeners
- Set<ApplicationEvent> earlyApplicationEvents
+ void refresh()
}
note left of aac::refresh
实现核心方法
end note
class "GenericApplicationContext" as gac <<BeanDefinitionRegistry>>{
}
note left of gac
BeanDefinitionRegistry接口
提供注册bean的功能
end note
class "AnnotationConfigServletWebServerApplicationContext" as acswsac {
}
sapp::applicationContextFactory <-- acf
sapp <.. cacxt
cacxt .> acf:工厂创建
cacxt <|.. aac
acf .[hidden]. aac
aac <|-- gac
gac <|- acswsac
acf <... acswsac
@enduml
FactoryBean注入原理
@startuml 'FactoryBean原理'
interface "FactoryBean<T>" as fb {
+ String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"
+ T getObject()
+ Class<?> getObjectType()
+ boolean isSingleton()
}
class "ClassPathBeanDefinitionScanner" as cpbds{
- BeanDefinitionRegistry registry
+ int scan(String... basePackages)
# Set<BeanDefinitionHolder> doScan(String... basePackages)
}
class "ClassPathMapperScanner" as cpms implements cpbds {
- Class<? extends Annotation> annotationClass
- Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class
+ void registerFilters()
+ Set<BeanDefinitionHolder> doScan(String... basePackages)
- void processBeanDefinitions(Set<BeanDefinitionHolder>)
}
class "MapperFactoryBean" as mfb implements fb {
- boolean addToConfig = true
- Class<T> mapperInterface
- SqlSessionTemplate sqlSessionTemplate
+ void checkDaoConfig()
+ T getObject()
}
interface "BeanDefinitionRegistry" as bdr {
...
+ void registerBeanDefinition(String beanName, BeanDefinition)
}
interface "BeanFactory" as bf {
+ Object getBean(String name,...)
+ Object getBean(Class,...)
}
interface "HierarchicalBeanFactory" as hbf extends bf{
+ BeanFactory getParentBeanFactory()
}
interface "ConfigurableBeanFactory" as cbf extends hbf{
+ BeanDefinition getMergedBeanDefinition(String name)
+ boolean isFactoryBean(String name)
}
class "AbstractBeanFactory" as abf <<FactoryBeanRegistrySupport>> implements cbf {
+ Object getBean(String name,...)
# T doGetBean(String name,Class<T>,Object[] args,typeCheckOnly)
# Object getObjectForBeanInstance(beanInstance,name,beanName,RootBeanDefinition )
}
note bottom of abf
方法内判断beanInstance是否为FactoryBean
如果是则通过FactoryBeanRegistrySupport获取
end note
class "DefaultListableBeanFactory" as dlbf{
- Map<String, BeanDefinition> beanDefinitionMap
- volatile List<String> beanDefinitionNames
+ void registerBeanDefinition(String beanName, BeanDefinition)
+ Object getBean(...)
}
cpms <--- mfb
cpbds <- bdr
bdr <.... dlbf
abf <|-- dlbf
fb -> abf::getObjectForBeanInstance
@enduml
Bean的创建过程
简而言之:尝试先获取
=> 没有则创建
=> 放入缓存
。
@startuml
title: Spring Bean 的创建过程
start
partition 获取 {
:BeanFactory#getBean;
:AbstractBeanFactory#doGetBean;
:DefaultSingletonBeanRegistry#getSingleton;
note right
尝试缓存中的可直接用对象
end note
}
-> 获取不到通过第二个参数ObjectFactory接口创建;
partition 创建(AbstractAutowireCapableBeanFactory) {
:createBean;
:doCreateBean;
:createBeanInstance;
:instantiateBean;
:addSingletonFactory;
#palegreen:populateBean;
note right
属性填充
end note
:initializeBean;
note right
初始化相关方法调用,且内部涉及到
BeanPostProcessor的调用,无循环
依赖情况下,最后在这个阶段创建
动态代理Aop对象
end note
}
partition 最终缓存 {
:DefaultSingletonBeanRegistry#addSingleton;
note right
bean对象完成创建和初始化,
在此加入缓存以供后期使用
end note
}
stop
@enduml
总结,bean的创建过程可抽象为几个步骤
@startuml
start
:获取BD;
:实例化;
:属性填充;
:初始化;
:进入缓存;
end
@enduml
Bean的生命周期
@startuml
start
:1.获取BD;
card 实例化阶段 {
:2.InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation;
:3.实力化;
:4.InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation;
}
floating note: 实例化
@enduml
循环依赖问题及三级缓存原理
样例:
class A{
B b;
}
class B {
A a;
}
title: Spring Boot 循环依赖解决过程
@startuml
|A|
start
:尝试获取;
:实例化;
:放入三级缓存;
:属性填充;
|B|
:尝试获取;
:实例化;
:放入三级缓存;
:属性填充;
:初始化方法调用;
:放入一级缓存;
|A|
:初始化方法调用;
:放入一级缓存;
@enduml
Spring Boot 自动装配原理
源码版本:2.7.0-SNAPSHOT
入口类:
@org.springframework.boot.autoconfigure.EnableAutoConfiguration
@org.springframework.context.annotation.Configuration
@org.springframework.context.annotation.Conditional
核心类:
org.springframework.boot.autoconfigureAutoConfigurationImportSelector
org.springframework.core.io.support.SpringFactoriesLoader
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
- 容器拿到AutoConfiguration配置类的流程
- 哪些配置类需要被加载(谁)
- 什么时候去拿配置类(时机)
- 怎么获取到配置类的(过程)
- 怎么解析配置类里的条件
@startuml
title: 类直接联系图
start
:@SpringBootApplication注解启动类;
:@EnableAutoConfiguration嵌套在其内部;
:@Import声明使用AutoConfigurationImportSelector;
#palegreen:AutoConfigurationImportSelector内部使用SpringFactories;
note right
该类实际有两个作用:
1. 加载EnableAutoConfiguration
相关联的外部配置类的名称
2. 过滤不符合条件的,比如
@ConditionalOnMissingClass
end note
:SpringFactories加载所有jar包里的`META-INF/spring.factories`并缓存;
#palegreen:`spring.factories`存储内容为key=value形式;
note right
存储外部配置类的地方,
对于此流程:
- key为注解EnableAutoConfiguration,
- value为多个由`,`分隔的全限定类名字符串,
比如mybatis的MybatisAutoConfiguration
end note
stop
@enduml
@startuml
title: 加载AutoConfiguration的整体流程
start
:SpringApplication#run;
:AbstractApplicationContext#refresh;
#palegreen:AbstractApplicationContext#invokeBeanFactoryPostProcessors;
note right
也就是说在此为入口
end note
#palegreen:ConfigurationClassPostProcessor#processConfigBeanDefinitions;
note right
处理配置类定义信息时,
问题:
1. 哪些类被视为配置类?
end note
#palegreen:ConfigurationClassParser#parse;
note right
读取到类上的注解@Import,并实例化
AutoConfigurationImportSelector对象
end note
:AutoConfigurationGroup#process;
:AutoConfigurationImportSelector#getAutoConfigurationEntry;
#palegreen:AutoConfigurationImportSelector#getCandidateConfigurations;
note right
去获取所有EnableAutoConfiguration
相关联的外部配置类全限定名称字符串
end note
:SpringFactoriesLoader#loadFactoryNames;
:加载所有jar包里的`META-INF/spring.factories`;
stop
@enduml
Spring boot 自动装配获取AutoConfiguration配置类核心原理
@startuml
title: Spring Boot 自动装配获取配置类原理
annotation "EnableAutoConfiguration" as eac {
Class<?> exclude()
String[] excludeName()
}
package "获取配置类名过程" <<Frame>> {
class "AutoConfigurationImportSelector" as acis <<DeferredImportSelector>> {
+ String[] selectImports(AnnotationMetadata)
# AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata)
# List<String> getCandidateConfigurations(...)
- ConfigurationClassFilter getConfigurationClassFilter()
}
class "SpringFactoriesLoader" as sfl {
+ {static} List<T> loadFactories(Class<T> factoryType, ClassLoader)
+ {static} List<String> loadFactoryNames(Class<?> factoryType, ClassLoader)
}
interface "AutoConfigurationImportFilter" as acif {
+ boolean[] match(String[] configClassName, AutoConfigurationMetadata)
}
note bottom of acif
顶层过滤接口,
ConditionalOnBean,
ConditionalOnMissingBean,
ConditionalOnClass
等条件注解通过其子类实现功能,
具体实现先略过
end note
entity "META-INF/spring.factories" as file{
configClass=classA,classB...
...
---
e.g:
MybatisAutoConfiguration
}
hide file circle
}
eac <-- acis: 通过Spring的@Import注解\n方式导入容器,详细另出
acis <- acif
acis <-- sfl: 只是获取配置类名
sfl <-- file
note right on link
通过ClassLoader加载所有
jar包下的相应文件,解析
并缓存。
这里获取所有Key为
EnableAutoConfiguration
的类名,可以参考
MybatisAutoConfiguration
的具体配置
end note
@enduml