<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringBoot運(yùn)行源碼分析:Spring應(yīng)用上下文準(zhǔn)備

          共 7114字,需瀏覽 15分鐘

           ·

          2022-05-10 13:09


          Spring應(yīng)用上下文的準(zhǔn)備

          我們?cè)谏弦还?jié)完成了應(yīng)用上下文的創(chuàng)建工作,SpringApplication 繼續(xù)通過(guò) prepareContext方法來(lái)進(jìn)行應(yīng)用上下文的準(zhǔn)備工作。首先,通過(guò)圖 4-4 來(lái)整體了解一下 prepareContext 的核心功能及流程。


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

          private void prepareContext(ConfigurableApplicationContext context,ConfigurableEnvironment
          environment,
          SpringApplicationRunL
          isteners
          listeners ,
          Applicat ionArguments applicat ionArguments, Bann
          er printedBanner)
          {
          //沒(méi)置上下文的配置環(huán)境
          context . setEnvironment (environment);
          //應(yīng)用上下文后置處理
          postProcessApplicationContext( context);//在 context 刷新之前,Appl icat ionContext Init
          ial izer 初始化 context
          applyInitializers(context)
          ;
          //通知監(jiān)聽(tīng)器 context 準(zhǔn)備完成,該方法以 上為上下文準(zhǔn)備階段,以下為上下文加載階段
          listeners . contextPrepared(context);//打印日志,啟動(dòng) Profile
          if (this . logStartupInfo)-
          logStartupInfo(context . getParent() == nu1l);
          logStartupProfileInfo( context);
          }
          //獲得 ConfigurableL istableBeanFactory 并炷冊(cè)單例對(duì)象
          ConfigurableL istableBeanFactory beanFactory = context . getBeanFactory();
          beanFactory. registerSingleton("springApplicat ionArguments", applicationAr
          guments);
          if (printedBanner != null) {
          //注冊(cè)打印日志對(duì)象
          beanF actory. registerSingleton("springBootBanner", printedBanner);
          if (beanFactory instanceof DefaultlistableBeanFactory) {
          //沒(méi)置是否允許覆蓋炷冊(cè)
          ((DefaultListableBeanFactory) beanFactory)
          . setAllowBeanDefinitionOverriding(this . allowBeanDefinitionOverriding);
          //獲取全部配置源,其中包含 primarySources 和 sources
          Set<0bject> sources = getAllSources();
          Assert . notEmpty(sources, "Sources must not be empty");
          //將 sources 中的 Bean 加載到 context 中
          load(context, sources . toArray(new 0bject[0]));
          //遁知監(jiān)聽(tīng)器 context 加載完成
          listeners . contextLoaded(context);
          }

          通過(guò)流程圖和具體代碼可以看出,在該方法內(nèi)完成了兩步操作:應(yīng)用上下文的準(zhǔn)備和加載。

          下面我們針對(duì)具體的源代碼進(jìn)行詳細(xì)講解。

          應(yīng)用上下文準(zhǔn)備階段

          在上下文準(zhǔn)備階段,主要有 3 步操作:對(duì) context 設(shè) 置 environment、應(yīng)用上下文后置處理和
          ApplicationContextlnitializer 初始化 context 操作。

          首先是對(duì) context 設(shè)置 environment,代碼和業(yè)務(wù)操作都很簡(jiǎn)單。

          public void setEnvironment (ConfigurableEnvironment environment) {
          //設(shè)置 context 的 environment
          super. setEnvi ronment( environment);
          //設(shè)置 context 的 reader 屬性的 conditionEvaluator 屬性 this.reade
          er. settEnvironment(environment) ;
          //設(shè)置 context 的 scanner 屬性的 environment 屬性
          this. scanner. setEnvi ronment ( envi ronment);
          }

          隨 后 , 便 是 進(jìn) 行 Spring 應(yīng) 用 上 下 文 的 后置處理 , 這 一 步 是 通 過(guò)
          postProcessApplicationContext 方法來(lái)完成的。

          protected void postProcessApplicat ionContext (ConfigurableApplicat ionConEext
          context)
          {
          f (this. beanNameGenerator != null) {
          // 如果 beanNameGenerator 為 null, 則將當(dāng)前的 beanNameGenerator 按照默認(rèn)名字進(jìn)
          行注冊(cè)
          context . getBeanFactory(). regi sterSingleton(
          Annotat ionConfigUtils .CONF IGURATION BEAN NAME GENERATOR,
          this . beanNameGenerator)
          ;
          esourceLoader 為 null 時(shí), 則根據(jù) context 的類(lèi)型分別進(jìn)行 Resourceloader 和 CL
          assLoader 的設(shè)置
          if (this .resourceLoader != null) {
          F (context instanceof GenericApplicationContext) {
          ((GenericApplicationContext) context) . setResourcel oader(this . resource
          Loader)
          ;
          if (context instanceof DefaultResourceLoader) {
          ( (DefaultResourceLoader) context)
          . setClassLoader(this.resourceLoader. getClassLoader());
          //如果為 true 則獲取并沒(méi)置轉(zhuǎn)換服務(wù)
          f (this .addConversionService) {
          context . getBeanFactory(). setConversionService(
          ApplicationConversionService . getSharedInstance());
          }


          postProcessApplicationContext 方 法 主 要 完 成 上 下 文 的 后 置 操 作 , 默 認(rèn) 包 含beanNameGeneratorResourceL oader.ClassL oader 和 ConversionService 的設(shè)置。該方法可由子類(lèi)覆蓋實(shí)現(xiàn),以添加更多的操作。

          而在此階段,beanNameGenerator 和 resourceL oader 都為 null,因此只操作了最后-一步的設(shè)置轉(zhuǎn)換服務(wù)。

          最后,在通知監(jiān)聽(tīng)器 context 準(zhǔn)備完成之前,通過(guò) applylnitializers 方法對(duì)上下文進(jìn)行初始化。

          所使用的
          ApplicationContextInitializer 正是我們?cè)?SpringApplication 初始化階段設(shè)置在itializers 變量中的值,只不過(guò)在通過(guò) getlnitializers 方法獲取時(shí)進(jìn)行了去重和排序。

          protected void applyInitializers(ConfigurableApplicat ionContext context) {
          /獲取 Appl icat ionContextInitializer 集合并遍歷
          for (ApplicationContextInitializer initializer : getInitializers()) {
          //解析當(dāng)前 initial izer.實(shí)現(xiàn)的 Appl icat ionContextInitializer 的泛型參數(shù)
          Class requiredType = GenericTypeResolver . resolveTypeArgument(
          initializer . getClass(), ApplicationContextInitializer.class);
          1 斷言判斷所需類(lèi)似是否與 context 類(lèi)型匹配
          Assert. isInstanceOf(requiredType, context, "Unable to call initialize
          r.");
          // 初始化 context
          initializer. initialize(context);
          }
          }

          完成以上操作之后,程序便調(diào)用
          SpringApplicationRunListeners 的 contextPrepared 方法通知監(jiān)聽(tīng)器,至此第一階段的準(zhǔn)備操作完成。

          應(yīng)用上下文加載階段

          應(yīng)用上下文加載階段包含以下步驟:打印日志和 Profile 的設(shè)置、設(shè)置是否允許覆蓋注冊(cè)、獲取全部配置源、將配置源加載入上下文、通知監(jiān)控器 contex 加載完成。

          首先進(jìn)入應(yīng)用上下文加載階段的操作為打印日志和 Profile 的設(shè)置,對(duì)此不展開(kāi)講解。隨后,便是獲得 ConfigurableL istableBeanFactory 并注冊(cè)單例對(duì)象,注冊(cè)的單例對(duì)象包含:

          ApplicationArguments 和 Banner。當(dāng) BeanFactory 為 DefaultL istableBeanFactory 時(shí),進(jìn)入設(shè)置是否允許覆蓋注冊(cè)的處理邏輯。

          此處需注意的是,當(dāng)進(jìn)行了 ApplicationArguments 類(lèi)單例對(duì)象的注冊(cè)之后,也就意味著我們?cè)谑褂?Spring 應(yīng)用上下文的過(guò)程中可以通過(guò)依賴(lài)注入來(lái)使用該對(duì)象。

          @Resource
          private ApplicationArguments applicat ionArguments;

          完成以.上操作后,便進(jìn)入配置源信息的處理階段,這一步通過(guò) getAllSources 方法來(lái)對(duì)配置源信息進(jìn)行合并操作。

          public Set getAllSources() {
          Set<0bject> allSources = new LinkedHashSet<>();
          if (!CollectionUtils.isEmpty(this . primarySources)) {
          allSources.addAll(this.primarySources);
          if (!CollectionUtils . isEmpty(this. sources)) {
          allSources. addAll(this.sources);
          }
          }

          return Collections . unmodifiableSet(allSources); }以上操作邏輯很簡(jiǎn)單,如果 Set 集合中不存在 primarySources 配置源或 sources 配置源,則將其添加入 Set 中,同時(shí)將 Set 設(shè)置為不可修改,并返回。

          前面章節(jié)已經(jīng)提到,變量 primarySources 的值 來(lái)自 SpringApplication 的構(gòu)造參數(shù),變量sources 的值來(lái)自 setResources 方法。

          當(dāng)獲得所有的配置源信息之后,通過(guò) load 方法將配置源信息加載到上下文中,代碼如下。

          protected void load(ApplicationContext context, Object[] sources) {
          /日志打印
          BeanDefinitionLoader loader = 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();
          }

          該方法主要通過(guò) BeanDefinitionL oader 來(lái)完成配置資源的加載操作。我們進(jìn)一步查看方法createBeanDefinitionL oader 的源代碼,會(huì)發(fā)現(xiàn)它最終調(diào)用了 BeanDefinitionL oader 的構(gòu)造方法,并進(jìn)行初始化操作。

          BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
          this. sources = sources;
          this . annotatedReader = new AnnotatedBeanDefinitionReader(registry);
          this . xmlReader = new XmlBeanDefinitionReader(registry);
          if (isGroovyPresent())
          this. groovyReader = new GroovyBeanDefinitionReader(registry);
          }

          通過(guò) BeanDefinitionLoader 的構(gòu)造方法我們可以看到 BeanDefinitionLoader 支持基于
          AnnotatedBeanDefinitionReaderXmlBeanDefinitionReader、GroovyBeanDefinitionReader等 多種類(lèi)型的加載操作。

          在執(zhí)行完 BeanDefinitionL oader 的創(chuàng)建及基本屬性設(shè)置之后,調(diào)用其 load方法,該方法最終執(zhí)行以下代碼。

          private int load(0bject source) {
          Assert. notNull(source, "Source must not be null");
          if (source instanceof Class) {
          return load((Class) source);
          }if (source instanceof Resource)
          return load( (Resource) source);
          }
          if (source instanceof Package) {
          return load( (Package) source);
          }
          if (source instanceof CharSequence) {
          return load( (CharSequence) source);
          throw new IllegalArgumentException("Invalid source type ”+ source. getC
          lass());}

          從以上代碼可以看出,BeanDefinitionLoader 加載支持的范圍包括:

          Class、Resource、 Package 和 CharSequence 四種。前面我們已經(jīng)提到變量 sources的來(lái)源有 primarySources 配置源和 sources 配置源。變量 primarySources 在初始化時(shí)接收的類(lèi)型為 Class,而變量 sources 通過(guò) set(Set )方法接收的參數(shù)為 String 集合。

          因此,在實(shí)際使用的過(guò)程中,Resource 和 Package 的判斷分支始終無(wú)法進(jìn)入執(zhí)行階段。

          完成以上操作后,接下來(lái)執(zhí)行
          SpringApplicationRunListeners 的 contextL oaded 方法通知監(jiān)聽(tīng)器上下文加載完成,至此整個(gè) Spring 應(yīng)用上下文的準(zhǔn)備階段完成。

          本文給大家講解的內(nèi)容是Spring應(yīng)用上下文準(zhǔn)備

          1. 下篇文章給大家講解的是Spring應(yīng)用上下文的刷新、調(diào)用 ApplicationRunner 和 CommandLineRunner;

          2. 覺(jué)得文章不錯(cuò)的朋友可以轉(zhuǎn)發(fā)此文關(guān)注小編;

          3. 感謝大家的支持!


          本文就是愿天堂沒(méi)有BUG給大家分享的內(nèi)容,大家有收獲的話(huà)可以分享下,想學(xué)習(xí)更多的話(huà)可以到微信公眾號(hào)里找我,我等你哦。

          瀏覽 57
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    国产永久免费无遮挡被操裸体美女 | 狠狠狠狠狠狠狠 | 超碰最新在线观看 | 91免费片 | 人人看天天操 |