源代碼分析,是一件既痛苦又快樂的事情,看別人寫的代碼是通過的,但當你能夠看明白的時候,相信快樂也會隨之而來,為了減少痛苦,更快的帶來快樂,在這里希望通過這篇文章對覺得困難的朋友有一個幫助。
本文以spring框架的XmlBeanFactory為入手點進行分析,希望能夠以盡量簡潔明了的方式給予有需要的朋友一定的幫助。
首先來打開該類的代碼,我們將看到如下代碼:
以下內容為程序代碼:
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException { this(resource, null); }
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); }
}
|
這個類的代碼很簡單,一個成員對象加兩個構造函數,從這里我們可以看出,最重要的地方在于最后一個構造函數:
以下內容為程序代碼:
super(parentBeanFactory); this.reader.loadBeanDefinitions(resource);
|
第一句就是將父親工廠交給父類的構造函數,實際上最后也就是把父工廠保存到類的parentBeanFactory成員對象中,這個對象是在AbstractBeanFactory抽象類中定義的,而這個父工廠也會一直傳遞到該抽象類進行保存。第二句就是整個類中最重要的地方了,顧名思義,它的目的是通過XmlBeanDefinitionReader這個XML的Reader從資源resource中(也就是你的配置文件)讀取bean的定義。接下來我們打開XmlBeanDefinitionReader的loadBeanDefinitions方法,我們可看到在這個方法里代碼就一行,調用了一個同名不同參的方法,而參數是EncodedResource的一個實例,這個類實際上是Resource的一個包裝類,用來保存資源的Encode的,那接下來我們再看被調用的loadBeanDefinitions方法,這個方法里最主要的部分就是:
以下內容為程序代碼:
InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
|
這里的目的是將資源包裝成一個InputSource,連同Resource作為參數傳遞到doLoadBeanDefinitions方法
[code]
DocumentBuilderFactory factory = createDocumentBuilderFactory();
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP implementation [" + factory + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory);
Document doc = builder.parse(inputSource);
return registerBeanDefinitions(doc, resource);
[/code]
這個方法的目的一目了然,就是為了將資源解釋成為Document對象,然后調用registerBeanDefinitions方法,這里不做詳細解釋,不了解的話請去看看關于JAXP的介紹。接下來我們打開registerBeanDefinitions方法:
以下內容為程序代碼:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeansException { XmlBeanDefinitionParser parser = (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass); return parser.registerBeanDefinitions(this, doc, resource); }
|
這里創建了一個XmlBeanDefinitionParser接口的實現,這個接口的具體類是DefaultXmlBeanDefinitionParser,這個接口很簡單,只有registerBeanDefinitions一個方法,這個方法的作用也很明了,就是用來注冊Bean的定義的,所以說類和方法的名字一定要起得有意義,這樣可以讓人一看就大概了解其作用,減少了很多閱讀代碼的痛苦。廢話不多說,我們打開DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,這個類就是解釋XML配置文件的核心類了,打開registerBeanDefinitions方法后我們看到如下代碼:
以下內容為程序代碼:
public int registerBeanDefinitions(BeanDefinitionReader reader, Document doc, Resource resource) throws BeanDefinitionStoreException {
this.beanDefinitionReader = reader; this.resource = resource;
logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); //初始化根元素 initDefaults(root); if (logger.isDebugEnabled()) { logger.debug("Default lazy init '" + getDefaultLazyInit() + "'"); logger.debug("Default autowire '" + getDefaultAutowire() + "'"); logger.debug("Default dependency check '" + getDefaultDependencyCheck() + "'"); }
preProcessXml(root);//一個空方法用于擴展 int beanDefinitionCount = parseBeanDefinitions(root);//解釋配置的主要方法 if (logger.isDebugEnabled()) { logger.debug("Found " + beanDefinitionCount + " <bean> elements in " + resource); } postProcessXml(root); //一個空方法用于擴展
return beanDefinitionCount; }
|
在這個方法當中,主要用于解釋定義的有兩個方法,一個是initDefaults,一個是parseBeanDefinitions,第一個方法是用來解釋根元素的屬性的,例如lazy-init, autowire等,而parseBeanDefinitions就是用來解釋具體的bean定義了,方法代碼如下:
以下內容為程序代碼:
protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException { NodeList nl = root.getChildNodes(); int beanDefinitionCount = 0; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (IMPORT_ELEMENT.equals(node.getNodeName())) { importBeanDefinitionResource(ele); } else if (ALIAS_ELEMENT.equals(node.getNodeName())) { String name = ele.getAttribute(NAME_ATTRIBUTE); String alias = ele.getAttribute(ALIAS_ATTRIBUTE); this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias); } else if (BEAN_ELEMENT.equals(node.getNodeName())) { beanDefinitionCount++; BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false); BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory()); } } } return beanDefinitionCount; }
|
其他標簽具體如何被解釋這里就不多說,相信大家也能看得懂,這里主要講一下解釋bean的的處理,我們注意以下代碼:
以下內容為程序代碼:
else if (BEAN_ELEMENT.equals(node.getNodeName())) { beanDefinitionCount++; BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false); BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory()); }
|
這里是當碰到一個bean標簽的時候所進行的處理,也既是對bean的定義進行解釋,可以看到parseBeanDefinitionElement方法的第一個參數就是bean則個元素,第二個參數表示該bean是否為內置的bean,從這里進行解釋的bean都不可能是內置的,所以這里直接以false為參數,打開parseBeanDefinitionElement方法,就可以看到這個方法里就是對bean的內部的解釋,也很簡單,也不多講了,呵呵(下班時間已經到了,所以就寫這么多了,基本的流程也就這樣,沒什么特別難的地方。),對了,最后還有一點就是解釋完后,bean的定義將會被保存到beanFactory中,這個beanFactory的實現就是XmlBeanFactory了,該beanFactory是在new的時候被傳遞到reader中的,就是該類中以下這行代碼:
以下內容為程序代碼:
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
|
好了,就這么多了,本文只作為參考,只講解了如何加載bean定義這塊,只作為一個參考,希望對其他朋友能有所幫助吧,因為時間匆忙,有錯漏的地方請指正。
(本文作者:easyjf開源 calmness)
posted on 2007-04-29 09:36
簡易java框架 閱讀(2223)
評論(1) 編輯 收藏