Spring源碼8. prepareContext()準(zhǔn)備應(yīng)用上下文

上篇回顧

上一篇SpringBootExceptionReporter異常上報(bào)中分析了springboot如何處理啟動(dòng)過(guò)程中的異常


目錄

1. 準(zhǔn)備容器prepareContext()
2. 統(tǒng)一ApplicationContext和Application使用的environment
3. ApplicationContext的后置處理
4. 執(zhí)行Initializers
????4.1 DelegatingApplicationContextInitializer
????4.2 SharedMetadataReaderFactoryContextInitializer
????4.3 ContextIdApplicationContextInitializer
????4.4 ConfigurationWarningsApplicationContextInitializer
????4.5 ServerPortInfoApplicationContextInitializer
????4.6 ConditionEvaluationReportLoggingListener
5. 發(fā)布ApplicationContextInitializedEvent事件
6. 打印啟動(dòng)和profile日志
7. 手工注冊(cè)單例Bean
8. 初始化BeanDefinitionLoader, 加載Application
9. 發(fā)布contextLoaded事件
????9.1 ConfigFileApplicationListener
????9.2 LoggingApplicationListener
????9.3 BackgroundPreinitializer
????9.4 DelegatingApplicationListener

1. 準(zhǔn)備環(huán)境prepareContext()

準(zhǔn)備應(yīng)用上下文環(huán)境AnnotationConfigServletWebServerApplicationContext, 執(zhí)行了以下8個(gè)步驟

  1. 統(tǒng)一ApplicationContext和Application使用的environment
  2. 后置處理ApplicationContext
  3. 執(zhí)行Initializers
  4. 發(fā)布contextPrepared事件
  5. 打印啟動(dòng)和profile日志
  6. 注冊(cè)單例bean
  7. 加載啟動(dòng)類(lèi)
  8. 發(fā)布contextLoaded事件
public class SpringApplication {

    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
                
            //本文的重點(diǎn)
            //準(zhǔn)備應(yīng)用上下文
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            //...
    }
    

    /**
     * 準(zhǔn)備應(yīng)用上下文
     * @param context AnnotationConfigServletWebServerApplicationContext實(shí)例
     * @param environment SpringApplication中的StandardServletEnvironment實(shí)例
     * @param applicationArguments SpringApplication中的DefaultApplicationArguments實(shí)例
     * @param printedBanner 默認(rèn)使用SpringApplicationBanner實(shí)例
     */
    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        //設(shè)置context(上下文)環(huán)境
        //統(tǒng)一ApplicationContext和Application,使用Application的environment
        context.setEnvironment(environment);
        //ApplicationContext的后置處理
        postProcessApplicationContext(context);
        //執(zhí)行Initializers
        applyInitializers(context);
        //發(fā)布contextPrepared事件
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            //配置了info日志
            //打印啟動(dòng)和profile日志
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        //獲取到DefaultListableBeanFactory實(shí)例
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //注冊(cè)名為springApplicationArguments,值為applicationArguments的單例bean
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        //banner不為空,那么注冊(cè)名為springBootBanner,值為printedBanner的單例bean
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            //allowBeanDefinitionOverriding默認(rèn)為false
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // 獲取sources列表,獲取到我們的YanggxApplication.class
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        //初始化bean加載器,并加載bean到應(yīng)用上下文
        load(context, sources.toArray(new Object[0]));
        //發(fā)布contextLoaded事件
        listeners.contextLoaded(context);
    }
}

2. 統(tǒng)一ApplicationContext和Application使用的environment

配置ApplicationContext和Application的environment成員變量, 使用Application的environment, AnnotationConfigServletWebServerApplicationContext的bean定讀取器reader和bean掃描器scanner都使用Application的environment

public class AnnotationConfigServletWebServerApplicationContext
        extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
    @Override
    public void setEnvironment(ConfigurableEnvironment environment) {
        //顯式調(diào)用父類(lèi)AbstractApplicationContext的setEnvironment方法
        super.setEnvironment(environment);
        //調(diào)用AnnotatedBeanDefinitionReader#setEnvironment()方法
        this.reader.setEnvironment(environment);
        
        //ClassPathBeanDefinitionScanner繼承了ClassPathScanningCandidateComponentProvider,所以調(diào)用了父類(lèi)setEnvironment方法
        this.scanner.setEnvironment(environment);
    }
}
顯式調(diào)用父類(lèi)AbstractApplicationContext的setEnvironment方法
public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    
    //environment成員變量
    @Nullable
    private ConfigurableEnvironment environment;
    
    @Override
    public void setEnvironment(ConfigurableEnvironment environment) {
        this.environment = environment;
    }
}
調(diào)用AnnotatedBeanDefinitionReader#setEnvironment()方法
public class AnnotatedBeanDefinitionReader {
    public void setEnvironment(Environment environment) {
        //初始化conditionEvaluator
        this.conditionEvaluator = new ConditionEvaluator(this.registry, environment, null);
    }
}
調(diào)用ClassPathBeanDefinitionScanner的setEnvironment方法

ClassPathBeanDefinitionScanner繼承了ClassPathScanningCandidateComponentProvider, 所以調(diào)用了父類(lèi)setEnvironment方法

ublic class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
    @Nullable
    private Environment environment;

    public void setEnvironment(Environment environment) {
        Assert.notNull(environment, "Environment must not be null");
        this.environment = environment;
        //conditionEvaluator置為null
        this.conditionEvaluator = null;
    }
}

3. ApplicationContext的后置處理

執(zhí)行了以下三步

  1. 設(shè)置ApplicationContext的beanNameGenerator
  2. 設(shè)置ApplicationContext的resourceLoader和classLoader
  3. 設(shè)置ApplicationContext的類(lèi)型轉(zhuǎn)換Service
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
        //沒(méi)有設(shè)置beanNameGenerator,默認(rèn)為null
        if (this.beanNameGenerator != null) {
            //如果beanNameGenerator不為空
            //那么注冊(cè)一個(gè)名為internalConfigurationBeanNameGenerator
            //值為beanNameGenerator的單例bean
            context.getBeanFactory().registerSingleton(
                    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                    this.beanNameGenerator);
        }
        //沒(méi)有設(shè)置resourceLoader,默認(rèn)為null
        if (this.resourceLoader != null) {
            //如果resourceLoader不為空
            if (context instanceof GenericApplicationContext) {
                //context是GenericApplicationContext子類(lèi)
                //那么設(shè)置上下文context的resourceLoader
                ((GenericApplicationContext) context)
                        .setResourceLoader(this.resourceLoader);
            }
            if (context instanceof DefaultResourceLoader) {
                //如果當(dāng)前上下文是DefaultResourceLoader的子類(lèi)
                //那么設(shè)置上下文context的classLoader
                ((DefaultResourceLoader) context)
                        .setClassLoader(this.resourceLoader.getClassLoader());
            }
        }
        //this.addConversionService默認(rèn)為true
        if (this.addConversionService) {
            //設(shè)置類(lèi)型轉(zhuǎn)換Service
            context.getBeanFactory().setConversionService(
                    ApplicationConversionService.getSharedInstance());
        }
    }

4. 執(zhí)行Initializers

initializers在SpringApplication初始化期間獲取到, 一共獲取到6個(gè)初始化器:

  • DelegatingApplicationContextInitializer
  • SharedMetadataReaderFactoryContextInitializer
  • ContextIdApplicationContextInitializer
  • ConfigurationWarningsApplicationContextInitializer
  • ServerPortInfoApplicationContextInitializer
  • ConditionEvaluationReportLoggingListener
protected void applyInitializers(ConfigurableApplicationContext context) {
    for (ApplicationContextInitializer initializer : getInitializers()) {
        //斷言判斷initializer的類(lèi)型是否符合條件
        Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
                initializer.getClass(), ApplicationContextInitializer.class);
        Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
        //執(zhí)行各個(gè)initializer的初始化initialize方法
        initializer.initialize(context);
    }
}
4.1 DelegatingApplicationContextInitializer

獲取環(huán)境中屬性context.initializer.classesInitializer配置的ApplicationContextInitializer列表, 執(zhí)行其initialize()方法, 由于我們沒(méi)有配置屬性context.initializer.classesInitializer, 所以不會(huì)執(zhí)行任何操作

//代理初始化器
public class DelegatingApplicationContextInitializer implements
        ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
        
    private static final String PROPERTY_NAME = "context.initializer.classes";
    
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        ConfigurableEnvironment environment = context.getEnvironment();
        //獲取environment中配置的context.initializer.classes屬性
        //其值為各個(gè)initializer,用逗號(hào)分隔開(kāi)
        List<Class<?>> initializerClasses = getInitializerClasses(environment);
        if (!initializerClasses.isEmpty()) {
            //獲取到各個(gè)initializer,并執(zhí)行其initialize()方法
            applyInitializerClasses(context, initializerClasses);
        }
    }
            
}
4.2 SharedMetadataReaderFactoryContextInitializer

添加了一個(gè)類(lèi)型為CachingMetadataReaderFactoryPostProcessor的BeanFactoryPostProcessor, CachingMetadataReaderFactoryPostProcessor會(huì)做兩件事情

  • 注冊(cè)一個(gè)名稱(chēng)為internalCachingMetadataReaderFactory, 類(lèi)型為SharedMetadataReaderFactoryBean的bean, 用于讀取bean的元數(shù)據(jù)Metadata
  • 獲取名稱(chēng)為internalConfigurationAnnotationProcessor, 類(lèi)型為ConfigurationClassPostProcessor的bean定義, 為其添加name為metadataReaderFactory, value為internalCachingMetadataReaderFactory的internalCachingMetadataReaderFactory
class SharedMetadataReaderFactoryContextInitializer implements
        ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {

    public static final String BEAN_NAME = "org.springframework.boot.autoconfigure."
            + "internalCachingMetadataReaderFactory";

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        //spring上下文容器添加一個(gè)CachingMetadataReaderFactoryPostProcessor
        applicationContext.addBeanFactoryPostProcessor(
                new CachingMetadataReaderFactoryPostProcessor());
    }
}
4.3 ContextIdApplicationContextInitializer

初始化容器ID, 獲取屬性spring.application.name配置的應(yīng)用名稱(chēng), 如果不存在的話(huà), 默認(rèn)使用application

//容器ID初始化器
public class ContextIdApplicationContextInitializer implements
        ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        //獲取并設(shè)置容器ID
        ContextId contextId = getContextId(applicationContext);
        applicationContext.setId(contextId.getId());
        //容器beanFactory中注冊(cè)一個(gè)名稱(chēng)為ContextId類(lèi)名
        //值為contextId的bean
        applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(),
                contextId);
    }
    
    //獲取ContextID
    private ContextId getContextId(ConfigurableApplicationContext applicationContext) {
        //父容器獲取spring.application.name對(duì)應(yīng)的bean
        ApplicationContext parent = applicationContext.getParent();
        if (parent != null && parent.containsBean(ContextId.class.getName())) {
            return parent.getBean(ContextId.class).createChildId();
        }
        //父容器獲取不到,則生成一個(gè)contextId
        return new ContextId(getApplicationId(applicationContext.getEnvironment()));
    }
    
    //獲取應(yīng)用ID
    private String getApplicationId(ConfigurableEnvironment environment) {
        //獲取屬性:spring.application.name
        String name = environment.getProperty("spring.application.name");
        //如果為空,默認(rèn)名application
        return StringUtils.hasText(name) ? name : "application";
    }

    //ContextId類(lèi)
    class ContextId {
        //原子Long類(lèi)
        private final AtomicLong children = new AtomicLong(0);

        private final String id;

        ContextId(String id) {
            this.id = id;
        }

        ContextId createChildId() {
            //線(xiàn)程安全遞增
            return new ContextId(this.id + "-" + this.children.incrementAndGet());
        }

        String getId() {
            return this.id;
        }

    }
            
}
4.4 ConfigurationWarningsApplicationContextInitializer

配置告警初始化器, 用于檢測(cè)注解了包org, org.springframework包內(nèi)的類(lèi), 如果注解了,那么打印warn日志

public class ConfigurationWarningsApplicationContextInitializer
        implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(ConfigurableApplicationContext context) {
        //添加一個(gè)beanFactory后置處理器
        //ConfigurationWarningsPostProcessor的子類(lèi)
        context.addBeanFactoryPostProcessor(
                new ConfigurationWarningsPostProcessor(getChecks()));
    }

    //返回ComponentScanPackageCheck實(shí)例
    protected Check[] getChecks() {
        return new Check[] { new ComponentScanPackageCheck() };
    }

    /**
     * 配置錯(cuò)誤后置處理器
     */
    protected static final class ConfigurationWarningsPostProcessor
            implements PriorityOrdered, BeanDefinitionRegistryPostProcessor {

        private Check[] checks;

        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
                throws BeansException {
            //處理各個(gè)檢查之后的警告
            for (Check check : this.checks) {
                //沒(méi)有問(wèn)題的話(huà)message為null
                String message = check.getWarning(registry);
                if (StringUtils.hasLength(message)) {
                    //有錯(cuò)誤信息,打印告警信息
                    warn(message);
                }
            }

        }

        private void warn(String message) {
            if (logger.isWarnEnabled()) {
                //打印告警日志
                logger.warn(String.format("%n%n** WARNING ** : %s%n%n", message));
            }
        }
    }
    
    //Component注解掃描Check類(lèi)
    protected static class ComponentScanPackageCheck implements Check {

        //有問(wèn)題的包
        private static final Set<String> PROBLEM_PACKAGES;

        static {
            //將org和org.springframework包添加到PROBLEM_PACKAGES
            //也就是不允許配置這兩個(gè)包內(nèi)的類(lèi)方法和屬性
            Set<String> packages = new HashSet<>();
            packages.add("org.springframework");
            packages.add("org");
            PROBLEM_PACKAGES = Collections.unmodifiableSet(packages);
        }

        @Override
        public String getWarning(BeanDefinitionRegistry registry) {
            //獲取被掃描的包
            Set<String> scannedPackages = getComponentScanningPackages(registry);
            //獲取有問(wèn)題的包
            List<String> problematicPackages = getProblematicPackages(scannedPackages);
            if (problematicPackages.isEmpty()) {
                //沒(méi)有問(wèn)題返回null
                return null;
            }
            //有問(wèn)題返回的錯(cuò)誤信息
            return "Your ApplicationContext is unlikely to "
                    + "start due to a @ComponentScan of "
                    + StringUtils.collectionToDelimitedString(problematicPackages, ", ")
                    + ".";
        }

        private boolean isProblematicPackage(String scannedPackage) {
            if (scannedPackage == null || scannedPackage.isEmpty()) {
                return true;
            }
            //如果包名為org或者org.springframework
            //那么返回true,否則返回false
            return PROBLEM_PACKAGES.contains(scannedPackage);
        }

        private String getDisplayName(String scannedPackage) {
            if (scannedPackage == null || scannedPackage.isEmpty()) {
                return "the default package";
            }
            return "'" + scannedPackage + "'";
        }
    }
}
4.5 ServerPortInfoApplicationContextInitializer

服務(wù)端口初始化器, 分別實(shí)現(xiàn)了ApplicationContextInitializer和ApplicationListener接口, 在applicationContext中添加了事件監(jiān)聽(tīng)器this, 監(jiān)聽(tīng)了WebServerInitializedEvent事件, 配置服務(wù)的端口號(hào)

public class ServerPortInfoApplicationContextInitializer
        implements ApplicationContextInitializer<ConfigurableApplicationContext>,
        ApplicationListener<WebServerInitializedEvent> {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        //把this添加到Application的listener中
        applicationContext.addApplicationListener(this);
    }
    
    //監(jiān)聽(tīng)處理WebServerInitializedEvent事件
    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        //獲取environment中配置的server.ports
        String propertyName = "local." + getName(event.getApplicationContext()) + ".port";
        setPortProperty(event.getApplicationContext(), propertyName,
                event.getWebServer().getPort());
    }
}
4.6 ConditionEvaluationReportLoggingListener

條件評(píng)估日志監(jiān)聽(tīng)器, 主要作用是給applicationContext添加了一個(gè)ConditionEvaluationReportListener監(jiān)聽(tīng)器, ConditionEvaluationReportListener監(jiān)聽(tīng)了ContextRefreshedEvent和ApplicationFailedEvent事件, 打印相應(yīng)日志

public class ConditionEvaluationReportLoggingListener
        implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        //applicationContext中添加一個(gè)ConditionEvaluationReportListener
        applicationContext
                .addApplicationListener(new ConditionEvaluationReportListener());
        if (applicationContext instanceof GenericApplicationContext) {
            //注冊(cè)一個(gè)ConditionEvaluationReport bean
            this.report = ConditionEvaluationReport
                    .get(this.applicationContext.getBeanFactory());
        }
    }
    
    //監(jiān)聽(tīng)到ApplicationEvent
    protected void onApplicationEvent(ApplicationEvent event) {
        ConfigurableApplicationContext initializerApplicationContext = this.applicationContext;
        if (event instanceof ContextRefreshedEvent) {
            //ContextRefreshed事件
            if (((ApplicationContextEvent) event)
                    .getApplicationContext() == initializerApplicationContext) {
                logAutoConfigurationReport();
            }
        }
        else if (event instanceof ApplicationFailedEvent
                && ((ApplicationFailedEvent) event)
                        .getApplicationContext() == initializerApplicationContext) {
            //ApplicationFailedEvent事件
            logAutoConfigurationReport(true);
        }
    }
}

//用于記錄Condition注解的評(píng)估情況
public final class ConditionEvaluationReport {

    //bean名稱(chēng)為autoConfigurationReport
    //類(lèi)型為ConditionEvaluationReport
    private static final String BEAN_NAME = "autoConfigurationReport";
    
    //從beanFactory中獲取ConditionEvaluationReport實(shí)例
    public static ConditionEvaluationReport get(
            ConfigurableListableBeanFactory beanFactory) {
        synchronized (beanFactory) {
            ConditionEvaluationReport report;
            if (beanFactory.containsSingleton(BEAN_NAME)) {
                //如果bean已經(jīng)被注冊(cè),立即返回
                report = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class);
            }
            else {
                //否則注冊(cè)bean
                report = new ConditionEvaluationReport();
                beanFactory.registerSingleton(BEAN_NAME, report);
            }
            locateParent(beanFactory.getParentBeanFactory(), report);
            return report;
        }
    }
}

5. 發(fā)布ApplicationContextInitializedEvent事件

Application容器初始化完成事件, 對(duì)該事件感興趣的監(jiān)聽(tīng)器有

  1. BackgroundPreinitializer
  2. DelegatingApplicationListener
BackgroundPreinitializer

擴(kuò)展點(diǎn), 后臺(tái)進(jìn)程初始化器, 用于多線(xiàn)程執(zhí)行后臺(tái)耗時(shí)任務(wù), 在這里不處理ApplicationContextInitializedEvent事件

DelegatingApplicationListener

擴(kuò)展點(diǎn), 代理監(jiān)聽(tīng)器, 繼續(xù)分發(fā)事件, 不處理ApplicationContextInitializedEvent事件

6. 打印啟動(dòng)和profile日志

//logStartupInfo默認(rèn)為true
if (this.logStartupInfo) {
        //打印項(xiàng)目啟動(dòng)信息
        // Starting YanggxApplication on pcname with PID 12372 (E:\java\spring\target\classes started by username in E:\java\spring)
        logStartupInfo(context.getParent() == null);
    
        //打印profile
        //No active profile set, falling back to default profiles: default
        logStartupProfileInfo(context);
    }

7. 注冊(cè)單例Bean

注冊(cè)了兩個(gè)單例Bean

  • 命令行參數(shù)bean, 名稱(chēng)為springApplicationArguments, 值為applicationArgument
  • banner bean, 名稱(chēng)為springBootBanner, 值為printedBanner
//注冊(cè)命令行參數(shù)bean
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
    //banner bean
    beanFactory.registerSingleton("springBootBanner", printedBanner);
}
7.1 手工注冊(cè)單例Bean流程

調(diào)用DefaultListableBeanFactory#registerSingleton方法, 顯示調(diào)用父類(lèi)DefaultSingletonBeanRegistry#registerSingleton方法

DefaultListableBeanFactory 手工注冊(cè)單例Bean

手工注冊(cè)單例Bean, 不同于掃描bean定義, 然后注冊(cè)單例bean, 手工注冊(cè)的單例Bean, 沒(méi)有維護(hù)到beanDefinitionMap中, 而是將beanName維護(hù)到manualSingletonNames中

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    //注冊(cè)單例bean
    public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
        super.registerSingleton(beanName, singletonObject);

        //判斷bean的創(chuàng)建過(guò)程是否已經(jīng)開(kāi)始了
        //調(diào)用抽象父類(lèi)AbstractBeanFactory#hasBeanCreationStarted()方法
        //判斷AbstractBeanFactory成員變量alreadyCreated Set不為空
        if (hasBeanCreationStarted()) {
            //bean創(chuàng)建過(guò)程已經(jīng)開(kāi)始了
            //鎖住成員變量beanDefinitionMap
            synchronized (this.beanDefinitionMap) {
                if (!this.beanDefinitionMap.containsKey(beanName)) {
                    //如果bean定義Map,  beanDefinitionMap已經(jīng)包含了bean
                    //維護(hù)到手工單例bean名稱(chēng)manualSingletonNames中
                    Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames.size() + 1);
                    updatedSingletons.addAll(this.manualSingletonNames);
                    updatedSingletons.add(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }
        else {
            // bean還沒(méi)有注冊(cè)過(guò), 仍處于啟動(dòng)注冊(cè)階段
            if (!this.beanDefinitionMap.containsKey(beanName)) {
                //如果beanDefinitionMap不包含beanName
                //那么添加到manualSingletonNames
                this.manualSingletonNames.add(beanName);
            }
        }

        //清空allBeanNamesByType和singletonBeanNamesByType
        clearByTypeCache();
    }
}
DefaultSingletonBeanRegistry手工注冊(cè)單例Bean

將beanName添加到registeredSingletons中, beanName和對(duì)應(yīng)的對(duì)象保存singletonObjects中, 并刪除beanName對(duì)應(yīng)的beanFactory, earlySingleton

