1. 程式人生 > >Spring IOC 學習筆記

Spring IOC 學習筆記

1、IoC思想 .

如何理解好Ioc呢?理解好Ioc的關鍵是要明確“誰控制誰,控制什麼,為何是反轉(有反轉就應該有正轉了),哪些方面反轉了”,那我們來深入分析一下:

●誰控制誰,控制什麼:傳統Java SE程式設計,我們直接在物件內部通過new進行建立物件,是程式主動去建立依賴物件;而IoC是有專門一個容器來建立這些物件,即由Ioc容器來控制物件的建立;誰控制誰?當然是IoC 容器控制了物件;控制什麼?那就是主要控制了外部資源獲取(不只是物件包括比如檔案等)。

●為何是反轉,哪些方面反轉了:有反轉就有正轉,傳統應用程式是由我們自己在物件中主動控制去直接獲取依賴物件,也就是正轉;而反轉則是由容器來幫忙建立及注入依賴物件;為何是反轉?因為由容器幫我們查詢及注入依賴物件,物件只是被動的接受依賴物件,所以是反轉;哪些方面反轉了?依賴物件的獲取被反轉了。 

理解DI的關鍵是:“誰依賴誰,為什麼需要依賴,誰注入誰,注入了什麼”,那我們來深入分析一下:

●誰依賴於誰:當然是應用程式依賴於IoC容器;

●為什麼需要依賴:應用程式需要IoC容器來提供物件需要的外部資源;

●誰注入誰:很明顯是IoC容器注入應用程式某個物件,應用程式依賴的物件;

●注入了什麼:就是注入某個物件所需要的外部資源(包括物件、資源、常量資料)

2、Spring初始化IoC容器的過程。

Spring 先載入beanDefinition到beanFactory中(用map儲存,key是beanName),beanDefinition是bean資料結構的一種對映。然後處理beanDefiniton(怎麼處理?)。完成bean註冊beanFactory中。在完成之前,先預例項化那些單例bean(lazy-init為false的)。

3、IoC容器的初始化包括BeanDefinition的Resource定位,載入和註冊。

(1)、定位:使用BeanDefinitionReader讀取資源applicationContext.xml檔案。

(2)、載入:讀取xml檔案中定義的Bean,然後表示成IoC容器內部的資料結構beanDefinition,包括xml中定義的和component_scan自動掃描到的帶有@service,@controller,@dao註解的bean。

疑問?spring是用哪個類解析xml中定義的component_scan路徑並scan所有bean的?

(3)、註冊:向IoC容器註冊這些BeanDefinition的過程。通過呼叫BeanDefinitionRegistry介面的實現來完成的,這個註冊是把載入過程解析到的BeanDefinition向IoC容器進行註冊。在IoC內部是通過一個HashMap來儲存這些BeanDefinition資料的

4、IoC容器的初始化不包含Bean依賴注入的實現,一般依賴注入發生在應用第一次向容器通過getBean索取Bean時。但可以根據BeanDefinition資訊中的Lazyinit屬性來設定。即為false時,在容器初始化完成後,就預例項化。

    預例項化時,先從父類容器中判斷是否有快取,父類沒有從子類容器判斷是否有快取。

public void preInstantiateSingletons() throws BeansException {
          if (this.logger.isInfoEnabled()) {
              this.logger.info("Pre-instantiating singletons in " + this);
          }
          synchronized (this.beanDefinitionMap) {
              // Iterate over a copy to allow for init methods which in turn register new bean definitions.
              // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
              List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
              for (String beanName : beanNames) {
                   RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);//父類中獲取。
                   if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                        if (isFactoryBean(beanName)) {
                             final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                             boolean isEagerInit;
                             if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                                  isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                                      public Boolean run() {
                                           return ((SmartFactoryBean<?>) factory).isEagerInit();
                                      }
                                  }, getAccessControlContext());
                             }
                             else {
                                  isEagerInit = (factory instanceof SmartFactoryBean &&
                                           ((SmartFactoryBean<?>) factory).isEagerInit());
                             }
                             if (isEagerInit) {
                                  getBean(beanName);
                             }
                        }
                        else {
                             getBean(beanName);
                        }
                   }
              }
          }
     }

 

5、Spring IoC對於不同scope的物件是怎麼管理的?

    如果是single模式,那麼直接取容器中的例項,那如果是原型模式,是每次getBean的時候,建立新例項嗎?//TODO

6、為什麼用Spring IoC而不是用工廠模式?

     使用工廠模式時,呼叫者仍然需要定位到工廠,使呼叫者和工廠耦合到一起。需要呼叫被呼叫者時直接IoC依賴注入。

7、幾種注入的不同@Resource,@Autowired,@Qualier?

TODO

8、IOC的注入方式?

參見這裡》Spring常用的三種注入方式  建構函式注入,Setter注入,基於註解的注入

 

參考:

Spring:原始碼解讀Spring IOC原理

淺談對Spring IOC以及DI的理解