在Spring中,IOC容器的重要地位我們就不多說了,對于Spring的使用者而言,IOC容器實際上是什么呢?我們可以說BeanFactory就是我們看到的IoC容器,當然了Spring為我們準備了許多種IoC容器來使用,這樣可以方便我們從不同的層面,不同的資源位置,不同的形式的定義信息來建立我們需要的IoC容器。
在Spring中,最基本的IOC容器接口是BeanFactory - 這個接口為具體的IOC容器的實現(xiàn)作了最基本的功能規(guī)定 - 不管怎么著,作為IOC容器,這些接口你必須要滿足應(yīng)用程序的最基本要求:
public interface BeanFactory {
//這里是對FactoryBean的轉(zhuǎn)義定義,因為如果使用bean的名字檢索FactoryBean得到的對象是工廠生成的對象,
//如果需要得到工廠本身,需要轉(zhuǎn)義
String FACTORY_BEAN_PREFIX = "&";
//這里根據(jù)bean的名字,在IOC容器中得到bean實例,這個IOC容器就是一個大的抽象工廠。
Object getBean(String name) throws BeansException;
//這里根據(jù)bean的名字和Class類型來得到bean實例,和上面的方法不同在于它會拋出異常:如果根據(jù)名字取得的bean實例的Class類型和需要的不同的話。
Object getBean(String name, Class requiredType) throws BeansException;
//這里提供對bean的檢索,看看是否在IOC容器有這個名字的bean
boolean containsBean(String name);
//這里根據(jù)bean名字得到bean實例,并同時判斷這個bean是不是單件
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//這里對得到bean實例的Class類型
Class getType(String name) throws NoSuchBeanDefinitionException;
//這里得到bean的別名,如果根據(jù)別名檢索,那么其原名也會被檢索出來
String[] getAliases(String name);
}
在BeanFactory里只對IOC容器的基本行為作了定義,根本不關(guān)心你的bean是怎樣定義怎樣加載的 - 就像我們只關(guān)心從這個工廠里我們得到到什么產(chǎn)品對象,至于工廠是怎么生產(chǎn)這些對象的,這個基本的接口不關(guān)心這些。如果要關(guān)心工廠是怎樣產(chǎn)生對象的,應(yīng)用程序需要使用具體的IOC容器實現(xiàn)- 當然你可以自己根據(jù)這個BeanFactory來實現(xiàn)自己的IOC容器,但這個沒有必要,因為Spring已經(jīng)為我們準備好了一系列工廠來讓我們使用。比如XmlBeanFactory就是針對最基礎(chǔ)的BeanFactory的IOC容器的實現(xiàn) - 這個實現(xiàn)使用xml來定義IOC容器中的bean。

