在Spring中IOC容器的重要地位我們就不多說了對於Spring的使用者而言IOC容器實際上是什麼呢?我們可以說BeanFactory就是我們看到的IoC容器當然了Spring為我們准備了許多種IoC容器來使用這樣可以方便我們從不同的層面不同的資源位置不同的形式的定義信息來建立我們需要的IoC容器
在Spring中最基本的IOC容器接口是BeanFactory 這個接口為具體的IOC容器的實現作了最基本的功能規定 不管怎麼著作為IOC容器這些接口你必須要滿足應用程序的最基本要求
public interface BeanFactory {
//這裡是對FactoryBean的轉義定義因為如果使用bean的名字檢索FactoryBean得到的對象是工廠生成的對象
//如果需要得到工廠本身需要轉義
String FACTORY_BEAN_PREFIX = &;
//這裡根據bean的名字在IOC容器中得到bean實例這個IOC容器就是一個大的抽象工廠
Object getBean(String name) throws BeansException;
//這裡根據bean的名字和Class類型來得到bean實例和上面的方法不同在於它會拋出異常如果根據名字取得的bean實例的Class類型和需要的不同的話
Object getBean(String name Class requiredType) throws BeansException;
//這裡提供對bean的檢索看看是否在IOC容器有這個名字的bean
boolean containsBean(String name);
//這裡根據bean名字得到bean實例並同時判斷這個bean是不是單件
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//這裡對得到bean實例的Class類型
Class getType(String name) throws NoSuchBeanDefinitionException;
//這裡得到bean的別名如果根據別名檢索那麼其原名也會被檢索出來
String[] getAliases(String name);
}
在BeanFactory裡只對IOC容器的基本行為作了定義根本不關心你的bean是怎樣定義怎樣加載的 就像我們只關心從這個工廠裡我們得到到什麼產品對象至於工廠是怎麼生產這些對象的這個基本的接口不關心這些如果要關心工廠是怎樣產生對象的應用程序需要使用具體的IOC容器實現 當然你可以自己根據這個BeanFactory來實現自己的IOC容器但這個沒有必要因為Spring已經為我們准備好了一系列工廠來讓我們使用比如XmlBeanFactory就是針對最基礎的BeanFactory的IOC容器的實現 這個實現使用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);
thisreaderloadBeanDefinitions(resource);
}
}
這個類的代碼很簡單一個成員對象加兩個構造函數從這裡我們可以看出最重要的地方在於最後一個構造函數
第一句就是將父親工廠交給父類的構造函數實際上最後也就是把父工廠保存到類的parentBeanFactory成員對象中這個對象是在AbstractBeanFactory抽象類中定義的而這個父工廠也會一直傳遞到該抽象類進行保存第二句就是整個類中最重要的地方了顧名思義它的目的是通過XmlBeanDefinitionReader這個XML的Reader從資源resource中(也就是你的配置文件)讀取bean的定義接下來我們打開XmlBeanDefinitionReader的loadBeanDefinitions方法我們可看到在這個方法裡代碼就一行調用了一個同名不同參的方法而參數是EncodedResource的一個實例這個類實際上是Resource的一個包裝類用來保存資源的Encode的那接下來我們再看被調用的loadBeanDefinitions方法這個方法裡最主要的部分就是
InputSource inputSource = new InputSource(inputStream);
if (encodedResourcegetEncoding() != null) {
inputSourcesetEncoding(encodedResourcegetEncoding());
}
return doLoadBeanDefinitions(inputSource encodedResourcegetResource());
這裡的目的是將資源包裝成一個InputSource連同Resource作為參數傳遞到doLoadBeanDefinitions方法
DocumentBuilderFactory factory = createDocumentBuilderFactory();
if (loggerisDebugEnabled()) {
loggerdebug(Using JAXP implementation [ + factory + ]);
}
DocumentBuilder builder = createDocumentBuilder(factory);
Document doc = builderparse(inputSource);
return registerBeanDefinitions(doc resource);
這個方法的目的一目了然就是為了將資源解釋成為Document對象然後調用registerBeanDefinitions方法這裡不做詳細解釋不了解的話請去看看關於JAXP的介紹接下來我們打開registerBeanDefinitions方法
public int registerBeanDefinitions(Document doc Resource resource) throws BeansException {
XmlBeanDefinitionParser parser =
(XmlBeanDefinitionParser) BeanUtilsinstantiateClass(thisparserClass);
return parserregisterBeanDefinitions(this doc resource);
}
這裡創建了一個XmlBeanDefinitionParser接口的實現這個接口的具體類是DefaultXmlBeanDefinitionParser這個接口很簡單只有registerBeanDefinitions一個方法這個方法的作用也很明了就是用來注冊Bean的定義的所以說類和方法的名字一定要起得有意義這樣可以讓人一看就大概了解其作用減少了很多閱讀代碼的痛苦廢話不多說我們打開DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法這個類就是解釋XML配置文件的核心類了打開registerBeanDefinitions方法後我們看到如下代碼
public int registerBeanDefinitions(BeanDefinitionReader reader Document doc Resource resource)
throws BeanDefinitionStoreException {
thisbeanDefinitionReader = reader;
thisresource = resource;
loggerdebug(Loading bean definitions);
Element root = docgetDocumentElement();
//初始化根元素
initDefaults(root);
if (loggerisDebugEnabled()) {
loggerdebug(Default lazy init + getDefaultLazyInit() + );
loggerdebug(Default autowire + getDefaultAutowire() + );
loggerdebug(Default dependency check + getDefaultDependencyCheck() + );
}
preProcessXml(root);//一個空方法用於擴展
int beanDefinitionCount = parseBeanDefinitions(root);//解釋配置的主要方法
if (loggerisDebugEnabled()) {
loggerdebug(Found + beanDefinitionCount + <bean> elements in + resource);
}
postProcessXml(root); //一個空方法用於擴展
return beanDefinitionCount;
}
在這個方法當中主要用於解釋定義的有兩個方法一個是initDefaults一個是parseBeanDefinitions第一個方法是用來解釋根元素的屬性的例如lazyinit autowire等而parseBeanDefinitions就是用來解釋具體的bean定義了方法代碼如下
protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {
NodeList nl = rootgetChildNodes();
int beanDefinitionCount = ;
for (int i = ; i < nlgetLength(); i++) {
Node node = em(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (IMPORT_ELEMENTequals(nodegetNodeName())) {
importBeanDefinitionResource(ele);
}
else if (ALIAS_ELEMENTequals(nodegetNodeName())) {
String name = elegetAttribute(NAME_ATTRIBUTE);
String alias = elegetAttribute(ALIAS_ATTRIBUTE);
thisbeanDefinitionReadergetBeanFactory()registerAlias(name alias);
}
else if (BEAN_ELEMENTequals(nodegetNodeName())) {
beanDefinitionCount++;
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele false);
BeanDefinitionReaderUtilsregisterBeanDefinition(bdHolder thisbeanDefinitionReadergetBeanFactory());
}
}
}
return beanDefinitionCount;
}
其他標簽具體如何被解釋這裡就不多說相信大家也能看得懂這裡主要講一下解釋bean的的處理我們注意以下代碼
else if (BEAN_ELEMENTequals(nodegetNodeName())) {
beanDefinitionCount++;
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele false);
BeanDefinitionReaderUtilsregisterBeanDefinition(bdHolder thisbeanDefinitionReadergetBeanFactory());
}
這裡是當碰到一個bean標簽的時候所進行的處理也既是對bean的定義進行解釋可以看到parseBeanDefinitionElement方法的第一個參數就是bean則個元素第二個參數表示該bean是否為內置的bean從這裡進行解釋的bean都不可能是內置的所以這裡直接以false為參數打開parseBeanDefinitionElement方法就可以看到這個方法裡就是對bean的內部的解釋也很簡單也不多講了呵呵(下班時間已經到了所以就寫這麼多了基本的流程也就這樣沒什麼特別難的地方)對了最後還有一點就是解釋完後bean的定義將會被保存到beanFactory中這個beanFactory的實現就是XmlBeanFactory了該beanFactory是在new的時候被傳遞到reader中的就是該類中以下這行代碼
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28593.html