热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

09、SpringBoot启动刷新应用上下文自动装配解析(一)

目录:Springboot源码学习目录上文:08、SpringBoot启动准备应用上下文前言:一、属性应用上下文debug进入refreshContext方法privatevoi

目录:Springboot源码学习目录

上文:08、SpringBoot 启动 准备应用上下文

前言


一、属性应用上下文

debug进入refreshContext方法

private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
// 进入刷新方法
refresh((ApplicationContext) context);
}

protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
// 进入重载刷新方法
refresh((ConfigurableApplicationContext) applicationContext);
}

protected void refresh(ConfigurableApplicationContext applicationContext) {
// 调用上下文自己的刷新方法
applicationContext.refresh();
}

调用到上下文自己的刷新方法,我们就发现就是之前的spring的逻辑

原有的spring逻辑我们就不再看了,这里只看一下springboot特有并且比较重要的的逻辑

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep cOntextRefresh= this.applicationStartup.start("spring.context.refresh");
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// beanFactory后处理,向工厂中注入WebApplicationContextServletContextAwareProcessor,这一步我们不用太关心
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
// 回调所有的 BeanFactoryPostProcessor,其中自动装配就是在该步完成,重点要关心的
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 创建并启动 Tomcat 服务器,就是在该步完成,重点要关心的
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
contextRefresh.end();
}
}
}

二、回调所有的 BeanFactoryPostProcessor

debug进入invokeBeanFactoryPostProcessors方法

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 调用后置处理注册器工具类,将获取到到的 BeanFactoryPostProcessor 实例化并调用
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}

PostProcessorRegistrationDelegateinvokeBeanFactoryPostProcessors方法逻辑很复杂,这个和Spring一样,这里我们只看和自动装配有关的那个 BeanFactoryPostProcessor

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {
// 省略不重要逻辑---
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 在呈现的部分代码里上面那部分代码就是获取所有BeanDefinitionRegistryPostProcessor的实现类,然后调用
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
// 省略不重要逻辑---
}

然后遍历所有的BeanDefinitionRegistryPostProcessor的实现类

我们在前文创建 应用上下文时说过,在创建过程中想上下文beanFactory中注册了一个ConfigurationClassPostProcessor,这个类也实现了BeanDefinitionRegistryPostProcessor

ConfigurationClassPostProcessor也是我们重点关注的类,自动装配就和他有关系,我们只需要debug他就可以了

private static void invokeBeanDefinitionRegistryPostProcessors(
Collection postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
.tag("postProcessor", postProcessor::toString);
// 找到ConfigurationClassPostProcessor然后执行
postProcessor.postProcessBeanDefinitionRegistry(registry);
postProcessBeanDefRegistry.end();
}
}

进入ConfigurationClassPostProcessor

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 省略不重要代码 ......
// ConfigurationClassPostProcessor解析的核心方法
processConfigBeanDefinitions(registry);
}

然后我们进入ConfigurationClassPostProcessorprocessConfigBeanDefinitions方法,

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List cOnfigCandidates= new ArrayList<>();
// 获取当前beanFactory中的所有beanName
String[] candidateNames = registry.getBeanDefinitionNames();
// 遍历当前beanFactory中的所有beanName,因为还出去回调beanFactroyPostProcessor阶段,工厂中的beanName只有几个
for (String beanName : candidateNames) {
// 获取beanName对应的BeanDefinition
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// CONFIGURATION_CLASS_ATTRIBUTE = "org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass"
// 如果BeanDefinition 中有 CONFIGURATION_CLASS_ATTRIBUTE属性,说明这个bean已经被解析过了,不需要再解析
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 如果BeanDefinition 中没有 CONFIGURATION_CLASS_ATTRIBUTE属性,则需要判断是否需要解析
// 判断逻辑就不看了,在这里直接写,当类上面标注了@Configuration/@Component/@ComponentScan/@Import/@ImportResource等注解,就是配置类,需要进行后面的解析
// 这个工具类的方法后面还会用到
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
// 判断是否为空,如果为空则说明没有需要解析的配置类,直接返回,一般第一次启动,我们能拿到的配置类就是我们的启动类,
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
// 对需要解析的配置类进行排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
// registry实现了SingletonBeanRegistry,此处为true
if (registry instanceof SingletonBeanRegistry) {
// 将registry强转为SingletonBeanRegistry
sbr = (SingletonBeanRegistry) registry;
// 默认为false,此处也成立
if (!this.localBeanNameGeneratorSet) {
// 从工厂中获取org.springframework.context.annotation.internalConfigurationBeanNameGenerator,对应的bean
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
// 第一次创建应用上下文,为空,
if (generator != null) {
this.compOnentScanBeanNameGenerator= generator;
this.importBeanNameGenerator = generator;
}
}
}
// 实例化时将上下文中的环境赋值给了当前对象,此处不为空
if (this.envirOnment== null) {
this.envirOnment= new StandardEnvironment();
}
// Parse each @Configuration class
// 配置类解析器,不要被此处的英文误导了,这个解析器可以解析@Component,@PropertySources,@ComponentScans,@Import,@ImportResource,@Bean这些注解
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// 将待解析的BeanDefinitionHolder存入candidates集合,后面遍历解析
Set candidates = new LinkedHashSet<>(configCandidates);
// 收集已经解析过的类
Set alreadyParsed = new HashSet<>(configCandidates.size());
// 循环解析
do {
StartupStep processCOnfig= this.applicationStartup.start("spring.context.config-classes.parse");
// 开始解析 上面存入candidates集合的配置类,核心逻辑
parser.parse(candidates);
// 遍历所有解析出来的类,检查标注有@Configuration注解且proxyBeanMethods属性=true的类与其@bean标注的方法是不是fianl关键字修饰,如果是则报错
parser.validate();
// 获取所有的解析出来的配置类,存入configClasses集合
Set cOnfigClasses= new LinkedHashSet<>(parser.getConfigurationClasses());
//删除掉配置类集合中已经解析过的配置类,防止重复解析
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
// 如果读取器为空,则创建一个,配置类bean定义信息读取器,该读取器专门将配置类解析成BeanDefinition
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 将配置类解析为beanDefinition,核心逻辑
this.reader.loadBeanDefinitions(configClasses);
// 将解析过的配置类加入已解析集合
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
// 清空待解析的配置类
candidates.clear();
// 如果解析后的 BeanDefinition 的总数 > 大于解析前的 BeanDefinition 的总数,则需要检查新增的bean中是否有配置类
if (registry.getBeanDefinitionCount() > candidateNames.length) {
// 获取所有的beanName
String[] newCandidateNames = registry.getBeanDefinitionNames();
// 获取所有解析之前的beanName
Set oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
// 收集所有已解析的beanName
Set alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
// 遍历所有的beanName,如果他在解析之前不存在,则获取他的他BeanDefinition
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
// 然后检查,这个类是不是配置类,并且没有解析过,如果是,则加入待解析的配置类中
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
/// 同时将解析前所有配置类更新
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}

上面这段解析流程中,最重要的是parser.parse(candidates);this.reader.loadBeanDefinitions(configClasses);这两行代码

parser.parse(candidates);代表的是将待解析的配置类中的类解析出来,而自动装配的逻辑也在其中

this.reader.loadBeanDefinitions(configClasses);代表的时候将解析出来的类,转化为 BeanDefinition

我们下篇文章再分析



推荐阅读
author-avatar
我系懒懒懒猫
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有