<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>

          Spring 如何從 IoC 容器中獲取對象?

          共 8037字,需瀏覽 17分鐘

           ·

          2021-03-04 20:27

          前情回顧

          前面幾篇文章主要分析了 Spring IoC 容器如何初始化,以及解析和注冊我們定義的 bean 信息。

          其中,「Spring 中的 IoC 容器」對 Spring 中的容器做了一個概述,「Spring IoC 容器初始化」和「Spring IoC 容器初始化(2)」分析了 Spring 如何初始化 IoC 容器,「Spring 是如何解析 <bean> 標簽的?」分析了 Spring 如何解析 <bean> 標簽及其子標簽,并注冊到 BeanFactory。

          主要流程如下:

          89734b9aaf7fb1cc60c2c44f5a5626fb.webp

          IoC 容器已經(jīng)建立,而且把我們定義的 bean 信息放入了容器,那么如何從容器中獲取對象呢?

          本文繼續(xù)分析。

          配置及測試代碼

          為便于查看,這里再貼一下 bean 配置文件和測試代碼。

          • 配置文件 application-ioc.xml
          <?xml?version="1.0"?encoding="UTF-8"?>
          <beans?xmlns="http://www.springframework.org/schema/beans"
          ???????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          ???????xsi:schemaLocation="http://www.springframework.org/schema/beans
          ???????http://www.springframework.org/schema/beans/spring-beans.xsd"
          >


          ????<bean?id="person"?class="com.jaxer.spring.ioc.Person">
          ????????<property?name="pet"?ref="dog"/>
          ????</bean>

          ????<bean?id="dog"?class="com.jaxer.spring.ioc.Dog">
          ????????<property?name="age"?value="1"/>
          ????????<property?name="owner"?ref="person"/>
          ????</bean>

          </beans>
          • 測試代碼
          public?class?IocTests?{
          ????@Test
          ????public?void?test01()?{
          ????????ApplicationContext?context?=?new?ClassPathXmlApplicationContext("application-ioc.xml");
          ????????System.out.println(context.getBean("person"));
          ????????System.out.println(context.getBean("dog"));
          ????}
          }

          /*
          ?*?輸出結(jié)果:
          ?*??Person{id=12,?name='Jack-12'}
          ?*??Dog{age=1}
          ?*/

          如何從容器獲取對象?

          從容器中獲取對象是通過 BeanFactory#getBean 方法,它有多個重載的方法,但最終都是通過

          AbstractBeanFactory#doGetBean 方法來實現(xiàn)的。doGetBean 方法代碼如下:

          public?abstract?class?AbstractBeanFactory?extends?FactoryBeanRegistrySupport?implements?ConfigurableBeanFactory?{
          ????//?...

          ????protected?<T>?T?doGetBean(
          ????????????String?name,?@Nullable?Class<T>?requiredType,?@Nullable?Object[]?args,?boolean?typeCheckOnly)

          ????????????throws?BeansException?
          {

          ????????String?beanName?=?transformedBeanName(name);
          ????????Object?bean;

          ????????//?從緩存中獲取單例?bean?對象
          ????????Object?sharedInstance?=?getSingleton(beanName);
          ????????if?(sharedInstance?!=?null?&&?args?==?null)?{
          ????????????//?...
          ????????????//?處理?FactoryBean?的場景
          ????????????bean?=?getObjectForBeanInstance(sharedInstance,?name,?beanName,?null);
          ????????}
          ????????
          ????????//?緩存中不存在?bean?對象
          ????????else?{
          ????????????if?(isPrototypeCurrentlyInCreation(beanName))?{
          ????????????????throw?new?BeanCurrentlyInCreationException(beanName);
          ????????????}

          ????????????//?bean?對象在父容器中,則從父容器中獲取?bean?對象
          ????????????BeanFactory?parentBeanFactory?=?getParentBeanFactory();
          ????????????if?(parentBeanFactory?!=?null?&&?!containsBeanDefinition(beanName))?{
          ????????????????//?Not?found?->?check?parent.
          ????????????????String?nameToLookup?=?originalBeanName(name);
          ????????????????if?(parentBeanFactory?instanceof?AbstractBeanFactory)?{
          ????????????????????return?((AbstractBeanFactory)?parentBeanFactory).doGetBean(
          ????????????????????????????nameToLookup,?requiredType,?args,?typeCheckOnly);
          ????????????????}
          ????????????????else?if?(args?!=?null)?{
          ????????????????????//?Delegation?to?parent?with?explicit?args.
          ????????????????????return?(T)?parentBeanFactory.getBean(nameToLookup,?args);
          ????????????????}
          ????????????????else?if?(requiredType?!=?null)?{
          ????????????????????//?No?args?->?delegate?to?standard?getBean?method.
          ????????????????????return?parentBeanFactory.getBean(nameToLookup,?requiredType);
          ????????????????}
          ????????????????else?{
          ????????????????????return?(T)?parentBeanFactory.getBean(nameToLookup);
          ????????????????}
          ????????????}

          ????????????//?是否只做類型檢查
          ????????????if?(!typeCheckOnly)?{
          ????????????????markBeanAsCreated(beanName);
          ????????????}

          ????????????try?{
          ????????????????//?獲取?BeanDefinition
          ????????????????RootBeanDefinition?mbd?=?getMergedLocalBeanDefinition(beanName);
          ????????????????checkMergedBeanDefinition(mbd,?beanName,?args);

          ????????????????//?獲取依賴的?bean?對象
          ????????????????//?若創(chuàng)建一個?bean?對象時依賴其他對象,則先創(chuàng)建被依賴對象
          ????????????????String[]?dependsOn?=?mbd.getDependsOn();
          ????????????????if?(dependsOn?!=?null)?{
          ????????????????????for?(String?dep?:?dependsOn)?{
          ????????????????????????if?(isDependent(beanName,?dep))?{
          ????????????????????????????//?...
          ????????????????????????}
          ????????????????????????registerDependentBean(dep,?beanName);
          ????????????????????????try?{
          ????????????????????????????getBean(dep);
          ????????????????????????}
          ????????????????????????catch?(NoSuchBeanDefinitionException?ex)?{
          ????????????????????????????//?...
          ????????????????????????}
          ????????????????????}
          ????????????????}

          ????????????????//?創(chuàng)建?scope?為?singleton(單例)的對象
          ????????????????if?(mbd.isSingleton())?{
          ????????????????????sharedInstance?=?getSingleton(beanName,?()?->?{
          ????????????????????????try?{
          ????????????????????????????return?createBean(beanName,?mbd,?args);
          ????????????????????????}
          ????????????????????????catch?(BeansException?ex)?{
          ????????????????????????????//?...
          ????????????????????????}
          ????????????????????});
          ????????????????????//?處理?FactoryBean?的場景
          ????????????????????bean?=?getObjectForBeanInstance(sharedInstance,?name,?beanName,?mbd);
          ????????????????}

          ????????????????//?創(chuàng)建?scope?為?prototype?的對象
          ????????????????else?if?(mbd.isPrototype())?{
          ????????????????????//?It's?a?prototype?->?create?a?new?instance.
          ????????????????????Object?prototypeInstance?=?null;
          ????????????????????try?{
          ????????????????????????beforePrototypeCreation(beanName);
          ????????????????????????prototypeInstance?=?createBean(beanName,?mbd,?args);
          ????????????????????}
          ????????????????????finally?{
          ????????????????????????afterPrototypeCreation(beanName);
          ????????????????????}
          ????????????????????//?處理?FactoryBean?的場景
          ????????????????????bean?=?getObjectForBeanInstance(prototypeInstance,?name,?beanName,?mbd);
          ????????????????}

          ????????????????//?創(chuàng)建其他類型對象
          ????????????????else?{
          ????????????????????String?scopeName?=?mbd.getScope();
          ????????????????????if?(!StringUtils.hasLength(scopeName))?{
          ????????????????????????throw?new?IllegalStateException("No?scope?name?defined?for?bean?′"?+?beanName?+?"'");
          ????????????????????}
          ????????????????????Scope?scope?=?this.scopes.get(scopeName);
          ????????????????????if?(scope?==?null)?{
          ????????????????????????throw?new?IllegalStateException("No?Scope?registered?for?scope?name?'"?+?scopeName?+?"'");
          ????????????????????}
          ????????????????????try?{
          ????????????????????????Object?scopedInstance?=?scope.get(beanName,?()?->?{
          ????????????????????????????beforePrototypeCreation(beanName);
          ????????????????????????????try?{
          ????????????????????????????????return?createBean(beanName,?mbd,?args);
          ????????????????????????????}
          ????????????????????????????finally?{
          ????????????????????????????????afterPrototypeCreation(beanName);
          ????????????????????????????}
          ????????????????????????});
          ????????????????????????//?處理?FactoryBean?的場景
          ????????????????????????bean?=?getObjectForBeanInstance(scopedInstance,?name,?beanName,?mbd);
          ????????????????????}
          ????????????????????catch?(IllegalStateException?ex)?{
          ????????????????????????//?...
          ????????????????????}
          ????????????????}
          ????????????}
          ????????????catch?(BeansException?ex)?{
          ????????????????cleanupAfterBeanCreationFailure(beanName);
          ????????????????throw?ex;
          ????????????}
          ????????}

          ????????//?類型檢查
          ????????if?(requiredType?!=?null?&&?!requiredType.isInstance(bean))?{
          ????????????try?{
          ????????????????T?convertedBean?=?getTypeConverter().convertIfNecessary(bean,?requiredType);
          ????????????????if?(convertedBean?==?null)?{
          ????????????????????throw?new?BeanNotOfRequiredTypeException(name,?requiredType,?bean.getClass());
          ????????????????}
          ????????????????return?convertedBean;
          ????????????}
          ????????????catch?(TypeMismatchException?ex)?{
          ????????????????//?...
          ????????????}
          ????????}
          ????????return?(T)?bean;
          ????}
          }

          獲取 bean 對象主要就是通過這個 doGetBean 方法實現(xiàn)的。

          該方法雖然看起來稍微有點長,但是呢,它內(nèi)部的實現(xiàn)更長、更復(fù)雜。不過也是有跡可循的,莫慌。

          本文先看下這個方法的整體流程,內(nèi)部邏輯后面再慢慢研究。先上流程圖:

          d628aefc99b66153cfef23a5ef3e74f3.webp

          代碼雖然有點長,但梳理下來其實也沒那么復(fù)雜了。

          這個方法主要做了什么呢?

          當(dāng)從容器中獲取 bean 對象時,首先從緩存中獲取。如果緩存中存在,處理 FactoryBean 的場景。

          BeanFactory 和 FactoryBean,這哥倆長得很像,也有個別面試題可能會問到。

          嗯……以后有機會單獨分析?

          如果緩存中沒有,先去父容器獲取,前面創(chuàng)建 BeanFactory 時可以指定 parent 參數(shù),就是那個。

          不在父容器中,若 bean 對象依賴了其他對象,則先創(chuàng)建被依賴的 bean 對象,再根據(jù) <bean> 標簽的 scope 屬性去創(chuàng)建相應(yīng)的 bean 對象。

          是不是有點像我們平時寫查詢接口時、先從緩存查詢,緩存中沒的話再查詢 DB?

          道理是一樣的,空間換時間。

          小結(jié)

          先整體,后細節(jié)。

          本文先從整體上分析了如何從 Spring IoC 容器中獲取 bean 對象,內(nèi)容不多,后文再詳細分解吧。

          休息會~

          瀏覽 31
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  国产视频在线播放 | 精品人妻一区二区三区奶水 | 高清无码在线免费观看 | 免费在线观看黄片 | 三年秘 无码一区二区三区 |