//默認(rèn)單例bean注冊(cè)器
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    
    //緩存單例bean, key為bean名稱(chēng),value為bean實(shí)例
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    //緩存beanFactory, key為bean名稱(chēng), value為beanFactory
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    //早期單例緩存, key為bean名稱(chēng), value為bean實(shí)例
    //為了解決循環(huán)依賴(lài)而引入的
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    //單例bean名稱(chēng)set
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

    //正在創(chuàng)建的單例bean名稱(chēng)set
    private final Set<String> singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));


    //手工注冊(cè)單例bean
    @Override
    public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
        //判斷名稱(chēng)和值不可以為空
        Assert.notNull(beanName, "Bean name must not be null");
        Assert.notNull(singletonObject, "Singleton object must not be null");
        synchronized (this.singletonObjects) {
            //判斷bean是否為空
            Object oldObject = this.singletonObjects.get(beanName);
            if (oldObject != null) {
                //不為空拋異常
                throw new IllegalStateException("Could not register object [" + singletonObject +
                        "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
            }
            //添加一個(gè)單例bean
            addSingleton(beanName, singletonObject);
        }
    }
    
    //添加一個(gè)單例bean
    protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            //保存到singletonObjects的map中
            this.singletonObjects.put(beanName, singletonObject);
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            //添加beanName
            this.registeredSingletons.add(beanName);
        }
    }
}

8. 初始化BeanDefinitionLoader, 加載Application

首先生成一個(gè)BeanDefinitionLoader, 用于加載SpringApplication的成員變量sources, 當(dāng)前sources列表中只有YanggxApplication.class一個(gè)對(duì)象

protected void load(ApplicationContext context, Object[] sources) {
    if (logger.isDebugEnabled()) {
        logger.debug(
                "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    //實(shí)例化BeanDefinitionLoader
    BeanDefinitionLoader loader = createBeanDefinitionLoader(
            getBeanDefinitionRegistry(context), sources);
    //this.beanNameGenerator為null
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    //this.resourceLoader為null
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    //this.environment為null
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    //調(diào)用load()方法,加載各個(gè)sources
    loader.load();
}
8.1 BeanDefinitionLoader

加載SpringApplication維護(hù)的sources列表資源, 可以加載類(lèi), XML, groovy等資源, 由于我們傳入的sources中只有一個(gè)YanggxApplication.class, 所以調(diào)用的是load(Class<?> source)方法, 最后調(diào)用的是AnnotatedBeanDefinitionReader#register()方法, 注冊(cè)了一個(gè)Bean定義

class BeanDefinitionLoader {

    //啟動(dòng)類(lèi)列表
    private final Object[] sources;

    //注解Bean定義讀取器
    private final AnnotatedBeanDefinitionReader annotatedReader;

    //XML Bean定義讀取器
    private final XmlBeanDefinitionReader xmlReader;

    //groovy Bean定義讀取器
    private BeanDefinitionReader groovyReader;

    //Bean定義掃描器
    private final ClassPathBeanDefinitionScanner scanner;

    //資源加載器
    private ResourceLoader resourceLoader;

    /**
     * 構(gòu)造函數(shù)
     */
    BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
        Assert.notNull(registry, "Registry must not be null");
        Assert.notEmpty(sources, "Sources must not be empty");
        //傳入的sources, 目前只有YanggxApplication.class
        this.sources = sources;
        this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
        this.xmlReader = new XmlBeanDefinitionReader(registry);
        if (isGroovyPresent()) {
            //使用了groovy
            this.groovyReader = new GroovyBeanDefinitionReader(registry);
        }
        this.scanner = new ClassPathBeanDefinitionScanner(registry);
        //排除sources掃描
        this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
    }

    /**
     * 加載sources
     */
    public int load() {
        int count = 0;
        for (Object source : this.sources) {
            count += load(source);
        }
        return count;
    }
    
    //加載Object資源
    private int load(Object source) {
        Assert.notNull(source, "Source must not be null");
        if (source instanceof Class<?>) {
            //加載類(lèi)資源
            return load((Class<?>) source);
        }
        if (source instanceof Resource) {
            //加載Resource資源
            return load((Resource) source);
        }
        if (source instanceof Package) {
            //加載Package資源
            return load((Package) source);
        }
        if (source instanceof CharSequence) {
            //加載字符串資源
            return load((CharSequence) source);
        }
        throw new IllegalArgumentException("Invalid source type " + source.getClass());
    }

    //加載類(lèi)資源
    private int load(Class<?> source) {
        if (isGroovyPresent()
                && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            // 使用了groovy,加載groovy資源
            GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
                    GroovyBeanDefinitionSource.class);
            load(loader);
        }
        //如果是@Component注解
        if (isComponent(source)) {
            this.annotatedReader.register(source);
            return 1;
        }
        return 0;
    }

    //加載groovy資源
    private int load(GroovyBeanDefinitionSource source) {
        int before = this.xmlReader.getRegistry().getBeanDefinitionCount();
        ((GroovyBeanDefinitionReader) this.groovyReader).beans(source.getBeans());
        int after = this.xmlReader.getRegistry().getBeanDefinitionCount();
        return after - before;
    }
    //加載resource資源
    private int load(Resource source) {
        if (source.getFilename().endsWith(".groovy")) {
            //使用了groovy
            if (this.groovyReader == null) {
                throw new BeanDefinitionStoreException(
                        "Cannot load Groovy beans without Groovy on classpath");
            }
            return this.groovyReader.loadBeanDefinitions(source);
        }
        //加載xml資源
        return this.xmlReader.loadBeanDefinitions(source);
    }
    
    //加載package資源
    private int load(Package source) {
        //scanner掃描
        return this.scanner.scan(source.getName());
    }

    //load xml資源
    private int load(CharSequence source) {
        String resolvedSource = this.xmlReader.getEnvironment()
                .resolvePlaceholders(source.toString());
        try {
            //先嘗試加載類(lèi)資源
            return load(ClassUtils.forName(resolvedSource, null));
        }
        catch (IllegalArgumentException | ClassNotFoundException ex) {
        }
        // 不成功的話(huà),加載resource資源
        Resource[] resources = findResources(resolvedSource);
        int loadCount = 0;
        boolean atLeastOneResourceExists = false;
        for (Resource resource : resources) {
            if (isLoadCandidate(resource)) {
                atLeastOneResourceExists = true;
                loadCount += load(resource);
            }
        }
        if (atLeastOneResourceExists) {
            return loadCount;
        }
        // 不成功的話(huà),加載package資源
        Package packageResource = findPackage(resolvedSource);
        if (packageResource != null) {
            return load(packageResource);
        }
        //還不成功的話(huà),就拋異常
        throw new IllegalArgumentException("Invalid source '" + resolvedSource + "'");
    }
}
AnnotatedBeanDefinitionReader注冊(cè)Bean定義
public class AnnotatedBeanDefinitionReader {

    //Class列表注冊(cè)Bean定義
    public void register(Class<?>... annotatedClasses) {
        for (Class<?> annotatedClass : annotatedClasses) {
            //單個(gè)Bean注冊(cè)
            registerBean(annotatedClass);
        }
    }
    
    //單個(gè)Class注冊(cè)bean
    public void registerBean(Class<?> annotatedClass) {
        doRegisterBean(annotatedClass, null, null, null);
    }

    //注冊(cè)Bean定義
    <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
            @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
        //生成注解BeanDefinition
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
        
        //判斷是否符合@Conditional注解的條件
        //不滿(mǎn)足的話(huà), 就不注冊(cè)Bean
        if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            return;
        }
        //設(shè)置instanceSupplier, //AbstractAutowireCapableBeanFactory#createBeanInstance中調(diào)用了instanceSupplier.get()生成bean實(shí)例
        abd.setInstanceSupplier(instanceSupplier);
        //Scope元空間
        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        abd.setScope(scopeMetadata.getScopeName());
        //生成Bean名稱(chēng)
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

        //處理Lazy, Primary, DependsOn, Role, Description注解
        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        if (qualifiers != null) {
            for (Class<? extends Annotation> qualifier : qualifiers) {
                if (Primary.class == qualifier) {
                    abd.setPrimary(true);
                }
                else if (Lazy.class == qualifier) {
                    abd.setLazyInit(true);
                }
                else {
                    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                }
            }
        }
        for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
            //beanDefinition定制器
            customizer.customize(abd);
        }

        //bean定義容器
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        
        //Scope代理模式處理
        //ScopedProxyMode.DEFAULT和NO不需要代理處理
        //INTERFACES使用JDK動(dòng)態(tài)代理
        //TARGET_CLASS使用CGLIB動(dòng)態(tài)代理
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        
        //注冊(cè)Bean定義
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }
}

9. 發(fā)布contextLoaded事件

調(diào)用listeners.contextLoaded(context), 發(fā)布了一個(gè)ApplicationPreparedEvent事件, 對(duì)ApplicationPreparedEvent事件感興趣的監(jiān)聽(tīng)器有:

  1. ConfigFileApplicationListener
  2. LoggingApplicationListener
  3. BackgroundPreinitializer
  4. DelegatingApplicationListener
9.1 ConfigFileApplicationListener

配置文件監(jiān)聽(tīng)器

public class ConfigFileApplicationListener
        implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
    //事件處理
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            onApplicationEnvironmentPreparedEvent(
                    (ApplicationEnvironmentPreparedEvent) event);
        }
        if (event instanceof ApplicationPreparedEvent) {
            //處理ApplicationPreparedEvent
            onApplicationPreparedEvent(event);
        }
    }
    
    //處理ApplicationPreparedEvent
    private void onApplicationPreparedEvent(ApplicationEvent event) {
        this.logger.switchTo(ConfigFileApplicationListener.class);
        addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());
    }
    
    //applicationContext中添加一個(gè)PropertySourceOrderingPostProcessor
    protected void addPostProcessors(ConfigurableApplicationContext context) {
        //用于重排序PropertySourceOrderingPostProcessor
        context.addBeanFactoryPostProcessor(
                new PropertySourceOrderingPostProcessor(context));
    }
}
9.2 LoggingApplicationListener

