SpringBoot启动大纲
2025-01-21 10:29:12 5 举报
AI智能生成
spring启动流程大纲
作者其他创作
大纲/内容
SpringApplication.run(xxx.class,args)
new SpringApplication(primarySources)
WebApplicationType.deduceFromClasspath() 确认是一个基于servlet的web应用
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))
getSpringFactoriesInstances(ApplicationContextInitializer.class)
SpringFactoriesLoader.loadFactoryNames()
loadSpringFactories(classloader) 通过类加载器加载META-INF/spring.factories下的类名是ApplicationContextInitializer.class对应的类存入缓存
createSpringFactoriesInstances()反射创建工厂实例
setInitializers()
找出类型是ApplicationContextInitializer的放入此list List<ApplicationContextInitializer<?>> initializers
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
getSpringFactoriesInstances(ApplicationListener.class)
SpringFactoriesLoader.loadFactoryNames()
loadSpringFactories(classloader) 通过类加载器加载META-INF/spring.factories下的类名是ApplicationListener.class的对应的类存入缓存
createSpringFactoriesInstances()反射创建工厂实例
setListeners()
找出类型是ApplicationListener放入此list List<ApplicationListener<?>> listeners
this.mainApplicationClass = deduceMainApplicationClass();
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} 栈跟踪推断出当前有main方法的类对象并返回
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} 栈跟踪推断出当前有main方法的类对象并返回
SpringApplication.run()
configureHeadlessProperty() 关于键盘鼠标显示等外设 参考 https://blog.csdn.net/zzb5682119/article/details/92796522
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(); 获得监听器并开始监听
listeners.starting(); 获得监听器并开始监听
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
listener.onApplicationEvent(event) 不同的listener实现不同的事件
prepareEnvironment()
getOrCreateEnvironment() 创建一个基于servlet的环境
configureEnvironment()配置环境
setConversionService()
configurePropertySources()
configureProfiles()
ConfigurationPropertySources.attach(environment) 添加configurationProperties 到source中
listeners.environmentPrepared(environment) 类似于上面的listeners.start()方法
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
listener.onApplicationEvent(event) 不同的listener实现不同的事件
bindToSpringApplication(environment); 将环境绑定到上下文
configureIgnoreBeanInfo()配置忽略bean的信息
printBanner(environment) 打印横幅
createApplicationContext() 根据应用创建上下文 此应用基于servlet 创建servlet的上下文
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); 主要是从spring.factories中读取出类型为 org.springframework.boot.SpringBootExceptionReporter 对应的类。然后创建类的实例 。 处理异常使用 不重要
prepareContex()
context.setEnvironment(environment); 将context中相关的environment全部替换成SpringApplication中创建的environment
postProcessApplicationContext(context); 由于当前SpringApplication实例的属性:beanNameGenerator和resourceLoader都为null,所以此方法目前相当于什么也没做。此方法可能是我们定制SpringApplication所用。
applyInitializers(context); 在context refresh之前应用ApplicationContextInitializer到context中。
listeners.contextPrepared(context); 类似于上面的listeners.start()方法和listeners.environmentPrepared(environment)方法
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
load(context, sources.toArray(new Object[0])) 加载SpringApplication的primarySources集合的资源并注册到bean ,也就是注册主启动类,为下面的扫描主启动类做准备,这一步非常重要不然都不知道扫描哪个类
listeners.contextLoaded(context); 将SpringApplication中的listeners注册到context中,并广播ApplicationPreparedEvent事件
refreshContext(context); 核心部分 及 spring 应用开始
prepareRefresh()准备此上下文以进行刷新,设置其启动日期和* active标志以及执行属性源的任何初始化。
其中具体做了什么看源码,源码注释十分详细,自己阅读
obtainFreshBeanFactory() 告诉子类刷新内部bean工厂,返回新鲜的BeanFactory实例
prepareBeanFactory(beanFactory); 为了在上下文中使用配置bean工厂。配置工厂的标准上下文特征,例如上下文的ClassLoader和后处理器。
细节看源码,注释十分详细,自己阅读
postProcessBeanFactory(beanFactory); 允许在上下文子类中对bean工厂进行后处理。
invokeBeanFactoryPostProcessors(beanFactory); 重点中的重点 自动装配便在此方法中实现。
ConfigurationClassPostProcessor此类的processConfigBeanDefinitions()方法
checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)此方法中找出配置候选人即我们的主启动类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry); 创建parse解析器
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry); 创建parse解析器
parser.parse(candidates);解析主启动类
processConfigurationClass()
doProcessConfigurationClass(configClass, sourceClass, filter); 递归处理配置类及其超类层次结构,这个方法非常重要
Process any @PropertySource annotations
Process any @ComponentScan annotations
扫描带有Component注解的类到configurationClasses这个map
Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true); 此处即为自动装配重点方法
getImports()
collectImports(sourceClass, imports, visited); 递归查找@import注解 拿到AutoConfigurationImportSelector.class 和 AutoConfigurationPackages.Registrar.class 这两个类
processImports()对拿到的这两个类进行处理 ,重点是将AutoConfigurationImportSelector.class这个类扔到DeferredImportSelectorHandler这个对象方便下面的自动装配
this.deferredImportSelectorHandler.process() 处理AutoConfigurationImportSelector.class并进行自动装配
processGroupImports()
grouping.getImports()
this.group.process this.group = AutoConfigurationImportSelector
((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry()
.getAutoConfigurationEntry()
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader()) 关键方法同最上面根据类名去加载spring.factorys文件中所有的自动装配类(并没有实例化只是加载类名到map)130个左右 然后在进行各种过滤筛选选出30个左右装配类。过滤筛选不说看源码
getBeanClassLoader()) 关键方法同最上面根据类名去加载spring.factorys文件中所有的自动装配类(并没有实例化只是加载类名到map)130个左右 然后在进行各种过滤筛选选出30个左右装配类。过滤筛选不说看源码
Process any @ImportResource annotations
Process individual @Bean methods
Process default methods on interfaces
initMessageSource(); 初始化此上下文消息源
initApplicationEventMulticaster() 为此上下文初始化事件多播器
onRefresh() 在特定上下文子类中初始化其他特殊bean。 例如tomcat初始化就在此方法中
createWebServer()
getWebServer()中创建tomcat
registerListeners(); 检查侦听器bean并注册它们
finishRefresh(); 发布相应的时间 ,源码注解很清楚自己阅读
afterRefresh(context, applicationArguments); 由子类实现,springboot没做什么
listeners.started(context);再次开始监听器做相关事情
listeners.running(context);
finishBeanFactoryInitialization(beanFactory); 实例化所有剩余的(非延迟初始化)单例
循环遍历beanfactory中beandefinitionmap中定义的bean getbean()方法如果能从工厂获取就返回bean实例不能就创建
如果已经创建单例bean则跳过,若没有则createbean()
resolveBeforeInstantiation() 实例化bean之前做一些额外操作(可自定义)只需要bean实现InstantiationAwareBeanPostProcessor接口 重写对应方法即可
docreatebean() 开始创建bean实例
createBeanInstance() 通过构造函数创建 Bean 实例。
构造函数上如果有 @Autowired,会先将引用类型的入参对象优先实例化。
但此时的 Bean 实例里的属性上、非构造方法上如果有 @Autowired,还没有进行依赖注入。
构造函数上如果有 @Autowired,会先将引用类型的入参对象优先实例化。
但此时的 Bean 实例里的属性上、非构造方法上如果有 @Autowired,还没有进行依赖注入。
applyMergedBeanDefinitionPostProcessors() AutowiredAnnotationBeanPostProcessor会扫描Bean的类中是否使用了@Autowired和@Value注解,扫描到的对象会封装成一个InjectionMetadata对象,缓存到一个Map集合中,后续根据缓存信息进行属性填充;
CommonAnnotationBeanPostProcessor则会扫描Bean类中是否使用了@Resource等注解,同样缓存起来等待后续进行属性填充。
CommonAnnotationBeanPostProcessor则会扫描Bean类中是否使用了@Resource等注解,同样缓存起来等待后续进行属性填充。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 加入到三级缓存
populateBean(beanName, mbd, instanceWrapper); 属性注入 对有 @Autowired 和 @Resource 的属性和非构造方法进行依赖注入。循环依赖等也在此方法中解决。
循环依赖重点:A中有B,B中有A
A创建实例,实例创建完成后放入三级缓存(其实是一个创建a的匿名内部类)及单列工厂addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
将注入属性时发现要引用B,然后继续创建B实例,实例化结束后将b实例(其实是一个创建b的匿名内部类)放入三级缓存
B实例属性注入时发现要引用A实例从工厂中再次getbean()
然后在dogetbean()方法中的getsingleton()方法中获取bean
先从一级缓存查询发现没有
再判断此bean是否在创建中然而a确实在创建中,再从二级缓存查询发现也没有
然后再去查询三级缓存,从三级缓存单列工厂创建一个bean(三级工厂相当于框架的扩展实现aop代理等功能)
将创建出的a实例放入二级缓存并移除三级缓存
B实例拿到A的实例后正常注入正常创建B实例,B实例完成完整创建(实例化+初始化)
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
try {
return createBean(beanName, mbd, args);
}
然后再进入getSingleton()方法
addSingleton()
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
移除二级缓存移除三级缓存 ,加入一级缓存
跳出循环A拿到B完整实例后进行属性注入
然后同上面一样 在addsingleton()方法中移除二级缓存和三级缓存,加入一级缓存
如此循环依赖问题解决
二级缓存理论上可以解决循环依赖问题但是对于框架的扩展性有限,而三级缓存的加入就是为了框架的扩展:例如AOP代理功能功能实现 参考:https://my.oschina.net/u/4340310/blog/4332450 https://blog.csdn.net/qq_35457078/article/details/112409302
自动注入源码解析
调用AutowiredAnnotationBeanPostProcessor这个类的postProcessProperties()
inject()注入方法 (注意InjectionMetadata 对象是所有注入点的封装对象 是由 上述方法applyMergedBeanDefinitionPostProcessors()所作的事情),然后循环InjectionMetadata这个对象中的Collection<InjectedElement> 属性 逐个注入点进行操作
resolveFieldValue()解决字段值
resolveDependency()
doResolveDependency()
resolveCandidate()
beanFactory.getBean(beanName); 解决候选者时又要去bean工厂拿实例就会再次创建自动注入的实例
field.set(bean, value); 完成属性注入
initializeBean()初始化bean
applyBeanPostProcessorsBeforeInitialization 初始化前置处理
invokeInitMethods 初始化 调用afterpropertyset方法 或者 定义的init-method方法等
applyBeanPostProcessorsAfterInitialization 初始化后置处理
0 条评论
下一页