好程式設計師Java培訓分享Spring Ioc的原理

好程式設計師發表於2020-11-20

   今天 好程式設計師 Java 培訓給大家介紹一下關於 SpringIoc 原理的詳解,首先 Ioc InversionofControl 。翻譯過來就是控制反轉,意思是物件之間的關係不再由傳統的程式來控制,而是由 spring 容器來統一控制這些物件建立、協調、銷燬,而物件只需要完成業務邏輯即可。

   IoC InversionofControl ,控制倒轉)這是 spring 的核心,貫穿始終。所謂 IoC ,對於 spring 框架來說,就是由 spring 來負責控制物件的生命週期和物件間的關係。舉個例子,我們是如何找女朋友的?常見的情況是,我們到處去看哪裡有長得漂亮身材又好的 mm ,然後打聽她們的興趣愛好、 qq 號、電話號…,想辦法認識她們,投其所好送其所好,然後嘿嘿…這個過程是複雜深奧的,我們必須自己設計和麵對每個環節。傳統的程式開發也是如此,在一個物件中,如果要使用另外的物件,就必須得到它(自己 new 一個,或者從 JNDI 中查詢一個),使用完之後還要將物件銷燬(比如 Connection 等),物件始終會和其他的介面或類藕合起來。

   IoC 的一個重點是在系統執行中,動態的向某個物件提供它所需要的其他物件。這一點是透過 DI DependencyInjection ,依賴注入)來實現的。比如物件 A 需要運算元據庫,以前我們總是要在 A 中自己編寫程式碼來獲得一個 Connection 物件,有了 spring 我們就只需要告訴 spring A 中需要一個 Connection ,至於這個 Connection 怎麼構造,何時構造, A 不需要知道。在系統執行時, spring 會在適當的時候製造一個 Connection ,然後像打針一樣,注射到 A 當中,這樣就完成了對各個物件之間關係的控制。 A 需要依賴 Connection 才能正常執行,而這個 Connection 是由 spring 注入到 A 中的,依賴注入的名字就這麼來的。那麼 DI 是如何實現的呢? Java1.3 之後一個重要特徵是反射( reflection ),它允許程式在執行的時候動態的生成物件、執行物件的方法、改變物件的屬性, spring 就是透過反射來實現注入的。

   下面來讓大家瞭解一下Spring 到底是怎麼執行的

 

public static void main(String[] args) {  

   ApplicationContext context = new FileSystemXmlApplicationContext(  

       "applicationContext.xml");  

   Animal animal = (Animal) context.getBean("animal");  

   animal.say();  

 }

 

這段程式碼你一定很熟悉吧,不過還是讓我們分析一下它吧,首先是applicationContext.xml

 

<bean id="animal" class="phz.springframework.test.Cat">  

   <property name="name" value="kitty" />  

</bean>

 

他有一個類phz.springframework.test.Cat

 

public class Cat implements Animal {  

 private String name;  

 public void say() {  

   System.out.println("I am " + name + "!");  

 }  

 public void setName(String name) {  

   this.name = name;  

 }  

}

 

實現了phz.springframework.test.Animal 介面

 

public interface Animal {  

  public void say();  

}

 

很明顯上面的程式碼輸出Iamkitty! 那麼到底 Spring 是如何做到的呢?接下來就讓我們自己寫個 Spring 來看看 Spring 到底是怎麼執行的吧!首先,我們定義一個 Bean 類,這個類用來存放一個 Bean 擁有的屬性

 

/* Bean Id */

  private String id;  

  /* Bean Class */

  private String type;  

  /* Bean Property */

  private Map<String, Object> properties = new HashMap<String, Object>();

 

一個Bean 包括 id,type, Properties

 

   接下來Spring 就開始載入我們的配置檔案了,將我們配置的資訊儲存在一個 HashMap 中, HashMap key 就是 Bean Id HasMap value 是這個 Bean ,只有這樣我們才能透過 context.getBean("animal") 這個方法獲得 Animal 這個類。我們都知道 Spirng 可以注入基本型別,而且可以注入像 List Map 這樣的型別,接下來就讓我們以 Map 為例看看 Spring 是怎麼儲存的吧

 

