當你凝視黑夜的時候,黑夜也在凝視着你!日日當精進,幹就完了!上篇Spring IOC 源碼調試二的進度,進行到了重點的AbstractBeanDefinitionReader
的loadBeanDefinitions
方法**,那這一篇接着進行。原創純手打!實屬不易!求贊!求關注!我不會由於您的不支持而低迷,可是有了您的支持我會變的亢奮!java
這是調試代碼node
AbstractBeanDefinitionReader
的loadBeanDefinitions(String location, @Nullable Set actualResources)
該方法中主要操做有:express
ResourceLoader resourceLoader = getResourceLoader()
:獲取一個ResourceLoader
(資源加載器)對象函數
此時獲取到的ResourceLoader
具體實現類是ClassPathXmlApplicationContext
對象,詳情請看Spring IOC 源碼調試二的2-5
部分的第3個操做。post
int count = loadBeanDefinitions(resources)
:繼續調用XmlBeanDefinitionReader
的loadBeanDefinitions(Resource... resources)
方法。此時的this對象是XmlBeanDefinitionReader
ui
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
//初始化 XmlBeanDefinitionReader 時 設置了 setResourceLoader(this)
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
// 進一步調用 XmlBeanDefinitionReader的loadBeanDefinitions(Resource... resources)方法
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
複製代碼
XmlBeanDefinitionReader
的loadBeanDefinitions(Resource... resources)
方法看下面代碼,該方法中是對每一個資源逐一解析的,可是返回值是總的bean的個數。很無奈又是層層調用XmlBeanDefinitionReader
的loadBeanDefinitions
重載方法,調用過程當中有一個邏輯是把參數Resource
對象轉換成了EncodeResource
對象,而且最後調用到XmlBeanDefinitionReader
的loadBeanDefinitions(EncodedResource encodedResource)
方法this
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
// 加載每一個資源的 bean 的個數
count += loadBeanDefinitions(resource);
}
// 返回總共 bean 的個數
return count;
}
複製代碼
XmlBeanDefinitionReader
的loadBeanDefinitions(EncodedResource encodedResource)
方法這個方法主要做用我認爲就是獲取到資源的輸入流。重點是將輸入流做爲參數傳入XmlBeanDefinitionReader
的doLoadBeanDefinitions(InputSource inputSource, Resource resource)
方法中spa
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 獲得資源的輸入流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 真正 解析 XML 文件方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
複製代碼
XmlBeanDefinitionReader
的doLoadBeanDefinitions(InputSource inputSource, Resource resource)
方法該方法主要就兩個操做:翻譯
Document doc = doLoadDocument(inputSource, resource);
:將xml文件解析爲Document
對象int count = registerBeanDefinitions(doc, resource)
:註冊Beandefinition
到容器(DefaultListableBeanFatory
)中/**將 xml文件 裝載爲 BeanDefinition */
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
複製代碼
Document doc = doLoadDocument(inputSource, resource)
此時的this對象依然爲XmlBeanDefinitionReader
對象,因此會執行XmlBeanDefinitionReader
的doLoadDocument(InputSource inputSource, Resource resource)
方法,代碼以下:debug
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
複製代碼
代碼執行的邏輯:
XmlBeanDefinitionReader
對象中維護了一個private DocumentLoader documentLoader = new DefaultDocumentLoader();
屬性DefaultDocumentLoader
的loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware)
方法DocumentBuilderImpl
的parse(InputSource is)
方法,最後執行DOM解析,返回Document
對象獲得xml文件的Document
對象後做爲參數傳給:XmlBeanDefinitionReader
對象的registerBeanDefinitions(doc, resource)
方法
:XmlBeanDefinitionReader
對象的registerBeanDefinitions(Document doc, Resource resource)
方法public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 獲取一個`DefaultBeanDefinitionDocumentReader`對象
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 獲取 註冊Beandefinition以前 Beandefinition的數量
int countBefore = getRegistry().getBeanDefinitionCount();
// 註冊 BeanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
複製代碼
該方法中主要邏輯有:
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader()
獲得一個BeanDefinitionDocumentReader
對象,真正的實現類是DefaultBeanDefinitionDocumentReader
int countBefore = getRegistry().getBeanDefinitionCount();
:獲取 註冊Beandefinition以前 Beandefinition的數量:XmlBeanDefinitionReader
對象,調用getRegistry()
方法時是調用父類AbstractBeanDefinitionReader
的getRegistry()
方法。2-5
部分的第一個操做在實例化:XmlBeanDefinitionReader
對象的時候把DefaultListableBeanFactory
最爲參數傳給了:XmlBeanDefinitionReader
的構造參數,而DefaultListableBeanFactory
對象又實現了BeanDefinitionRegistry
,因此調用AbstractBeanDefinitionReader
的getRegistry()
方法獲得的對象是DefaultListableBeanFactory
DefaultListableBeanFactory
的getBeanDefinitionCount()
方法就是獲取beanDefinitionMap
(Bean元數據信息集合)中的個數documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
:註冊 BeanDefinitioncreateReaderContext(resource)
:我理解爲構造:XmlBeanDefinitionReader
對象的應用上下文大概意思就是把:XmlBeanDefinitionReader
包裝一下變成XmlReaderContext
對象
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
複製代碼
DefaultBeanDefinitionDocumentReader
的registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
方法此時的this對象變爲了DefaultBeanDefinitionDocumentReader
看到下面代碼就知道三個操做
this.readerContext = readerContext;
:將上層函數傳進來的XmlReaderContext
賦值給本身的屬性doc.getDocumentElement()
獲取Document
的節點對象DefaultBeanDefinitionDocumentReader
的doRegisterBeanDefinitions(Element root)
方法public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
複製代碼
DefaultBeanDefinitionDocumentReader
的doRegisterBeanDefinitions(Element root)
方法該方法註釋翻譯過來是:在給定的根中註冊每一個bean定義,我理解就是......好吧我沒理解啥。
主要有兩個操做
this.delegate = createDelegate(getReaderContext(), root, parent);
:獲取 BeanDefinitionParserDelegate
對象
簡單說一下BeanDefinitionParserDelegate
對象:
Beandefinition
的方法parseBeanDefinitions(root, this.delegate);
:一看這方法就知道後面將註冊又委託給了this.delegate
/**在給定的根中註冊每一個bean定義 * Register each bean definition within the given root {@code <beans/>} element. */
@SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...)
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
// 獲取 BeanDefinitionParserDelegate 對象
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 空方法
preProcessXml(root);
// 解析xml 標籤
parseBeanDefinitions(root, this.delegate);
// 空方法
postProcessXml(root);
this.delegate = parent;
}
複製代碼
DefaultBeanDefinitionDocumentReader
的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
方法在該方法中,要了解一下Dom解析相關的 Node、Element等對象
由於要解析咱們在xml中配置的Bean
,因此會parseDefaultElement(ele, delegate)
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)) {
// 只 解析 "import", "alias", "bean", "beans" 標籤
parseDefaultElement(ele, delegate);
}
else {
// 解析 其餘的標籤 好比 <component-scan> 標籤
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
複製代碼
DefaultBeanDefinitionDocumentReader
的parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
方法由於調試項目中只配置了<bean></bean>
標籤,因此只關注代碼中的processBeanDefinition(ele, delegate);
方法
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// 解析 bean 標籤
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
複製代碼
DefaultBeanDefinitionDocumentReader的
processBeanDefinition(ele, delegate);方法
看代碼瞭解到,將解析任務委託給了BeanDefinitionParserDelegate
對象
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 將 xml 配置信息封裝爲 Beandefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//將 Beandefinition 註冊到 容器(DefaultListableBeanFactory) 中
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
複製代碼
該方法主要的3個操做
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele)
:將 xml 配置信息封裝爲 Beandefinition
在這段代碼中能夠得知:
id
屬性就是咱們Bean的名字parseBeanDefinitionElement(ele, beanName, containingBean)
方法中還會初始化Beandefinition
的一些屬性BeanDefinitionHolder
對象將Beandefinition
包裝起來public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// 定義 bean 的名字 爲xml中配置的 id 屬性
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
// 校驗名字是否是惟一的
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 將xml配置信息 封裝成 BeanDefinition 對象
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
複製代碼
註冊Beandefinition
到容器中:BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
getReaderContext().getRegistry()
:由於在4-2-3.1
中封裝的XmlReaderContext
對象包含:XmlBeanDefinitionReader
對象的全部信息,因此這個方法獲取到的對象就是容器對象DefaultListableBeanFactory
,
該方法將第一個操做獲取到的bdHolder
(Beandefinition
對象的持有者)和 容器對象做爲參數傳入
進入方法後又調用registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())
(此時registry就是DefaultListableBeanFactory對象)將Beandefinition
對象添加到DefaultListableBeanFactory
對象的屬性Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256)
中,就算註冊完成了
BeanDefinitionReaderUtils
的 registerBeanDefinition()
方法代碼
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 調用 容器對象(DefaultListableBeanFactory) 註冊 Beandefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
複製代碼
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
該方法中還有一些邏輯,可是主流程就是將Beandefinition
添加到beanDefinitionMap
中
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder))
該方法註釋爲Send registration event
,我理解是發佈一個註冊事件。這塊沒有深刻跟蹤。
DefaultBeanDefinitionDocumentReader
的parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
方法(4-2-3.5)此時processBeanDefinition(ele, delegate);
方法執行完畢
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
複製代碼
DefaultBeanDefinitionDocumentReader
的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
方法(4-2-3.4)此時 parseDefaultElement(ele, delegate);
方法執行完畢,可是此處是遍歷根節點對象,意思就是多個<bean></bean>
標籤的話就會遍歷執行解析重複上面的過程。
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)) {
// 只 解析 "import", "alias", "bean", "beans" 標籤
parseDefaultElement(ele, delegate);
}
else {
// 解析 其餘的標籤 好比 <component-scan> 標籤
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
複製代碼
DefaultBeanDefinitionDocumentReader
的doRegisterBeanDefinitions(Element root)
方法(4-2-3.3)parseBeanDefinitions(root, this.delegate);
方法this.delegate = parent
,即將this.delegate
置爲null
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
//獲得一個 BeanDefinitionParserDelegate 對象
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 空方法
preProcessXml(root);
// 解析xml 標籤
parseBeanDefinitions(root, this.delegate);
// 空方法
postProcessXml(root);
this.delegate = parent;
}
複製代碼
DefaultBeanDefinitionDocumentReader
的registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
方法(4-2-3.2)此時執行完了doRegisterBeanDefinitions(doc.getDocumentElement());
方法
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
複製代碼
XmlBeanDefinitionReader
對象的registerBeanDefinitions(Document doc, Resource resource)
方法(4-2)documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
方法getRegistry().getBeanDefinitionCount() - countBefore
計算得出該次註冊BeanDefinition
的個數public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
複製代碼
XmlBeanDefinitionReader
的doLoadBeanDefinitions(InputSource inputSource, Resource resource)
方法(4)int count = registerBeanDefinitions(doc, resource);
方法/**將 xml文件 裝載爲 BeanDefinition */
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
複製代碼
AbstractBeanDefinitionReader
的loadBeanDefinitions(String location, @Nullable Set actualResources)
方法(1)count += loadBeanDefinitions(resource);
方法resource
Beandefinition
的數量public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
// 加載每一個資源的 bean 的個數
count += loadBeanDefinitions(resource);
}
return count;
}
複製代碼
loadBeanDefinitions()
方法包含了對xml文件的解析以及對Beandefinition
對象的封裝和註冊loadBeanDefinitions()
中最後註冊是調用的DefaultListableBeanFactory
對象的方法Beandefinition
對象都被維護在DefaultListableBeanFactory
對象的Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
屬性中若是喜歡請關注我公衆號【程序傾聽者】,說出你的故事!我在這裏傾聽!
文章原文地址