Spring应用上下文准备上一节我们完成了应用上下文的创建,SpringApplication继续通过prepareContext方法准备应用上下文。首先通过图4-4从整体上理解prepareContext的核心功能和流程。结合流程图,看看SpringApplication中prepareContext方法的源码和功能注解。privatevoidprepareContext(ConfigurableApplicationContextcontext,ConfigurableEnvironmentenvironment,SpringApplicationRunListenerslisteners,ApplicationArgumentsapplicationArguments,BannerprintedBanner){//没置上下文的配置环境context.setEnvironment(environment);//应用上下文后置处理postProcessApplicationContext(context);//在context刷新之前,ApplicationContextInitializer初始化contextapplyInitializers(context);//通知监听器上下文准备完成。上面方法是上下文准备阶段,下面是上下文加载阶段listeners.contextPrepared(context);//打印日志并启动Profileif(this.logStartupInfo)-logStartupInfo(context.getParent()==nu1l);logStartupProfileInfo(context);}//获取ConfigurableListableBeanFactory并注册单例对象ConfigurableListableBeanFactorybeanFactory=context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments",applicationArguments);if(printedBanner!=null){//注册打印日志对象beanFactory.registerSingleton("springBootBanner",printedBanner);if(beanFactoryinstanceofDefaultlistableBeanFactory){//不设置是否允许盖书((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);//获取所有配置源,包括primarySources和sourcesSet<0bject>sources=getAllSources();Assert.notEmpty(sources,"Sourcesmustnotbeempty");//设置sourcesinBean被加载到contextload(context,sources.toArray(new0bject[0]));//监听的listenercontext被加载listeners.contextLoaded(context);}从流程图和具体代码可以看出,在该方法内完成两步操作:应用上下文的准备和加载。接下来,我们将详细解释具体的源代码。应用上下文准备阶段在上下文准备阶段,主要有三个步骤:为上下文设置环境,对应用上下文进行后处理,用ApplicationContextInitializer初始化上下文操作。首先是给context设置环境,代码和业务操作都很简单。publicvoidsetEnvironment(ConfigurableEnvironmentenvironment){//设置context的环境super.setEnvironment(environment);//设置context的reader属性的conditionEvaluator属性this.reader.settEnvironment(environment);//设置context的环境属性上下文this.scanner的扫描仪属性。setEnvironment(environment);}随后进行Spring应用上下文的后处理,这一步是通过postProcessApplicationContext方法完成的。protectedvoidpostProcessApplicationContext(ConfigurableApplicationConEextcontext){f(this.beanNameGenerator!=null){//如果beanNameGenerator为null,则根据默认名称注册当前beanNameGeneratorcontext.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATIONBEANNAMEGENERATOR,this.beanerNamesource)时为null,根据context的类型分别设置Resourceloader和CLassLoader(DefaultResourceLoader)context).setClassLoader(this.resourceLoader.getClassLoader());//如果为true,获取并设置转换服务f(this.addConversionService){context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());}postProcessApplicationContext方法主要完成context的后置操作,包含beanNameGeneratorResourceLoader.ClassLoader和ConversionService默认设置。该方法可以被子类覆盖以添加更多操作。而这个阶段beanNameGenerator和resourceLoader都是null,所以只操作最后一步的设置转换服务。最后,在通知侦听器上下文准备就绪之前,通过applyInitializers方法初始化上下文。使用的ApplicationContextInitializer正是我们在SpringApplication初始化阶段在itializers变量中设置的值,只是在通过getlnitializers方法获取的时候进行了去重和排序。protectedvoidapplyInitializers(ConfigurableApplicationContextcontext){//获取ApplicationContextInitializer集合并遍历for(ApplicationContextInitializerinitializer:getInitializers()){//解析当前初始化器。Class>requiredType=GenericTypeResolver.resolveTypeArgument(text,initializer.initializer).class)实现的ApplicationContextInitializer的泛型参数;1Assert判断所需相似度是否匹配上下文类型Assert.isInstanceOf(requiredType,context,"Unabletocallinitializer.");//初始化contextinitializer.initialize(context);}}以上操作完成后,程序调用SpringApplicationRunListeners的contextPrepared方法通知监听器第一阶段的准备工作已经完成。应用上下文加载阶段应用上下文加载阶段包括以下步骤:打印log和Profile设置,设置是否允许覆盖注册,获取所有配置源,将配置源加载到上下文中,通知monitor上下文加载完成。进入应用上下文加载阶段的第一个操作就是打印log和设置profile,这里不再赘述。然后,获取ConfigurableListableBeanFactory并注册单例对象。注册的单例对象包括:ApplicationArguments和Banner。当BeanFactory为DefaultListableBeanFactory时,进入设置是否允许覆盖注册的处理逻辑。这里需要注意的是,当ApplicationArguments类单例对象被注册时,就意味着我们在使用Spring应用上下文的过程中可以通过依赖注入来使用该对象。@ResourceprivateApplicationArgumentsapplicationArguments;以上操作完成后,进入配置源信息处理阶段。这一步通过getAllSources方法合并配置源信息。publicSet
