Spring啟動流程(二)之Spring載入Bean Definition的流程
prepareRefresh()
prepareRefresh();//初始化配置和環境
obtainFreshBeanFactory()
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory(); }
下面的refreshBeanFactory方法的主要工作:載入applicationContext.xml配置檔案,建立Spring Bean Definition
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
DefaultListableBeanFactory是一個很重要的Bean工廠類,內部儲存了bean definition資訊,即bean的元資料,即描述bean的資訊,這些內容存放在DefaultListableBeanFactory內的不同的容器中(map、list、set);
DefaultListableBeanFactory可以通過後置處理器擴充套件;
loadBeanDefinitions方法傳入DefaultListableBeanFactory,內部是將bean definitions資訊設定到bean factory,如何設定呢?會使用不同的bean definition readers來讀取配置檔案中配置的bean,然後設定到DefaultListableBeanFactory內部的不同資料結構中。
比如常用的XmlBeanDefinitionReader。可以看一下BeanDefinitionReader介面的類繼承層次圖如下。
Bean Definition大致建立過程:
1、載入applicationContext.xml配置檔案
2、解析xml
3、將xml中的內容轉化為Spring Bean Definition。
下面是一些細節及關鍵類:
1、載入資源配置檔案
AbstractBeanDefinitionReader.java
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);//通過類載入器在classpath下找到applicationContext配置檔案的絕對路徑
2、解析生成的xml物件轉為Spring BeanDefinition:
DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
依次遍歷所有遇到的元素(空行、換行、註釋、xml節點),但是隻會解析xml節點(node instanceof Element) 。
內部除了namespace是http://www.springframework.org/schema/beans的,其他節點解析都走delegate.parseCustomElement(ele);
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
這裡的namespaceHandler是從META-INF/spring-handlers檔案讀取的,之後通過反射初始化使用
不過這裡不管是通過哪個namespaceHandler,都要通過NamespaceHandlerSupport轉發處理,因為所有的namespaceHandler都是繼承NamespaceHandlerSupport,重寫了init方法,init方法只是建立xml節點屬性->BeanDefinitionParser的對映關係。
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
this.parsers.put(elementName, parser);
}
接著會從這個對映關係裡找名稱空間處理器然後處理
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}
如果是開啟註解的包掃描配置:
<context:component-scan base-package="com.baby.kim">
會呼叫ComponentScanBeanDefinitionParser,將使用@Service,@Controller等註解的物件轉為beanDefinition。
其他的Context namespace下的處理器還有
3、註冊beanDefinition到DefaultListableBeanFactory
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
3.1、最終呼叫
將beanDefinition資訊儲存到DefaultListableBeanFactory的屬性中。
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
總結:
這一篇主要介紹了Spring是如何解析和將在bean definition到bean factory中的,
下一篇Spring啟動流程(三)之Bean的例項化將介紹Bean的例項化過程