Map 配置可以像下面的

 

<bean id="test">  

    <property name="testMap">  

      <map>  

        <entry key="a">  

          <value>1</value>  

        </entry>  

        <entry key="b">  

          <value>2</value>  

        </entry>  

      </map>  

    </property>  

  </bean>

 

Spring 是怎樣儲存上面的配置呢?,程式碼如下:

 

(beanProperty.element("map") != null) {  

          Map<String, Object> propertiesMap = new HashMap<String, Object>();  

          Element propertiesListMap = (Element) beanProperty  

              .elements().get(0);  

          Iterator<?> propertiesIterator = propertiesListMap  

              .elements().iterator();  

          while (propertiesIterator.hasNext()) {  

            Element vet = (Element) propertiesIterator.next();  

            if (vet.getName().equals("entry")) {  

              String key = vet.attributeValue("key");  

              Iterator<?> valuesIterator = vet.elements()  

                  .iterator();  

              while (valuesIterator.hasNext()) {  

                Element value = (Element) valuesIterator.next();  

                if (value.getName().equals("value")) {  

                  propertiesMap.put(key, value.getText());  

                }  

                if (value.getName().equals("ref")) {  

                  propertiesMap.put(key, new String[] { value  

                      .attributeValue("bean") });  

                }  

              }  

            }  

          }  

          bean.getProperties().put(name, propertiesMap);  

        }

 

   接下來就進入最核心部分了,讓我們看看Spring 到底是怎麼依賴注入的吧,其實依賴注入的思想也很簡單,它是透過反射機制實現的,在例項化一個類時,它透過反射呼叫類中 set 方法將事先儲存在 HashMap 中的類屬性注入到類中。讓我們看看具體它是怎麼做的吧。首先例項化一個類,像這樣

 

public static Object newInstance(String className) {  

    Class<?> cls = null;  

    Object obj = null;  

    try {  

      cls = Class.forName(className);  

      obj = cls.newInstance();  

    } catch (ClassNotFoundException e) {  

      throw new RuntimeException(e);  

    } catch (InstantiationException e) {  

      throw new RuntimeException(e);  

    } catch (IllegalAccessException e) {  

      throw new RuntimeException(e);  

    }  

    return obj;  

  }

 

接著它將這個類的依賴注入進去,像這樣

 

public static void setProperty(Object obj, String name, String value) {  

    Class<? extends Object> clazz = obj.getClass();  

    try {  

      String methodName = returnSetMthodName(name);  

      Method[] ms = clazz.getMethods();  

      for (Method m : ms) {  

        if (m.getName().equals(methodName)) {  

          if (m.getParameterTypes().length == 1) {  

            Class<?> clazzParameterType = m.getParameterTypes()[0];  

            setFieldValue(clazzParameterType.getName(), value, m,  

                obj);  

            break;  

          }  

        }  

      }  

    } catch (SecurityException e) {  

      throw new RuntimeException(e);  

    } catch (IllegalArgumentException e) {  

      throw new RuntimeException(e);  

    } catch (IllegalAccessException e) {  

      throw new RuntimeException(e);  

    } catch (InvocationTargetException e) {  

      throw new RuntimeException(e);  

    }  

}

 

   最後它將這個類的例項返回給我們,我們就可以用了。我們還是以Map 為例看看它是怎麼做的,我寫的程式碼裡面是建立一個 HashMap 並把該 HashMap 注入到需要注入的類中,像這樣:

 

if (value instanceof Map) {  

        Iterator<?> entryIterator = ((Map<?, ?>) value).entrySet()  

            .iterator();  

        Map<String, Object> map = new HashMap<String, Object>();  

        while (entryIterator.hasNext()) {  

          Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next();  

          if (entryMap.getValue() instanceof String[]) {  

            map.put((String) entryMap.getKey(),  

                getBean(((String[]) entryMap.getValue())[0]));  

          }  

        }  

        BeanProcesser.setProperty(obj, property, map);  

      }


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913864/viewspace-2735467/,如需轉載,請註明出處,否則將追究法律責任。

相關文章