從零開始造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)飛哥