1. 目录
[TOC]
2. 说明
3. 源码解析
3.1. AbstractRefreshableApplicationContext#loadBeanDefinitions
AbstractRefreshableApplicationContext 不提供加载beanDefinition的具体逻辑,交由子类实现,xml加载的方式的子类为XmlWebApplicationContext
,
loadBeanDefinitions
加载Bean定义,此类在AbstractRefreshableApplicationContext为抽象方法,因此需要找到实现类方法XmlWebApplicationContext#loadBeanDefinitions()
实现类加载Bean定义
3.2. 加载入口方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
|
3.3. loadBeanDefinitions()
加载BeanDefinition
1 2 3 4 5 6 7 8 9 10
| protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) { for (String configLocation : configLocations) { reader.loadBeanDefinitions(configLocation); } } }
|
从这里可以看出来,此时开始获取到Spring的配置文件,准备从配置文件中加载Bean的定义相关的信息
4. XmlBeanDefinitionReader
解析Spring的xml文件配置信息
XmlBeanDefinitionReader
继承至AbstractBeanDefinitionReader
,其加载BeanDefinition的主要方法由抽象类完成
4.1. AbstractBeanDefinitionReader#loadBeanDefinitions()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { return loadBeanDefinitions(location, null); }
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available"); }
if (resourceLoader instanceof ResourcePatternResolver) { try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); 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 { 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; } }
Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int count = 0; for (Resource resource : resources) { count += loadBeanDefinitions(resource); } return count; }
@Override public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); }
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.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); }
try (InputStream inputStream = encodedResource.getResource().getInputStream()) { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }
|
4.2. doLoadBeanDefinitions()
读取xml docment 加载bean定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| 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); } }
|
4.3. registerBeanDefinitions()
注册BeanDefinition
注册BeanDefinition
1 2 3 4 5 6 7 8 9 10 11 12
| 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; }
|
4.4. DefaultBeanDefinitionDocumentReader#registerBeanDefinitions()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| @Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; doRegisterBeanDefinitions(doc.getDocumentElement()); } protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; 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); 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); parseBeanDefinitions(root, this.delegate); postProcessXml(root);
this.delegate = parent; }
|
4.5. DefaultBeanDefinitionDocumentReader#parseBeanDefinitions()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 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); } }
|
4.6. DefaultBeanDefinitionDocumentReader#parseDefaultElement()
解析默认的标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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)) { doRegisterBeanDefinitions(ele); } }
|
此处根据默认的bean类型解析对应的标签,具体逻辑就暂时忽略了
4.7. BeanDefinitionParserDelegate#parseCustomElement()
解析非默认的标签
非默认的标签,即没有在 xmlns="http://www.springframework.org/schema/beans
空间下的,需要单独引入的,如context需引入xmlns:context="http://www.springframework.org/schema/context"
spring 提供的自定义标签解析器如图:

代码解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @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
,开始各自的解析逻辑
至此,xml标签的解析就完成了
对于程序中的@Component
注解,xml需配置扫描<context:component-scan/>
加上这标签的则会在拿到命名空间时拿到ContextNameSpaceHandler
,用于扫描包并解析BeanDefinition
5. 注意要点
此处只是针对xml文件下的对应命名空间下的BeanDefinition的加载,至于使用注解@Component
的加载是通过一个扫描器执行,后续再进行讲解
//todo 基于注解的
6. 总结
加载Bean定义主要就是先拿到配置的文件地址,再转换成流,再转换成Docment元素,使用xml文档的标准解析得到对应的节点元素,分析元素类型再进行解析成对应的BeanDefinition