菜鳥學SSH(十三)——Spring容器IOC解析及簡單實現

劉水鏡發表於2014-06-30

最近一段時間,“容器”兩個字一直縈繞在我的耳邊,甚至是吃飯、睡覺的時候都在我腦子裡蹦來蹦去的。隨著這些天一次次的交流、討論,對於容器的理解也逐漸加深。理論上的東西終歸要落實到實踐,今天就藉助Spring容器實現原理,簡單說說吧。

簡單的說,Spring就是通過工廠+反射將我們的bean放到它的容器中的,當我們想用某個bean的時候,只需要呼叫getBean("beanID")方法。


原理簡單介紹:

Spring容器的原理,其實就是通過解析xml檔案,或取到使用者配置的bean,然後通過反射將這些bean挨個放到集合中,然後對外提供一個getBean()方法,以便我們獲得這些bean。下面是一段簡單的模擬程式碼:

 

package com.tgb.spring.factory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;

public class ClassPathXmlApplicationContext implements BeanFactory  {
    
    //容器的核心,用來存放注入的Bean
    private Map<String, Object> container = new HashMap<String, Object>();
    
    //解析xml檔案,通過反射將配置的bean放到container中
    public ClassPathXmlApplicationContext(String fileName) throws Exception{
        SAXBuilder sb = new SAXBuilder();
        Document doc = sb.build(this.getClass().getClassLoader().getResourceAsStream(fileName));
        Element root = doc.getRootElement();
        List list = XPath.selectNodes(root, "/beans/bean");
          
        //掃描配置檔案中的bean
        for (int i = 0; i < list.size(); i++) {               
           Element bean = (Element) list.get(i);
           String id = bean.getAttributeValue("id");
           String clazz = bean.getAttributeValue("class");
           Object o = Class.forName(clazz).newInstance();
           container.put(id, o);
          }
    }
    
    @Override
    public Object getBean(String id) {        
        return container.get(id);
    }

}

 

 

首先宣告一個存放bean的Map,然後通過jdom解析配置檔案,迴圈遍歷所有的<bean>節點,並通過反射將它們放到我們之前宣告的Map中。然後提供一個getBean()的方法,讓我們可以通過bean的Id來找到我們想要的bean。


下面是一個簡單的xml配置檔案:

 

<?xml version="1.0" encoding="UTF-8"?>
<beans>

  <bean id="E" class="com.tgb.spring.factory.England" />
  
  <bean id="S" class="com.tgb.spring.factory.Spain" />
  
  <bean id="P" class="com.tgb.spring.factory.Portugal" />

</beans>

 



 

客戶端通過呼叫前面的ClassPathXmlApplicationContext,來載入上面的配置檔案,然後就可以通過Id來獲得我們需要的bean了:

 

package com.tgb.spring.factory;

public class Test {

    public static void main(String[] args) throws Exception {
        
        //載入配置檔案
        BeanFactory f = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        //英格蘭
        Object oe = f.getBean("E");
        Team e = (Team)oe;
        e.say();
        
        //西班牙
        Object os = f.getBean("S");
        Team s = (Team)os;
        s.say();
        
        //葡萄牙
        Object op = f.getBean("P");
        Team p = (Team)op;
        p.say();
    }

}

 


輸出結果:

 

England :我們是歐洲的中國隊,不在乎這次小組沒出線...
Spain   :我們是兩屆歐洲盃冠軍、一屆世界盃冠軍!
Portugal:我們的C羅一個頂十個!

 


其他程式碼:

 

//工廠介面
package com.tgb.spring.factory;

public interface BeanFactory {
    Object getBean(String id);
}

//Team介面
package com.tgb.spring.factory;

public interface Team {
    void say();
}

//英格蘭
package com.tgb.spring.factory;

public class England implements Team{
    
    public void say() {
        System.out.println("England:我們是歐洲的中國隊,不在乎這次小組沒出線...");
    }
}

//西班牙
package com.tgb.spring.factory;

public class Spain implements Team{

    @Override
    public void say() {
        System.out.println("Spain:我們是兩屆歐洲盃冠軍、一屆世界盃冠軍!");
    }
    
}

//葡萄牙
package com.tgb.spring.factory;

public class Portugal implements Team {

    @Override
    public void say() {
        System.out.println("Portugal:我們的C羅一個頂十個!");
    }

}

 


以上內容是對Spring的一個簡單模擬,當然Spring遠比這個要複雜的多,也強大的多,而且獲取bean的方式也不止通過工廠這一種。這裡只是做一個粗略的Demo說說自己對容器的簡單理解,向Spring致敬。例子簡陋,表達粗糙,歡迎拍磚交流。

 




相關文章