源代碼分析,是一件既痛苦又快樂的事情,看別人寫的代碼是通過的,但當你能夠看 明白的時候,相信快樂也會隨之而來,為了減少痛苦,更快的帶來快樂,在這裡希望通過 這篇文章對覺得困難的朋友有一個幫助。
首先來打開該類的代碼,我們將看到如下代碼:
Java代碼
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);
}
}
這個類的代碼很簡單,一個成員對象加兩個構造函數,從這裡我們可以看出,最重要 的地方在於最後一個構造函數:
Java代碼
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
第一句就是將父親工廠交給父類的構造函數,實際上最後也就是把父工廠保存到類的 parentBeanFactory成員對象中,這個對象是在AbstractBeanFactory抽象類中定義的,而 這個父工廠也會一直傳遞到該抽象類進行保存。第二句就是整個類中最重要的地方了,顧 名思義,它的目的是通過XmlBeanDefinitionReader這個XML的Reader從資源resource中( 也就是你的配置文件)讀取bean的定義。接下來我們打開XmlBeanDefinitionReader的 loadBeanDefinitions方法,我們可看到在這個方法裡代碼就一行,調用了一個同名不同 參的方法,而參數是EncodedResource的一個實例,這個類實際上是Resource的一個包裝 類,用來保存資源的Encode的,那接下來我們再看被調用的loadBeanDefinitions方法, 這個方法裡最主要的部分就是:
Java代碼
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding ());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
這裡的目的是將資源包裝成一個InputSource,連同Resource作為參數傳遞到 doLoadBeanDefinitions方法
Java代碼
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);
這個方法的目的一目了然,就是為了將資源解釋成為Document對象,然後調用 registerBeanDefinitions方法,這裡不做詳細解釋,不了解的話請去看看關於JAXP的介 紹。接下來我們打開registerBeanDefinitions方法:
Java代碼
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方法後我們 看到如下代碼:
Java代碼
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定義了,方法代碼如下:
Java代碼
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的的處理,我們注意以下代碼:
Java代碼
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中的,就是該類中以下這行代碼:
Java代碼
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
好了,就這麼多了,本文只作為參考,只講解了如何加載bean定義這塊,只作為一個 參考,希望對其他朋友能有所幫助吧,因為時間匆忙,有錯漏的地方請指正。