SpringBoot中Spring应用上下文的准备有哪些(spring boot,代码,源码分析,web开发)

时间:2024-05-04 11:25:20 作者 : 石家庄SEO 分类 : web开发
  • TAG :

SpringBoot中Spring应用上下文的准备有哪些,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

Spring应用上下文的准备

首先,通过图 4-4 来整体了解一下 prepareContext 的核心功能及流程。

SpringBoot中Spring应用上下文的准备有哪些

配合流程图,看一下 SpringApplication 中 prepareContext 方法源代码及功能注解。

privatevoidprepareContext(ConfigurableApplicationContextcontext,ConfigurableEnvironmentenvironment,SpringApplicationRunListenerslisteners,ApplicationArgumentsapplicationArguments,BannerprintedBanner){//没置上下文的配置环境context.setEnvironment(environment);//应用上下文后置处理postProcessApplicationContext(context);//在context刷新之前,ApplicationContextInitializer初始化contextapplyInitializers(context);//通知监听器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");//将sources中的Bean加载到context中load(context,sources.toArray(new0bject[0]));//遁知监听器context加载完成listeners.contextLoaded(context);}

通过流程图和具体代码可以看出,在该方法内完成了两步操作:应用上下文的准备和加载。

下面我们针对具体的源代码进行详细讲解。

应用上下文准备阶段

在上下文准备阶段,主要有 3 步操作:对 context 设 置 environment、应用上下文后置处理和 ApplicationContextlnitializer 初始化 context 操作。

首先是对 context 设置 environment,代码和业务操作都很简单。

publicvoidsetEnvironment(ConfigurableEnvironmentenvironment){//设置context的environmentsuper.setEnvironment(environment);//设置context的reader属性的conditionEvaluator属性this.readeer.settEnvironment(environment);//设置context的scanner属性的environment属性this.scanner.setEnvironment(environment);}

随 后 , 便 是 进 行 Spring 应 用 上 下 文 的 后置处理 , 这 一 步 是 通 过postProcessApplicationContext 方法来完成的。

protectedvoidpostProcessApplicationContext(ConfigurableApplicationConEextcontext){f(this.beanNameGenerator!=null){//如果beanNameGenerator为null,则将当前的beanNameGenerator按照默认名字进行注册context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATIONBEANNAMEGENERATOR,this.beanNameGenerator);esourceLoader为null时,则根据context的类型分别进行Resourceloader和CLassLoader的设置if(this.resourceLoader!=null){F(contextinstanceofGenericApplicationContext){((GenericApplicationContext)context).setResourceloader(this.resourceLoader);if(contextinstanceofDefaultResourceLoader){((DefaultResourceLoader)context).setClassLoader(this.resourceLoader.getClassLoader());//如果为true则获取并没置转换服务f(this.addConversionService){context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());}

postProcessApplicationContext 方 法 主 要 完 成 上 下 文 的 后 置 操 作 , 默 认 包 含beanNameGeneratorResourceL oader.ClassL oader 和 ConversionService 的设置。该方法可由子类覆盖实现,以添加更多的操作。

而在此阶段,beanNameGenerator 和 resourceL oader 都为 null,因此只操作了最后-一步的设置转换服务。

最后,在通知监听器 context 准备完成之前,通过 applylnitializers 方法对上下文进行初始化。

所使用的 ApplicationContextInitializer 正是我们在 SpringApplication 初始化阶段设置在itializers 变量中的值,只不过在通过 getlnitializers 方法获取时进行了去重和排序。

protectedvoidapplyInitializers(ConfigurableApplicationContextcontext){/获取ApplicationContextInitializer集合并遍历for(ApplicationContextInitializerinitializer:getInitializers()){//解析当前initializer.实现的ApplicationContextInitializer的泛型参数Class<?>requiredType=GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);1断言判断所需类似是否与context类型匹配Assert.isInstanceOf(requiredType,context,"Unabletocallinitializer.");//初始化contextinitializer.initialize(context);}}

完成以上操作之后,程序便调用 SpringApplicationRunListeners 的 contextPrepared 方法通知监听器,至此第一阶段的准备操作完成。

应用上下文加载阶段

应用上下文加载阶段包含以下步骤:打印日志和 Profile 的设置、设置是否允许覆盖注册、获取全部配置源、将配置源加载入上下文、通知监控器 contex 加载完成。

首先进入应用上下文加载阶段的操作为打印日志和 Profile 的设置,对此不展开讲解。随后,便是获得 ConfigurableL istableBeanFactory 并注册单例对象,注册的单例对象包含:

ApplicationArguments 和 Banner。 当 BeanFactory 为 DefaultL istableBeanFactory 时,进入设置是否允许覆盖注册的处理逻辑。

此处需注意的是,当进行了 ApplicationArguments 类单例对象的注册之后,也就意味着我们在使用 Spring 应用上下文的过程中可以通过依赖注入来使用该对象。

@ResourceprivateApplicationArgumentsapplicationArguments;

完成以.上操作后,便进入配置源信息的处理阶段,这一步通过 getAllSources 方法来对配置源信息进行合并操作。

publicSet<Object>getAllSources(){Set<0bject>allSources=newLinkedHashSet<>();if(!CollectionUtils.isEmpty(this.primarySources)){allSources.addAll(this.primarySources);if(!CollectionUtils.isEmpty(this.sources)){allSources.addAll(this.sources);}}

return Collections . unmodifiableSet(allSources); }以上操作逻辑很简单,如果 Set 集合中不存在 primarySources 配置源或 sources 配置源,则将其添加入 Set 中,同时将 Set 设置为不可修改,并返回。

前面章节已经提到,变量 primarySources 的值 来自 SpringApplication 的构造参数,变量sources 的值来自 setResources 方法。

当获得所有的配置源信息之后,通过 load 方法将配置源信息加载到上下文中,代码如下。

protectedvoidload(ApplicationContextcontext,Object[]sources){/日志打印BeanDefinitionLoaderloader=createBeanDefinitionLoader(getBeanDefinitionRegistry(context),sources);f(this.beanNameGenerator!=nu1l).loader.setBeanNameGenerator(this.beanNameGenerator);if(this.resourceLoader!=nu1l){loader.setResourceLoader(this.resourceLoader);if(this.environment!=null){loader.setEnvironment(this.environment);loader.load();}

该方法主要通过 BeanDefinitionL oader 来完成配置资源的加载操作。我们进一步查看方法createBeanDefinitionL oader 的源代码,会发现它最终调用了 BeanDefinitionL oader 的构造方法,并进行初始化操作。

BeanDefinitionLoader(BeanDefinitionRegistryregistry,Object...sources){this.sources=sources;this.annotatedReader=newAnnotatedBeanDefinitionReader(registry);this.xmlReader=newXmlBeanDefinitionReader(registry);if(isGroovyPresent())this.groovyReader=newGroovyBeanDefinitionReader(registry);}

通过 BeanDefinitionLoader 的构造方法我们可以看到 BeanDefinitionLoader 支持基于AnnotatedBeanDefinitionReaderXmlBeanDefinitionReader、GroovyBeanDefinitionReader等 多种类型的加载操作。

在执行完 BeanDefinitionL oader 的创建及基本属性设置之后,调用其 load方法,该方法最终执行以下代码。

privateintload(0bjectsource){Assert.notNull(source,"Sourcemustnotbenull");if(sourceinstanceofClass<?>){returnload((Class<?>)source);}if(sourceinstanceofResource)returnload((Resource)source);}if(sourceinstanceofPackage){returnload((Package)source);}if(sourceinstanceofCharSequence){returnload((CharSequence)source);thrownewIllegalArgumentException("Invalidsourcetype”+source.getClass());}

从以上代码可以看出,BeanDefinitionLoader 加载支持的范围包括:

Class、Resource、 Package 和 CharSequence 四种。 前面我们已经提到变量 sources的来源有 primarySources 配置源和 sources 配置源。变量 primarySources 在初始化时接收的类型为 Class,而变量 sources 通过 set(Set )方法接收的参数为 String 集合。

因此,在实际使用的过程中,Resource 和 Package 的判断分支始终无法进入执行阶段。

完成以上操作后,接下来执行 SpringApplicationRunListeners 的 contextL oaded 方法通知监听器上下文加载完成,至此整个 Spring 应用上下文的准备阶段完成。

关于SpringBoot中Spring应用上下文的准备有哪些问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

本文:SpringBoot中Spring应用上下文的准备有哪些的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:C++的IDE有哪些下一篇:

5 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18