從零開始造Spring01---BeanFactory的學習

前言

這是學習劉老師的《從零開始造Spring》的第一篇學習筆記。
主要分為兩大塊 :
一、解析xml文件,初始化BeanDefinition,
二、生成Bean的實例對象
第一堂課比較簡單,我們首先從測試用例出發(fā)

測試用例

    @Test
    public void testGetBean() {
        // 解析xml文件
        reader.loadBeanDefinitions(new ClassPathResource("petstore-v1.xml"));
        // 獲得BeanDefinition
        BeanDefinition bd = factory.getBeanDefinition("petStore");

        assertTrue(bd.isSingleton());

        assertFalse(bd.isPrototype());

        assertEquals(BeanDefinition.SCOPE_DEFAULT,bd.getScope());

        assertEquals("org.litespring.service.v1.PetStoreService",bd.getBeanClassName());

        PetStoreService petStore = (PetStoreService)factory.getBean("petStore");

        assertNotNull(petStore);

        PetStoreService petStore1 = (PetStoreService)factory.getBean("petStore");

        assertTrue(petStore.equals(petStore1));
    }

解析xml 文件

我們是通過XmlBeanDefinitionReader 來解析xml 文件的。采用dom4j的方式解析。核心代碼如下:

public void loadBeanDefinitions(Resource resource){
        InputStream is = null;
        try{            
            is = resource.getInputStream();
            SAXReader reader = new SAXReader();
            Document doc = reader.read(is);

            Element root = doc.getRootElement(); //<beans>
            Iterator<Element> iter = root.elementIterator();
            while(iter.hasNext()){
                Element ele = (Element)iter.next();
                String id = ele.attributeValue(ID_ATTRIBUTE);
                String beanClassName = ele.attributeValue(CLASS_ATTRIBUTE);
                BeanDefinition bd = new GenericBeanDefinition(id,beanClassName);
                if (ele.attribute(SCOPE_ATTRIBUTE)!=null) {                 
                    bd.setScope(ele.attributeValue(SCOPE_ATTRIBUTE));                   
                }
                this.registry.registerBeanDefinition(id, bd);
            }
        } catch (Exception e) {     
            throw new BeanDefinitionStoreException("IOException parsing XML document from " + resource.getDescription(),e);
        }finally{
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {                   
                    e.printStackTrace();
                }
            }
        }

    }

注意: Resource類主要是用來獲取xml 的文件流,它有兩個實現(xiàn)類這里寫ClassPathResource 以及FileSystemResource ,第一個實現(xiàn)類主要是獲取類路徑下的文件,也就是說該xml文件在項目中。第二個實現(xiàn)類主要是用于獲取指定路徑下的文件。該文件可能不在項目中。

public interface Resource {
    public InputStream getInputStream() throws IOException;
    public String getDescription();
}

生成Bean的實例

首先,傳入getBean方法傳入beanID,在該方法中 首先拿到BeanDefinition,然后,根據(jù)beanClassName 字段通過反射的方式生成對應的bean 實例。
核心代碼如下:

    public Object getBean(String beanID) {
        BeanDefinition bd = this.getBeanDefinition(beanID);
        if(bd == null){
            return null;
        }
        //bd是單例
        if(bd.isSingleton()){
            Object bean = this.getSingleton(beanID);
            if(bean == null){
                bean = createBean(bd);
                this.registerSingleton(beanID, bean);
            }
            return bean;
        } 
        return createBean(bd);
    }
    private Object createBean(BeanDefinition bd) {
        ClassLoader cl = this.getBeanClassLoader();
        String beanClassName = bd.getBeanClassName();
        try {
            Class<?> clz = cl.loadClass(beanClassName);
            return clz.newInstance();
        } catch (Exception e) {         
            throw new BeanCreationException("create bean for "+ beanClassName +" failed",e);
        }   
    }

其中,DefaultSingletonBeanRegistry 類中定義了一個ConcurrentHashMap,將生成bean實例放在該Map中,在調(diào)用registerSingleton方法時,首先會根據(jù)beanName檢查是否已存在實例,如果存在在拋出異常。否則,將新生成的實例放入該Map中。

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

    public void registerSingleton(String beanName, Object singletonObject) {

        Assert.notNull(beanName, "'beanName' must not be null");

        Object oldObject = this.singletonObjects.get(beanName);
        if (oldObject != null) {
            throw new IllegalStateException("Could not register object [" + singletonObject +
                    "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
        }
        this.singletonObjects.put(beanName, singletonObject);

    }

    public Object getSingleton(String beanName) {

        return this.singletonObjects.get(beanName);
    }

源代碼:劉老師的源碼地址


作者:碼農(nóng)飛哥

微信公眾號:碼農(nóng)飛哥