Spring Boot源碼(四) - prepareEnvironment、反射創建ApplicationContext對象、prepareContext

目錄

一、創建和配置Environment

1、創建Environment對象(getOrCreateEnvironment)

2、配置Environment(ConversionService、main方法傳入的args參數、Profile)

3、SpringApplicationRunListener的environmentPrepared回調

4、自定義Environment

二、反射創建ApplicationContext對象

三、prepareContext

1、爲Spring容器設置初始化的環境

2、爲ConfigurableApplicationContext設置屬性

3、回調ApplicationContextInitializer的initialize方法

4、回調SpringApplicationRunListener的contextPrepared方法

5、將applicationArguments、Banner註冊成單例Bean

6、是否添加LazyInitializationBeanFactoryPostProcessor進行懶加載處理

7、 將main類註冊BeanDefinition

8、回調SpringApplicationRunListener的contextLoaded方法


// 將main方法的args參數進行封裝
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 準備Environment
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 配置忽略注入的Bean
configureIgnoreBeanInfo(environment);
// 打印banner圖
Banner printedBanner = printBanner(environment);
// 反射創建ApplicationContext對象
context = createApplicationContext();
// 還在加載自動裝配的SpringBootExceptionReporter類型, 默認只有FailureAnalyzers
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
// 爲ApplicationContext設置屬性、做refresh的準備工作
prepareContext(context, environment, listeners, applicationArguments, printedBanner);

一、創建和配置Environment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                   ApplicationArguments applicationArguments) {
    // Create and configure the environment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach(environment);
    listeners.environmentPrepared(environment);
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

1、創建Environment對象(getOrCreateEnvironment)

private ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
    }
}

    根據之前斷定的webApplicationType類型(run之前可以通過set方法進行修改),創建不同類型的Environment類型。

2、配置Environment(ConversionService、main方法傳入的args參數、Profile)

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    configurePropertySources(environment, args);
    configureProfiles(environment, args);
}

3、SpringApplicationRunListener的environmentPrepared回調

void environmentPrepared(ConfigurableEnvironment environment) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.environmentPrepared(environment);
    }
}

4、自定義Environment

    如果是自定義Environment,則使用EnvironmentConverter進行處理。

 

二、反射創建ApplicationContext對象

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch (this.webApplicationType) {
                case SERVLET:  // AnnotationConfigServletWebServerApplicationContext
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;    
                case REACTIVE: // AnnotationConfigReactiveWebServerApplicationContext
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:       // AnnotationConfigApplicationContext
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
        }
        catch (ClassNotFoundException ex) { // 省略部分代碼  }
    }
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

    與配置ConfigurableEnvironment 一樣,根據webApplicationType通過反射創建ConfigurableApplicationContext 類型對象。

 

三、prepareContext

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
                            SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {

    // 爲Spring容器設置初始化的環境
    context.setEnvironment(environment);

    // 爲ConfigurableApplicationContext設置屬性(bean名稱生成器、Resource加載器和 
    // ConversionService)
    postProcessApplicationContext(context);
    // 回調ApplicationContextInitializer的initialize方法
    applyInitializers(context);
    // 回調SpringApplicationRunListener的contextPrepared方法
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    // Add boot specific singleton beans
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    // 將applicationArguments、Banner註冊成單例Bean
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    if (beanFactory instanceof DefaultListableBeanFactory) {
        ((DefaultListableBeanFactory) beanFactory)
                .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    // 是否添加LazyInitializationBeanFactoryPostProcessor進行懶加載處理
    if (this.lazyInitialization) {
        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    }

    // 將sources註冊BeanDefinition,沒有特殊添加,則會將main註冊BeanDefinition
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[0]));

    // 回調SpringApplicationRunListener的contextLoaded方法
    listeners.contextLoaded(context);
}

1、爲Spring容器設置初始化的環境

    context.setEnvironment(environment);

2、爲ConfigurableApplicationContext設置屬性

    默認bean名稱生成器、Resource加載器爲空,則不會進行設置。ConversionService則會設置ApplicationConversionService.sharedInstance單例對象。

3、回調ApplicationContextInitializerinitialize方法

    循環調用ApplicationContextInitializerinitialize初始化方法。

4、回調SpringApplicationRunListener的contextPrepared方法


5、將applicationArguments、Banner註冊成單例Bean

    其Bean名稱和Bean對象對應關係爲(後續我們需要的時候可以通過getBean方法進行獲取,使用):

springApplicationArguments
ApplicationArguments對象
springBootBanner
SpringBootBanner


6、是否添加LazyInitializationBeanFactoryPostProcessor進行懶加載處理

7、 將main類註冊BeanDefinition

將sources註冊BeanDefinition,沒有特殊添加,則會將main註冊BeanDefinition。個人理解,上面將不會再進行修改的applicationArguments等直接註冊成Bean。而將可能通過BeanPostProcessor修改的main方法類,只是註冊成BeanDefinition。

8、回調SpringApplicationRunListener的contextLoaded方法

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章