1. 程式人生 > >編碼剖析Spring管理Bean的原理

編碼剖析Spring管理Bean的原理

bean對象 控制 eva BE 並且 return select lec exception

在Spring的第一個案例中,我們已經知道了怎麽將bean交給Spring容器進行管理,並且明白了怎麽從Spring容器中獲取bean。那我們就有一個疑問了:Spring是如何創建並管理bean的呢?現在我們就來編碼剖析Spring管理Bean的原理。
本文是在Spring的第一個案例的基礎上展開的。
我們要使用dom4j讀取Sping的配置文件——beans.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="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean> </beans>

那麽就需要將dom4j所需的jar包導入該項目中。dom4j所需的jar包為:

  • dom4j-1.6.1.jar
  • jaxen-1.1-beta-6.jar

dom4j讀取到諸如

<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean>

這樣的內容時,務必需要將讀取到的bean的信息存到一個JavaBean對象中。於是我們可在junit.test包下創建這樣一個JavaBean——BeanDefinition.java,其代碼為:

/**
 * 將讀取到的bean的信息存到一個JavaBean對象中
 *
 */
public class BeanDefinition {
    
private String id; private String className; public BeanDefinition(String id, String className) { this.id = id; this.className = className; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } }

接下來我們就創建一個傳智播客版的Spring容器來模擬Spring容器。在junit.test下新建一個類——ItcastClassPathXMLApplicationContext.java,其代碼如下:

/**
 * 傳智播客版Spring容器
 *
 */
public class ItcastClassPathXMLApplicationContext {
    private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();
    private Map<String, Object> sigletons = new HashMap<String, Object>();

    public ItcastClassPathXMLApplicationContext(String filename) {
        this.readXML(filename);
        this.instanceBeans();
    }

    /**
     * 完成bean的實例化
     */
    private void instanceBeans() {
        for (BeanDefinition beanDefinition : beanDefines) {
            try {
                if (beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim())) {
                    sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 讀取XML配置文件
     * @param filename
     */
    private void readXML(String filename) {
        SAXReader saxReader = new SAXReader();
        Document document = null;
        try {
            URL xmlpath = this.getClass().getClassLoader().getResource(filename);
            document = saxReader.read(xmlpath);
            Map<String, String> nsMap = new HashMap<String, String>();
            nsMap.put("ns", "http://www.springframework.org/schema/beans"); // 加入命名空間
            XPath xsub = document.createXPath("//ns:beans/ns:bean"); // 創建beans/bean查詢路徑
            xsub.setNamespaceURIs(nsMap); // 設置命名空間
            List<Element> beans = xsub.selectNodes(document); // 獲取文檔下所有bean節點
            for (Element element : beans) {
                String id = element.attributeValue("id"); // 獲取id屬性值
                String clazz = element.attributeValue("class"); // 獲取class屬性值
                BeanDefinition beanDefine = new BeanDefinition(id, clazz);
                beanDefines.add(beanDefine);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 獲取bean實例
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) {
        return this.sigletons.get(beanName);
    }
}

這樣,傳智播客版的Spring容器就創建出來了。接下來我們就要測試傳智播客版的Spring容器是否能夠取得bean實例,只須修改SpringTest類的代碼為:

public class SpringTest {

    @Test
    public void test() {
        // ApplicationContext是接口
        // ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); // 實例化Spring容器
        // PersonService personService = (PersonService) ctx.getBean("personService"); // 從Spring容器取得bean
        // personService.save();

        ItcastClassPathXMLApplicationContext ctx = new ItcastClassPathXMLApplicationContext("beans.xml"); // 實例化Spring容器
        PersonService personService = (PersonService) ctx.getBean("personService"); // 從Spring容器取得bean
        personService.save();
    }

}

測試test()方法,Eclipse控制臺打印如下:
技術分享圖片

通過編寫代碼剖析Spring管理Bean的原理,我們就能深刻理解Spring內部到底是如何創建並管理bean實例的.

編碼剖析Spring管理Bean的原理