文以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);
}
}
這個類的代碼很簡單,一個成員對象加兩個構(gòu)造函數(shù),從這里我們可以看出,最重要的地方在于最后一個構(gòu)造函數(shù):
第一句就是將父親工廠交給父類的構(gòu)造函數(shù),實際上最后也就是把父工廠保存到類的parentBeanFactory成員對象中,這個對象是在AbstractBeanFactory抽象類中定義的,而這個父工廠也會一直傳遞到該抽象類進行保存。第二句就是整個類中最重要的地方了,顧名思義,它的目的是通過XmlBeanDefinitionReader這個XML的Reader從資源resource中(也就是你的配置文件)讀取bean的定義。接下來我們打開XmlBeanDefinitionReader的loadBeanDefinitions方法,我們可看到在這個方法里代碼就一行,調(diào)用了一個同名不同參的方法,而參數(shù)是EncodedResource的一個實例,這個類實際上是Resource的一個包裝類,用來保存資源的Encode的,那接下來我們再看被調(diào)用的loadBeanDefinitions方法,這個方法里最主要的部分就是:
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
這里的目的是將資源包裝成一個InputSource,連同Resource作為參數(shù)傳遞到doLoadBeanDefinitions方法
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對象,然后調(diào)用registerBeanDefinitions方法,這里不做詳細解釋,不了解的話請去看看關(guān)于JAXP的介紹。接下來我們打開registerBeanDefinitions方法:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeansException {
XmlBeanDefinitionParser parser =
(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
return parser.registerBeanDefinitions(this, doc, resource);
}
這里創(chuàng)建了一個XmlBeanDefinitionParser接口的實現(xiàn),這個接口的具體類是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方法的第一個參數(shù)就是bean則個元素,第二個參數(shù)表示該bean是否為內(nèi)置的bean,從這里進行解釋的bean都不可能是內(nèi)置的,所以這里直接以false為參數(shù),打開parseBeanDefinitionElement方法,就可以看到這個方法里就是對bean的內(nèi)部的解釋,也很簡單,也不多講了,呵呵(下班時間已經(jīng)到了,所以就寫這么多了,基本的流程也就這樣,沒什么特別難的地方。),對了,最后還有一點就是解釋完后,bean的定義將會被保存到beanFactory中,這個beanFactory的實現(xiàn)就是XmlBeanFactory了,該beanFactory是在new的時候被傳遞到reader中的,就是該類中以下這行代碼:
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
在Spring中,最基本的IOC容器接口是BeanFactory - 這個接口為具體的IOC容器的實現(xiàn)作了最基本的功能規(guī)定 - 不管怎么著,作為IOC容器,這些接口你必須要滿足應(yīng)用程序的最基本要求:



























在BeanFactory里只對IOC容器的基本行為作了定義,根本不關(guān)心你的bean是怎樣定義怎樣加載的 - 就像我們只關(guān)心從這個工廠里我們得到到什么產(chǎn)品對象,至于工廠是怎么生產(chǎn)這些對象的,這個基本的接口不關(guān)心這些。如果要關(guān)心工廠是怎樣產(chǎn)生對象的,應(yīng)用程序需要使用具體的IOC容器實現(xiàn)- 當然你可以自己根據(jù)這個BeanFactory來實現(xiàn)自己的IOC容器,但這個沒有必要,因為Spring已經(jīng)為我們準備好了一系列工廠來讓我們使用。比如XmlBeanFactory就是針對最基礎(chǔ)的BeanFactory的IOC容器的實現(xiàn) - 這個實現(xiàn)使用xml來定義IOC容器中的bean。

文以spring框架的XmlBeanFactory為入手點進行分析,希望能夠以盡量簡潔明了的方式給予有需要的朋友一定的幫助。















這個類的代碼很簡單,一個成員對象加兩個構(gòu)造函數(shù),從這里我們可以看出,最重要的地方在于最后一個構(gòu)造函數(shù):
第一句就是將父親工廠交給父類的構(gòu)造函數(shù),實際上最后也就是把父工廠保存到類的parentBeanFactory成員對象中,這個對象是在AbstractBeanFactory抽象類中定義的,而這個父工廠也會一直傳遞到該抽象類進行保存。第二句就是整個類中最重要的地方了,顧名思義,它的目的是通過XmlBeanDefinitionReader這個XML的Reader從資源resource中(也就是你的配置文件)讀取bean的定義。接下來我們打開XmlBeanDefinitionReader的loadBeanDefinitions方法,我們可看到在這個方法里代碼就一行,調(diào)用了一個同名不同參的方法,而參數(shù)是EncodedResource的一個實例,這個類實際上是Resource的一個包裝類,用來保存資源的Encode的,那接下來我們再看被調(diào)用的loadBeanDefinitions方法,這個方法里最主要的部分就是:





這里的目的是將資源包裝成一個InputSource,連同Resource作為參數(shù)傳遞到doLoadBeanDefinitions方法








這個方法的目的一目了然,就是為了將資源解釋成為Document對象,然后調(diào)用registerBeanDefinitions方法,這里不做詳細解釋,不了解的話請去看看關(guān)于JAXP的介紹。接下來我們打開registerBeanDefinitions方法:






這里創(chuàng)建了一個XmlBeanDefinitionParser接口的實現(xiàn),這個接口的具體類是DefaultXmlBeanDefinitionParser,這個接口很簡單,只有registerBeanDefinitions一個方法,這個方法的作用也很明了,就是用來注冊Bean的定義的,所以說類和方法的名字一定要起得有意義,這樣可以讓人一看就大概了解其作用,減少了很多閱讀代碼的痛苦。廢話不多說,我們打開DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,這個類就是解釋XML配置文件的核心類了,打開registerBeanDefinitions方法后我們看到如下代碼:


























在這個方法當中,主要用于解釋定義的有兩個方法,一個是initDefaults,一個是parseBeanDefinitions,第一個方法是用來解釋根元素的屬性的,例如lazy-init, autowire等,而parseBeanDefinitions就是用來解釋具體的bean定義了,方法代碼如下:

























其他標簽具體如何被解釋這里就不多說,相信大家也能看得懂,這里主要講一下解釋bean的的處理,我們注意以下代碼:






