月夜星空-liulq

--愿美好接踵而至

前言

    今天这篇开始要讲解refreshContext方法了,是核心,一篇文章很难讲解完全,我会分为多篇文章来和大家一起学习,大家打起精神,一起撸码吧。

refreshContext 核心来了

    这个方法接下来要和我们的Spring进行整合了,先来看看怎么调用到Spring的启动源码的吧。

//SpringBoot的refreshContext方法
private void refreshContext(ConfigurableApplicationContext context{
        this.refresh(context);
       ... ...

}

//接下来的refresh就是我们的Spring的refresh,最重要的方法
protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext)applicationContext).refresh();
}

    这个refreshContext方法本身并没有做太多的事,主要就是去调用Spring的refresh方法,整合了我们的Spring,我们接下来就会对这个方法进行详细的学习。注意看这个refresh来自于哪,是AbstractApplicationContext类,这个类我在《SpringBoot源码系列(三)》已经提到了是怎么来的了,如果忘记了可以回过头再看一下。

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
//一些准备工作,如设置时间,属性等,不重要
this.prepareRefresh();
//重要方法,下面《this.obtainFreshBeanFactory 获取beanFactory》章节详细说明 刷新容器,找到之前创建的beanFactory并返回 ConfigurableListableBeanFactory beanFactory
= this.obtainFreshBeanFactory();
//设置了一堆的属性值,这个方法不进人内部了,总之就是设置了一些aware接口,一些beanPostProcessors接口等
this.prepareBeanFactory(beanFactory); try {
//不重要 如果是Spring进来的这是一个空方法,SpringBoot进来的话,里面添加了一个beanPostProcessors和一个aware方法
this.postProcessBeanFactory(beanFactory);
//非常重要的方法,下面《invokeBeanFactoryPostProcessors 自动装配》章节详细说明 做了两个事,一个是自动装配,一个是执行beanFactoryPostProcessors方法
this.invokeBeanFactoryPostProcessors(beanFactory);

//下面的几个方法会放到《SpringBoot源码系列(六)》中讲解
this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var9) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } }

 this.obtainFreshBeanFactory 获取beanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//为我们之前创建的beanFactory附一个SerializationId
this.refreshBeanFactory();
//找到之前创建的beanFactory,返回 ConfigurableListableBeanFactory beanFactory
= this.getBeanFactory(); if (this.logger.isDebugEnabled()) { this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory); } return beanFactory; }

     这段代码提到了之前创建的beanFactory,那是在哪里创建的呢,我们看看《SpringBoot源码系列(三)》,在这里我提到了beanFactory是在执行createApplicationContext方法,创建GenericApplicationContext类实例的时候创建的。

 invokeBeanFactoryPostProcessors 自动装配

     先贴出这段代码:

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//分为两部分来看,第一部分 this.getBeanFactoryPostProcessors(见下面《代码片段 getBeanFactoryPostProcessors》章节),
//第二部分 执行invokeBeanFactoryPostProcessors方法(见下面《代码片段 invokeBeanFactoryPostProcessors》章节
) PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,
this.getBeanFactoryPostProcessors()); if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }

代码片段 getBeanFactoryPostProcessors

 

    public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
        return this.beanFactoryPostProcessors;
    }

    这段代码就是返回了我们的全局的beanFactoryPostProcessors,是一个list集合,他的值从哪里来呢,我们回头看看《SpringBoot源码系列(四)》,当时说过在执行初始化器的时候会创建3个beanFactoryPostProcessors,这里读取到的就是那3个类。

    接下来我们看看这三个类:

 

 

    我们找到这三个类,然后看看他们实现了什么接口,经过查看,分别为(别嫌麻烦,因为这几个接口下面的《代码片段 invokeBeanFactoryPostProcessors》用到了,防止到时出现这几个接口时大家蒙,所以列出来了):

    1 ConfigurationWarningsPostProcessor                      实现了    BeanDefinitionRegistryPostProcessor接口;

    2 CachingMetadataReaderFactoryPostProcessor       实现了    BeanDefinitionRegistryPostProcessor接口;

    3 PropertySourceOrderingPostProcessor                    实现了    BeanFactoryPostProcessor接口;

    

代码片段 invokeBeanFactoryPostProcessors

     invokeBeanFactoryPostProcessors这个方法的代码非常多,有100多行,但是理解起来并不难,我会在注释中尽量写的详细些,大家一定要详细的看我写的注释,便于大家的理解。


public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
        Set<String> processedBeans = new HashSet();
        ArrayList regularPostProcessors;
        ArrayList registryProcessors;
        int var9;
        ArrayList currentRegistryProcessors;
        String[] postProcessorNames;