日志監(jiān)聽(tīng)器

public class LoggingApplicationListener implements GenericApplicationListener {

    private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
        ConfigurableListableBeanFactory beanFactory = event.getApplicationContext()
                .getBeanFactory();
        //注冊(cè)日志單例bean
        if (!beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) {
            beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem);
        }
    }
    
}
9.3 BackgroundPreinitializer

后臺(tái)預(yù)初始化器, 當(dāng)前不做任務(wù)處理, 方便以后擴(kuò)展

9.4 DelegatingApplicationListener

代理監(jiān)聽(tīng)器, 不做任何處理, 方便以后擴(kuò)展

總結(jié)

這一步的主要作用是為下面刷新applicationContext做準(zhǔn)備

  • 統(tǒng)一了ApplicationContext和Application的environment
  • 設(shè)置ApplicationContext的beanNameGenerator,resouceLoader和classLoader, 并設(shè)置beanFactory的類(lèi)型轉(zhuǎn)換Service
  • 執(zhí)行Initializer
  • 發(fā)布ApplicationContextInitializedEvent
  • 打印啟動(dòng)日志和profile日志
  • 手工注冊(cè)命令行和banner兩個(gè)單例Bean
  • 初始化BeanDefinitionLoader, 加載啟動(dòng)類(lèi)sources
  • 發(fā)布contextLoaded事件

下一篇

我們將會(huì)在下一篇refreshContext()刷新應(yīng)用上下文, 研究springboot如何掃描加載bean, 如何建立webserver容器

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末轻绞,一起剝皮案震驚了整個(gè)濱河市佣耐,隨后出現(xiàn)的幾起案子懒叛,更是在濱河造成了極大的恐慌诅迷,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜘欲,死亡現(xiàn)場(chǎng)離奇詭異展鸡,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)座泳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)诫给,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)盛险,“玉大人鹤啡,你說(shuō)我怎么就攤上這事』┳埽” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)转质。 經(jīng)常有香客問(wèn)我辉饱,道長(zhǎng),這世上最難降的妖魔是什么唯沮? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任介蛉,我火速辦了婚禮践险,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘担忧。我一直安慰自己纤壁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布酌媒。 她就那樣靜靜地躺著欠痴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪秒咨。 梳的紋絲不亂的頭發(fā)上斋否,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音拭荤,去河邊找鬼茵臭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛舅世,可吹牛的內(nèi)容都是我干的旦委。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼雏亚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼缨硝!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起罢低,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤查辩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后网持,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體宜岛,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年功舀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了萍倡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辟汰,死狀恐怖列敲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情帖汞,我是刑警寧澤戴而,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站翩蘸,受9級(jí)特大地震影響所意,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一扁眯、第九天 我趴在偏房一處隱蔽的房頂上張望壮莹。 院中可真熱鬧,春花似錦姻檀、人聲如沸命满。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)胶台。三九已至,卻和暖如春杂抽,著一層夾襖步出監(jiān)牢的瞬間诈唬,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工缩麸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铸磅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓杭朱,卻偏偏與公主長(zhǎng)得像阅仔,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子弧械,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring容器高層視圖 Spring 啟動(dòng)時(shí)讀取應(yīng)用程序提供的Bean配置信息八酒,并在Spring容器中生成一份相...
    Theriseof閱讀 2,799評(píng)論 1 24
  • 1.Spring整體架構(gòu) 1)核心容器(Core Container) Core模塊,主要包含了Spring框架基...
    Sponge1128閱讀 1,057評(píng)論 0 1
  • 參考W3C Spring教程 Spring致力于J2EE應(yīng)用的各種解決方案刃唐,而不僅僅專(zhuān)注于某一層解決方案羞迷。可以說(shuō)S...
    王偵閱讀 1,153評(píng)論 0 6
  • 什么是Spring框架画饥? ?Spring框架是個(gè)輕量級(jí)的Java EE框架衔瓮。所謂輕量級(jí),是指不依賴(lài)于容器就能運(yùn)行的...
    小任務(wù)大夢(mèng)想閱讀 356評(píng)論 1 0
  • 認(rèn)識(shí)顧音的時(shí)候荒澡,她是夜貓子报辱,對(duì)于她來(lái)說(shuō)凌晨一點(diǎn)才是睡覺(jué)時(shí)間。 后來(lái)慢慢熟悉以后单山,知道顧音有一個(gè)男朋友,她給我看過(guò)男...
    小益讀書(shū)閱讀 223評(píng)論 0 0