spring技术内幕笔记:IoC容器初始化过程(2)- BeanDefinition的载入
2017-07-12 22:25
751 查看
Spring版本:4.3.8.RELEASE
BeanDefinition载入过程,相当于把定义的BeanDefinition在IoC容器中转换成一个Spring内部表示的数据结构的过程。IoC容器对Bean的管理和依赖注入功能的实现,就是通过对其持有的BeanDefinition进行的各种相关操作完成的。这些BeanDefinition数据在IoC容器中通过HashMap来保存和维护。
从DefaultListableBeanFactory的设计入手,看一下IoC容器载入BeanDefinition的过程。
1、FileSystemXmlApplicationContext
从FileSystemXmlApplicationContext开始,在FileSystemXmlApplicationContext的构造函数FileSystemXmlApplicationContext(String[] configLocations,
boolean refresh, ApplicationContext parent)中调用了refresh方法
2、AbstractApplicationContext
3、AbstractRefreshableApplicationContext
loadBeanDefinitions方法由AbstractXmlApplicationContext类实现
4、AbstractXmlApplicationContext
5、AbstractBeanDefinitionReader
在AbstractBeanDefinitionReader的loadBeanDefinitions方法中,又调用了XmlBeanDefinitionReader的loadBeanDefinitions方法。
6、XmlBeanDefinitionReader
7、DefaultBeanDefinitionDocumentReader
8、BeanDefinitionParserDelegate
与<bean>定义相关的。
(1)以解析属性Property的方法为例,看一下整个BeanDefinition载入过程
(2)对<property>元素解析的过程
经过逐层解析,在XML文件中定义的BeanDefinition就被整个载入到了IoC容器中,并在容器中建立的数据映射。在IoC容器中建立的对应的数据结构以AbstractBeanDefinition
为入口,让IoC容器执行索引、查询和操作。
经过以上的载入过程,IoC容器大致完成了管理bean对象的数据准备工作,但是,现在在IoC容器中存在的还只是静态配置信息,要完全发挥容器的作用,还需要完成数据向容器的注册。
整体的流程:
BeanDefinition载入过程,相当于把定义的BeanDefinition在IoC容器中转换成一个Spring内部表示的数据结构的过程。IoC容器对Bean的管理和依赖注入功能的实现,就是通过对其持有的BeanDefinition进行的各种相关操作完成的。这些BeanDefinition数据在IoC容器中通过HashMap来保存和维护。
从DefaultListableBeanFactory的设计入手,看一下IoC容器载入BeanDefinition的过程。
1、FileSystemXmlApplicationContext
从FileSystemXmlApplicationContext开始,在FileSystemXmlApplicationContext的构造函数FileSystemXmlApplicationContext(String[] configLocations,
boolean refresh, ApplicationContext parent)中调用了refresh方法
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext { public FileSystemXmlApplicationContext() { } public FileSystemXmlApplicationContext(ApplicationContext parent) { super(parent); } /** * 构造函数:需要传入XML资源文件的路径 */ public FileSystemXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } /** * 构造函数:传入多个资源文件 */ public FileSystemXmlApplicationContext(String... configLocations) throws BeansException { this(configLocations, true, null); } /** * 构造函数 * @param configLocations 资源文件数组 * @param parent 双亲IoC容器 */ public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException { this(configLocations, true, parent); } /** * 构造函数 * @param configLocations 资源文件路径 * @param refresh 是否调用refresh方法载入BeanDefinition */ public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException { this(configLocations, refresh, null); } /** * 构造函数 * @param configLocations 资源文件路径 * @param refresh 是否调用refresh方法载入BeanDefinition * @param parent 双亲IoC容器 * @throws BeansException */ public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh();//分析容器初始化的一个重要入口 } } /** * 通过资源文件路径获取Resource对象,返回的是一个FileSystemResource对象,通过这个对象可以进行相关I/O操作,完成BeanDefinition定位 * @param path 资源文件路径 * @return Resource spring中的资源对象 */ @Override protected Resource getResourceByPath(String path) { if (path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); } }refresh()方法,启动了对BeanDefinition资源定位的过程,由AbstractApplicationContext实现
2、AbstractApplicationContext
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // 调用obtainFreshBeanFactory()方法 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } } protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory();//调用了refreshBeanFactory()方法 ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } //由子类AbstractRefreshableApplicationContext实现 protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;refresh()方法中,调用了obtainFreshBeanFactory()方法,obtainFreshBeanFactory()方法又调用了refreshBeanFactory方法,在AbstractApplicationContext中,该方法是一个抽象方法,具体的实现由AbstractApplicationContext的子类AbstractRefreshableApplicationContext来实现。
3、AbstractRefreshableApplicationContext
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { /** * AbstractRefreshableApplicationContext中实现的refreshBeanFactory()方法 * * @throws BeansException */ @Override protected final void refreshBeanFactory() throws BeansException { //如果已经建立了BeanFactory,销毁并关闭BeanFactory if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //构造了一个BeanFactory,这里使用DefaultListableBeanFactory实现 DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); //载入BeanDefinition 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的地方 * getInternalParentBeanFactory()的具体实现可以参看AbstractApplicationContext的实现 * * @return */ protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); } /** * 抽象方法,载入BeanDefinition,由子类AbstractXmlApplicationContext实现 * * @param beanFactory * @throws BeansException * @throws IOException */ protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException; }
loadBeanDefinitions方法由AbstractXmlApplicationContext类实现
4、AbstractXmlApplicationContext
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext { @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { //创建XmlBeanDefinitionReader对象,通过回调设置到BeanFactory中,beanFactory使用的也是DefaultListableBeanFactory XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setEnvironment(this.getEnvironment()); //设置ResourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被调用 beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //启动Bean定义信息载入的过程,委托给BeanDefinitionReader完成 initBeanDefinitionReader(beanDefinitionReader); //XmlBeanDefinitionReader对象加载BeanDefinition loadBeanDefinitions(beanDefinitionReader); } protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) { reader.setValidating(this.validating); } /** * 载入BeanDefinition * @param reader * @throws BeansException * @throws IOException */ protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //以Reource的方式获取配置文件的资源位置 Resource[] configResources = getConfigResources(); if (configResources != null) { //调用loadBeanDefinitions方法,该方法在XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader中已经实现 reader.loadBeanDefinitions(configResources); } //以string方式获取配置文件的位置 String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } } }初始化FileSystemXmlApplicationContext的过程中是通过调用IoC容器的refresh来启动整个BeanDefinition的载入过程的,这个初始化是通过定义的XmlBeanDefinitionReader对象来完成的,使用的Ioc容器是DefalutListableBeanFactory,具体的Resource载入在XmlBeanDefinitionReader读入BeanDefinition时实现,这里使用的是XML的方式定义,因此使用XmlBeanDefinitionReader载入。如果是其他的方式,需要使用其他的BeanDefinitionReader。loadBeanDefinitions已在XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader实现。
5、AbstractBeanDefinitionReader
public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader { @Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { //如果Resource为空,停止BeanDefinition的载入,否则启动载入BeanDefinition的过程 Assert.notNull(resources, "Resource array must not be null"); //对载入Bean的数量进行统计 int counter = 0; //遍历整个Resource集合,从每个集合中载入所有的BeanDefinition for (Resource resource : resources) { //loadBeanDefinitions方法是一个接口方法,在XmlBeanDefinitionReader中有具体的实现 counter += loadBeanDefinitions(resource); } return counter; } }
在AbstractBeanDefinitionReader的loadBeanDefinitions方法中,又调用了XmlBeanDefinitionReader的loadBeanDefinitions方法。
6、XmlBeanDefinitionReader
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { //(1)入口 @Override public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { //调用载入以XML形式的BeanDefinition的方法,并使用Resource对象创建EncodedResource对象 return loadBeanDefinitions(new EncodedResource(resource)); } /** * (2)载入以XML形式的BeanDefinition的方法 */ public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } //获取资源对象set集合 Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } //将当前的资源对象加入set集合 if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { //获取资源对象的输入流,得到XML文件 InputStream inputStream = encodedResource.getResource().getInputStream(); try { //创建InputSource准备进行读取 InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { //设置编码 inputSource.setEncoding(encodedResource.getEncoding()); } //具体的读取过程在doLoadBeanDefinitions方法 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(); } } } /** * (3)具体载入BeanDefinition的方法 * 从特定的XML文件中实际载入BeanDefinition的地方 */ protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //取得XML文件的Document对象 Document doc = doLoadDocument(inputSource, resource); //启动的是对BeanDefinition解析的详细过程,会使用到spring的bean配置规则 return registerBeanDefinitions(doc, resource); } 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)BeanDefinition解析的详细过程 * 按照Spring的Bean语义要求进行解析资源文件并转换为内部的数据结构BeanDefinition */ public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //创建BeanDefinitionDocumentReader对XML形式的BeanDefinition进行解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); //具体的解析过程在registerBeanDefinitions方法中完成,该方法在DefaultBeanDefinitionDocumentReader中有实现 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //对载入Bean的数量进行统计 return getRegistry().getBeanDefinitionCount() - countBefore; } /** * (5)创建BeanDefinitionDocumentReader对象 * */ protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); } //使用DefaultBeanDefinitionDocumentReader对XML形式的BeanDefinition进行解析 private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class; }BeanDefinition的载入分成两部分,首先通过调用XML的解析器得到Document对象,此时这些Document对象并没有按照Spring的Bean规则进行解析,在完成通用的XML解析以后,才是按照Spring 并没有按照Spring的Bean规则进行解析,在完成通用的XML解析以后,才是按照Spring Bean规则进行解析的地方,这个过程在documentReader中实现,使用的documentReader是默认设置好的DefaultBeanDefinitionDocumentReader。
7、DefaultBeanDefinitionDocumentReader
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { /** * (1)根据XML的Document对象,解析为BeanDefinition */ public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); //获取根节点 Element root = doc.getDocumentElement(); //注册每一个BeanDefinition doRegisterBeanDefinitions(root); } /** * (2)根据根节点注册每一个BeanDefinition */ protected void doRegisterBeanDefinitions(Element root) { //用于解析BeanDefinition的委托类 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.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } //在开始处理bean定义之前,允许XML通过处理任何自定义元素类型进行扩展 preProcessXml(root); //从根元素开始解析 parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; } /** * (3)从根元素开始解析BeanDefinition * @param root the DOM root element of the document */ 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)解析默认的元素(import、alias、bean、beans) */ private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //import if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); }//alias else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); }//bean else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { //处理元素 processBeanDefinition(ele, delegate); }//beans else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // 递归 doRegisterBeanDefinitions(ele); } } /** * (5)处理给定的Element元素,解析BeanDefinition并注册 */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { /* BeanDefinition的解析结果由BeanDefinitionHolder来持有,BeanDefinitionHolder是BeanDefinition的封装类,封装了 * BeanDefinition的名字和别名,用它来完成向IoC容器的注册 * 解析过程是由BeanDefinitionParserDelegate来实现,根据XML元素信息对Spring的bean规则进行解析 */ BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 向IoC容器注册解析得到的BeanDefnition BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // 注册完成后,发送消息 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } } }BeanDefinitionHolder除了持有BeanDefinition对象外,还持有其他与BeanDefinition的使用相关的信息,比如Bean的名字、别名集合等。这个解析过程是由BeanDefinitionParserDelegate来实现,这个类包含了对各种Spring Bean定义规则的处理,把元素的值从XML文件读出,设置到生成的BeanDefinitionHolder中。
8、BeanDefinitionParserDelegate
public class BeanDefinitionParserDelegate { /** * (1)解析XML元素 */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } /** * (2)解析元素的详细过程,并返回BeanDefinitionHolder对象 */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { //获取<bean>元素中定义的id、name和aliase属性的值 String id = ele.getAttribute(ID_ATTRIBUTE);//id String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//name //aliases List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } //引发对Bean元素的详细解析 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.isDebugEnabled()) { logger.debug("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; } /** * (3)对BeanDefinition定义元素的处理,具体生成BeanDefinition的地方 */上面是对Bean元素进行解析的过程,也就是BeanDefinition依据XML的<bean>定义被创建的过程,BeanDefinition可以看成是对<bean>的抽象,封装的数据大多都是
与<bean>定义相关的。
(1)以解析属性Property的方法为例,看一下整个BeanDefinition载入过程
/** * 对指定Bean元素的<property>子元素集合进行解析 */ public void parsePropertyElements(Element beanEle, BeanDefinition bd) { //获取元素下所有的节点 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { //判断是<property>元素后对<property>元素进行解析 parsePropertyElement((Element) node, bd); } } } /** * 解析<property>元素 */ public void parsePropertyElement(Element ele, BeanDefinition bd) { //获取<property>的name属性 String propertyName = ele.getAttribute(NAME_ATTRIBUTE); if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); try { //如果同一个Bean中已经有同名的property存在,则不进行解析,也就是同一个Bean中有相同的property,起作用的是第一个 if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } //解析<property>值的地方,解析结果会封装到PropertyValue中,然后设置到BeanDefinitionHolder中 Object val = parsePropertyValue(ele, bd, propertyName); PropertyValue pv = new PropertyValue(propertyName, val); parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } } /** * 获取<property>元素的值 */ public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // Should only have one child element: ref, value, list, etc. NodeList nl = ele.getChildNodes();//获取子节点,应该只有一个子元素,ref、value、list等 Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } //是否有ref属性 boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); //是否有value属性 boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } //如果是ref属性 if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } //创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref信息 RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; }//如果是value else if (hasValueAttribute) { //创建TypedStringValue对象,封装value信息 TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; }//如果还有子元素,触发对子元素的解析 else if (subElement != null) { return parsePropertySubElement(subElement, bd); } else { // Neither child element nor "ref" or "value" attribute found. error(elementName + " must specify a ref or value", ele); return null; } }这里是对property子元素解析的过程,Array、List、Set等各种元素都在这里进行解析,生成对应的数据对象,比如ManagedList、ManagedSet等,这些Managed类是Spring对具体的BeanDefinition的数据封装,具体解析方法在BeanDefinitionParserDelegate类中也都能找到。
(2)对<property>元素解析的过程
/** * 解析<property>元素的子元素 */ public Object parsePropertySubElement(Element ele, BeanDefinition bd) { return parsePropertySubElement(ele, bd, null); } /** * Parse a value, ref or collection sub-element of a property or * constructor-arg element. * @param ele subelement of property element; we don't know which yet * @param defaultValueType the default type (class name) for any * {@code <value>} tag that might be created */ public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { //如果元素没有使用spring默认命名空间,调用自定义元素解析方法 if (!isDefaultNamespace(ele)) { return parseNestedCustomElement(ele, bd); } else if (nodeNameEquals(ele, BEAN_ELEMENT)) {//如果是<bean>元素 BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, REF_ELEMENT)) { // A generic reference to any name of any bean. String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in the same XML file. refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in a parent context. refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); toParent = true; if (!StringUtils.hasLength(refName)) { error("'bean', 'local' or 'parent' is required for <ref> element", ele); return null; } } } if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); return null; } RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } else if (nodeNameEquals(ele, IDREF_ELEMENT)) {//<idref>元素 return parseIdRefElement(ele); } else if (nodeNameEquals(ele, VALUE_ELEMENT)) {//<value>元素 return parseValueElement(ele, defaultValueType); } else if (nodeNameEquals(ele, NULL_ELEMENT)) {//<null>元素 // It's a distinguished null value. Let's wrap it in a TypedStringValue // object in order to preserve the source location. TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {//<array>元素 return parseArrayElement(ele, bd); } else if (nodeNameEquals(ele, LIST_ELEMENT)) {//<list>元素 return parseListElement(ele, bd); } else if (nodeNameEquals(ele, SET_ELEMENT)) {//<set>元素 return parseSetElement(ele, bd); } else if (nodeNameEquals(ele, MAP_ELEMENT)) {//<map>元素 return parseMapElement(ele, bd); } else if (nodeNameEquals(ele, PROPS_ELEMENT)) {//<props>元素 return parsePropsElement(ele); } else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } } parseListElement为例: /** * 解析<list>元素 */ public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) { String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = collectionEle.getChildNodes(); ManagedList<Object> target = new ManagedList<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectionEle)); //具体的解析过程 parseCollectionElements(nl, target, bd, defaultElementType); return target; } /** * 解析集合元素的具体过程 */ protected void parseCollectionElements( NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) { //遍历所有的元素节点 for (int i = 0; i < elementNodes.getLength(); i++) { Node node = elementNodes.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) { //加入到target中,target是一个ManagedList,同时触发对下一层的调用 target.add(parsePropertySubElement((Element) node, bd, defaultElementType)); } } }
经过逐层解析,在XML文件中定义的BeanDefinition就被整个载入到了IoC容器中,并在容器中建立的数据映射。在IoC容器中建立的对应的数据结构以AbstractBeanDefinition
为入口,让IoC容器执行索引、查询和操作。
经过以上的载入过程,IoC容器大致完成了管理bean对象的数据准备工作,但是,现在在IoC容器中存在的还只是静态配置信息,要完全发挥容器的作用,还需要完成数据向容器的注册。
整体的流程:
相关文章推荐
- spring技术内幕笔记:IoC容器的初始化过程(3)- BeanDefinition的注册
- spring 技术内幕--IOC初始化过程深入之BeanDefinition的载入和解析1
- spring 技术内幕--IOC初始化过程深入之BeanDefinition的定位
- spring 技术内幕--IOC初始化之BeanDefinition的在IOC容器中的注册
- Spring技术内幕之IOC容器的实现(02)-BeanDefinition的Resource定位
- Spring源码阅读之IoC容器初始化2 -- BeanDefinition载入与解析
- spring技术内幕笔记:IoC容器初始化过程(1)- Resource定位
- 【Spring源码--IOC容器的实现】(三)BeanDefinition的载入和解析【II】
- 【Spring源码--IOC容器的实现】(三)BeanDefinition的载入和解析【I】
- Spring技术内幕之IOC容器的实现(01)-IOC容器初始化过程
- 6-spring源码3.2.18解读+spring技术内幕(关于BeanDefinition的载入和解析)
- SpringIoc BeanDefinition载入交互过程
- Spring源码阅读之IoC容器初始化3 -- BeanDefinition在IoC容器中的注册
- Spring技术内幕笔记 -- IoC容器的实现
- 深探spring系列-----ioc初始化(1)BeanDefinition的Resource定位
- spring技术内幕3-IOC容器载入Bean定义资源
- 5-spring源码3.2.18解读+spring技术内幕(关于BeanDefinition的定位)
- Ioc容器beanDefinition-Spring 源码系列(1)
- Spring容器初始化异常:org.springframework.beans.factory.BeanDefinitionStoreException
- IOC容器初始化——BeanDefinition的Resource定位