//还记得我们的beanFactory是什么吗,在《SpringBoot源码系列(三)》 createApplicationContext 的时候创建的beanFactory,是一个DefaultListableBeanFactory,
// 我们现在查看下这个类的类图,发现这个类实现了BeanDefinitionRegistry接口,所以代码是会进入if的这段的
if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory; regularPostProcessors = new ArrayList(); registryProcessors = new ArrayList(); Iterator var6 = beanFactoryPostProcessors.iterator();
//遍历我们之前取到的三个beanFactoryPostProcessors
while(var6.hasNext()) { BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();

//上面的《代码片段1》章节中已经说道了这三个类都实现了什么接口,现在向上翻一翻,发现有两个类实现了beanDefinitionRegistryPostProcessor接口,
// 所以遍历时,会有两个类进入if,有一个类进入else
// 走完这段之后,我们的registryProcessors集合会包含两个beanFactoryPostProcessors类,regularPostProcessors会包含一个
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
//这行没啥用 registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor);
} else { regularPostProcessors.add(postProcessor); } } currentRegistryProcessors = new ArrayList();

/ ** 按照BeanDefinitionRegistryPostProcessors这个类型,查找beanName
* 这个方法我就不详细讲解了,大家只需要知道执行之后,我们的postProcessorsNames[0]="org.springframework.context.annotation.internalConfigurationAnnotationProcessor"
* 感兴趣自己进去看看,这个方法的大致逻辑是:
* 调用了doGetBeanNamesForType方法,这个方法内部循环了beanDefinitionNames
* 这个doGetBeanNamesForyType方法比较长,需要判断是否是FactoryBean,如果是的话,会在beanName前面加上一个&(注意,这里我说的是FactoryBean,不是BeanFactory),我们的这个后面会说;
* 循环beanDefNames,然后调用isTypeMatch方法,从方法名称就可以看出,是验证我们类是否是BeanDefinitionRegistryPostProcessors类型,
* 经过判断,只有一个internalConfigurationAnnotationProcessor类满足,所以取出来了这个名称。
* 需要注意:这个名称不是真正的类,在我们《SpringBoot源码系列(三)》中的createApplicationContext,创建ApplicationContext时,这个名称加载进来的,对应了另外一个类名 -- ConfigurationClassPostProcessor;
*
* 细心的朋友会发现,下面的方法基本都在重复,反复调用getBeanNameForType获取类名;然后反复调用invokeBeanFactoryPostProcessors,我们跟踪代码看看都在做什么
**/ postProcessorNames
= beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); String[] var16 = postProcessorNames; var9 = postProcessorNames.length; int var10; String ppName; for(var10 = 0; var10 < var9; ++var10) { ppName = var16[var10];
//ppName对应的类是ConfigurationClassPostProcessor类,这个类实现了下面的这个接口,所以会走到if里面
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//执行之后,currentRegistryProcessors集合装载了ConfigurationClassPostProcessor类 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.
class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory);
//registryProcessors里面之前已经有两个beanFactoryPostProcessors类了,这里又把当前的ConfigurationClassPostProcessor加进来了 registryProcessors.addAll(currentRegistryProcessors);

//重要方法 《SpringBoot源码加餐--自动装配》详细讲解。重点来了,自动装配,完成后项目中符合的类都会被加载到beanFactory中 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear();

//又一次按照BeanDefinitionRegistryPostProcessor类型,查找beanName,
//可能大家会有疑问,为什么相同的代码要被执行两次,这是因为我们上面查找beanName时还没有把所有的类信息都加载到我们的BeanFactory当中,
//经过了上面的自动装配之后会把所有的类加载进来,这里再次执行是看看有没有再次加载进来符合条件的类 postProcessorNames
= beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); var16 = postProcessorNames; var9 = postProcessorNames.length;
//细心的朋友会发现,从这里向下的代码其实一直在重复上面的工作,就是在按照一个类型查询beanName,然后执行自动装配的方法,下面就不一一说明了
for(var10 = 0; var10 < var9; ++var10) { ppName = var16[var10]; if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear();
... ... invokeBeanFactoryPostProcessors((Collection)registryProcessors, (ConfigurableListableBeanFactory)beanFactory); invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory); } else { invokeBeanFactoryPostProcessors((Collection)beanFactoryPostProcessors, (ConfigurableListableBeanFactory)beanFactory); } ... ...

invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory); beanFactory.clearMetadataCache(); }

 总结

    refresh方法是整个启动流程的核心,这篇文章主要讲解了找到之前创建的beanFactory和自动装配前的一些准备工作,按照之前加载进来的beanFactoryPostProcessors的子类作为参数,反复调用invokeBeanDefinitionRegistryPostProcessors方法,完成自动装配。这里我们以第一次调用这个方法为例,注意我们传入方法中的两个参数,第一个是currentRegistryProcessors,这个参数当前的值是ConfigurationClassPostProcessor,第二个参数就是我们的beanFactory,这两个参数大家需要有个印象,等到下篇文章讲述自动装配原理的时候会用到。

    接下来我会在《SpringBoot源码加餐--自动装配》中详细讲解自动装配的过程,在《SpringBoot源码系列(六)》及后续的文章中继续讲解bean的实例化初始化,以及调用beanPostprocessor等。

 

 

 

    

 

posted on 2022-01-16 17:12  月夜星空-liulq  阅读(242)  评论(0)    收藏  举报