前言
Spring配置文件读取流程原本是和http://www.cnblogs.com/xrq730/p/6285358.html一文放在一块儿的,这两天在看Spring自定义标签的时候,感受对Spring配置文件读取流程仍是研究得不够,所以将Spring配置文件读取流程部分从以前的文章拆出来单独成为一文。html
为了看一下Spring配置文件加载流程,先定义一个bean.xml:node
1spring 2c# 3缓存 4数据结构 5dom 6ide 7函数 8源码分析 9 10 11 12 13 14 15 |
<? xml version = "1.0" encoding = "UTF-8" ?> < beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> < bean id = "beanPostProcessorBean" class = "org.xrq.action.BeanPostProcessorBean" /> < bean id = "beanFactoryPostProcessorBean" class = "org.xrq.action.BeanFactoryPostProcessorBean" /> < bean id = "multiFunctionBean" class = "org.xrq.action.MultiFunctionBean" init-method = "initMethod" > < property name = "propertyA" value = "abc" /> </ bean > </ beans > |
至于Bean是什么并不重要,有配置文件就够了。
Bean定义加载流程—-从Refresh到Bean定义加载前
首先看一下Bean加载前整个代码流程走向。Spring上下文刷新始于AbstractApplicationContext的refresh()方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public void refresh() throws BeansException, IllegalStateException { synchronized ( this .startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); ... } |
代码不全帖了,第7行的obtainFreshBeanFactory()方法进去:
1 2 3 4 5 6 7 8 |
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug( "Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } |
第2行的refreshBeanFactory()方法进去,它是AbstractApplicationContext的子类AbstractRefreshableApplicationContext中的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@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); } } |
首先第8行获取DefaultListableBeanFactory,而后执行第11行的方法,传入当前获取的BeanFactory,准备加载Bean定义。BeanFactory中有存储了些什么数据在【Spring源码分析】Bean加载流程概览一文中有画表格详细说明,看过表格的朋友应该知道为何第8行要获取的是DefaultListableBeanFactory而不是它的接口BeanFactory,由于Bean定义存储在Map<String, BeanDefinition>中,这个Map的位置就是在DefaultListableBeanFactory里,所以这里直接获取DefaultListableBeanFactory并做为参数层层向后传,加载完Bean定义后直接向Map<String, BeanDefinition>里put键值对。
看下loadBeanDefinitions方法,它是AbstractRefreshableApplicationContext子类AbstractXmlApplicationContext中的一个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setResourceLoader( this ); beanDefinitionReader.setEntityResolver( new ResourceEntityResolver( this )); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } |
第3行的XmlBeanDefinitionReader是Bean加载的核心类,先构建出来,后面代码没什么值得看的,直接看第13行代码,传入XmlBeanDefinitionReader:
1 2 3 4 5 6 7 8 9 10 |
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null ) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null ) { reader.loadBeanDefinitions(configLocations); } } |
由第8行的代码进去,这个就不跟了,直接走到XmlBeanDefinitionReader的父类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 |
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null ) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available" ); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null ) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug( "Loaded " + loadCount + " bean definitions from location pattern [" + location + "]" ); } return loadCount; } 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 loadCount = loadBeanDefinitions(resource); if (actualResources != null ) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug( "Loaded " + loadCount + " bean definitions from location [" + location + "]" ); } return loadCount; } } |
咱们研究Spring加载流程使用的ClassPathXmlApplicationContext是ResourcePatternResolver的实现类,进入第8行的判断,走第12行的方法,这里也不跟了,很简单,最终代码走到了XmlBeanDefinitionReader的loadBeanDefinitions方法中,也就是Bean定义加载的开始。
Bean定义加载流程—-Bena定义的存储
上面说到了Bean定义是存储在DefaultListableBeanFactory中的,咱们来看一下具体代码:
1 2 3 4 5 |
/** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(); /** List of bean definition names, in registration order */ private final List<String> beanDefinitionNames = new ArrayList<String>(); |
最终DefaultListableBeanFactory会先遍历beanDefinitionNames,从beanDefinitionMap中拿到对应的BeanDefinition,最终转为具体的Bean对象。BeanDefinition自己是一个接口,AbstractBeanDefinition这个抽象类存储了Bean的属性,看一下AbstractBeanDefinition这个抽象类的定义:

这个类的属性与方法不少,这里就列举了一些最主要的方法和属性,能够看到包含了bean标签中的全部属性,以后就是根据AbstractBeanDefinition中的属性值构造出对应的Bean对象。
Bean定义加载流程—-开始加载Bean定义
上面一部分的结尾说道,Bean定义加载的开始始于XmlBeanDefinitionReader的loadBeanDefinitions方法,看下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 |
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<EncodedResource> currentResources = this .resourcesCurrentlyBeingLoaded.get(); if (currentResources == null ) { currentResources = new HashSet<EncodedResource>( 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()); } 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(); } } } |
第17行根据XML文件获取输入字节流,接着流程走到23行doLoadBeanDefinitions方法:
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 |
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource); Document doc = this .documentLoader.loadDocument( inputSource, getEntityResolver(), this .errorHandler, validationMode, isNamespaceAware()); 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行,获取验证模式,代码不跟了,最终出来的是DetectMode,DetectMode的意思是XML文件的验证模式由XML文件自己决定,若是是DTD那就使用DTD验证,若是是XSD就使用XSD验证。
接着是第5行~第6行,这两行的做用是经过DOM获得org.w3c.dom.Document对象,Document将XML文件当作一棵树,Dociument即对这颗树数据结构的一个描述。
最近进入第7行,继续加载Bean定义的流程,跟一下registerBeanDefinitions方法:
1 2 3 4 5 6 7 |
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // Read document based on new BeanDefinitionDocumentReader SPI. BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } |
由于是每一个XML文件执行一次registerBeanDefinitions方法注册Bean定义,所以这整个方法的返回值表示的是当前XML里面一共注册了多少个Bean。直接进入第5行的代码,使用BeanDefintionDocumentReader的registerBeanDefinitions方法来注册Bean定义:
1 2 3 4 5 6 7 8 9 10 11 12 |
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this .readerContext = readerContext; logger.debug( "Loading bean definitions" ); Element root = doc.getDocumentElement(); BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); preProcessXml(root); parseBeanDefinitions(root, delegate); postProcessXml(root); } |
这里面的方法,第9行的方法preProcessXml是个空方法,留给子类扩展用;第11行的方法postProcessXml是个空方法,留给子类扩展用。
第5行的方法获得根节点,也就是<beans …></beans>。
剩下的就是第7行的createHelper方法与第10行的parseBeanDefintions方法了,前者构造出一个Bean定义解析器的委托类,后者使用委托类解析Bean定义,下面分两部分分别来看。
Bean定义加载流程—-createHelper
先看createHelper,即根据根节点建立一个Bean定义解析器的委托类,看一下代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 |
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this .readerContext = readerContext; logger.debug( "Loading bean definitions" ); Element root = doc.getDocumentElement(); BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); preProcessXml(root); parseBeanDefinitions(root, delegate); postProcessXml(root); } |
第2行没有什么特别的,new一个BeanDefinitionParserDelegate出来,第3行的代码跟一下,用于设置默认属性:
1 2 3 4 |
public void initDefaults(Element root) { populateDefaults( this .defaults, root); this .readerContext.fireDefaultsRegistered( this .defaults); } |
跟一下第2行的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
protected void populateDefaults(DocumentDefaultsDefinition defaults, Element root) { defaults.setLazyInit(root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE)); defaults.setMerge(root.getAttribute(DEFAULT_MERGE_ATTRIBUTE)); defaults.setAutowire(root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE)); defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE)); if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) { defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)); } if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) { defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)); } if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) { defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)); } defaults.setSource( this .readerContext.extractSource(root)); } |
看到就是这个地方将<beans>标签下的default-lazy-init、default_merge、default_autowire、default-dependency-check、default-autowire-candidates、default-init-method、default-destroy-method这几个属性取出来,设置到DocumentDefaultsDefinition即defaults中。
Bean定义加载流程—-parseBeanDefintions
到了parseBeanDefintions方法了,这个方法开始真正遍历XML文件中的各个标签并转换为对应的Bean定义,看一下方法定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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); } } |
首先说一下,这里的Namespace都是默认的Namespace,至于Namespace的问题,和自定义Spring标签相关,我想放到自定义Spring标签部分说,这里只要知道代码会进入第2行与第9行的判断便可。
第2行的判断进去,都在遍历Element下的节点不看了,直接跟第9行的代码parseDefaultElement:
1 2 3 4 5 6 7 8 9 10 11 |
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); } } |
这边就是判断节点名称是import仍是alias仍是bean,是其中任意一个就进入相应的执行逻辑,import和alias不看了,这里就看Bean加载流程部分,也就是第9行的processBeanDefinition方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. 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)); } } |
先看第4行,第4行的意思是在须要的时候装饰Bean定义,好比AOP的场景会使用到,这个留在AOP的时候看这段代码。
再看第7行,第7行的意思是注册Bean定义,这在下一部分说,属于Bean定义加载流程的最后一步。
如今看来第2行的代码,顾名思义即解析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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_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); } 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 ; } |
第2行~第18行的代码都是用于获取BeanName,从这段逻辑中咱们能够总结出BeanName定义的规则:
- 默认的BeanName就是<bean>标签重定义的id
- <bean>标签中能够定义name属性,一个bean能够有多个别名(alias),都定义在name属性中,不一样的别名以”,;”分割,假如beanId未定义,那么就以name属性中的第一个别名做为beanName
第20行~第22行的代码主要用于确保BeanName的惟一性,跟一下第21行的方法就知道,BeanName与Bean别名都会放在Set<String>中,而后每次加载Bean定义的时候都会去这个Set<String>中检查当前BeanName和Bean别名是否存在,若是存在就报错。
接着进入第24行的代码,开始解析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 37 38 39 40 41 42 43 44 45 46 47 48 |
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this .parseState.push( new BeanEntry(beanName)); String className = null ; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null ; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource( this .readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error( "Bean class [" + className + "] not found" , ele, ex); } catch (NoClassDefFoundError err) { error( "Class that bean class [" + className + "] depends on not found" , ele, err); } catch (Throwable ex) { error( "Unexpected failure during bean definition parsing" , ele, ex); } finally { this .parseState.pop(); } return null ; } |
对这个方法逐行总结一下:
- 第4行,ParseState是一个基于栈的简单结构,在解析的流程中用于追踪逻辑上的位置,里面存放的是Entry接口。Entry接口有各类实现类好比AdviceEntry、AdvisorEntry、BeanEntry、PropertyEntry等,每一步操做开始将一个Entry推送至栈顶,每一步操做结束将Entry从栈顶弹出,这里将一个BeanEntry推送至栈顶,标识解析Bean定义开始
- 第6行~第9行的代码,用于获取Bean对应的类路径
- 第12行~第15行的代码,用于解析<bean>标签中的parent属性
- 第16行的代码,根据Bean对应的类路径以及parent,生成一个AbstractBeanDefinition,AbstractBeanDefinition是一个抽象类,生成出来的具体实例为GenericBeanDefinition
- 第18行的代码,就不跟了进去一看就很好理解,是用于解析Bean定义的属性的,包括scope、sington、abstract、lazy-init、autowire、dependency-check、depends-on、autowire-candidate、primary、init-method、destory-method、factory-method、factory-bean,createHelper部分说了这个方法会建立一个名为defaults的DocumentDefaultsDefinition,像lazy-init、autowire-candidate、init-method、destory-method未定义时都会尝试从DocumentDefaultsDefinition中获取
- 第19行用于设置Bean描述
- 第21行的方法parseMetaElements用于解析META元素
- 第22行的方法parseLookupOverrideSubElements用于解析<bean>标签下的<lookup-method>标签
- 第23行的方法parseReplacedMethodSubElements用于解析<bean>标签下的<replaced-method>标签,不过这个和<lookup-method>标签好像不太经常使用
- 第25行的方法parseConstructorArgElements用于解析<bean>标签下的<constructor-arg>标签,<constructor-arg>标签用于实现构造函数注入Bean属性
- 第26行的方法parsePropertyElements用于解析<bean>标签下的<property>标签,<property>标签是最多见的Bean属性注入的方式
- 第27行的方法parseQualifierElements用于解析<bean>标签下的<qualifier>标签,使用<qualifier>标签也是Spring属性注入的一种方式,不过不太经常使用
这样,就把整个Bean定义加载的流程跟完了,最后一步,就是将AbstractBeanDefinition写回到DefaultListableBeanFactory中了。
Bean定义加载流程—-Bean定义写回DefaultListableBeanFactory
最后一步,将Bean定义写回DefaultListableBeanFactory中。代码要追溯回DefaultBeanDefinitionDocumentReader的processBeanDefinition方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. 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)); } } |
Bean定义加载完毕后构造为一个BeanDefinitionHolder,第4行的代码以前说过的,用于在必要的状况下装饰Bean定义先无论。
第7行的代码用于注册Bean定义,跟一下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null ) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } } } |
跟一下第7行的方法,调用DefaultListableBeanFactory的registerBeanDefinition方法:
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 |
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty" ); Assert.notNull(beanDefinition, "BeanDefinition must not be null" ); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed" , ex); } } synchronized ( this .beanDefinitionMap) { Object oldBeanDefinition = this .beanDefinitionMap.get(beanName); if (oldBeanDefinition != null ) { if (! this .allowBeanDefinitionOverriding) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound." ); } else { if ( this .logger.isInfoEnabled()) { this .logger.info( "Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]" ); } } } else { this .beanDefinitionNames.add(beanName); this .frozenBeanDefinitionNames = null ; } this .beanDefinitionMap.put(beanName, beanDefinition); resetBeanDefinition(beanName); } } |
简单说这个方法作了几件事情:
- beanDefinitionNames添加BeanName
- beanDefinitionMap添加一对映射,Key为BeanName,Value为Bean定义
- 第38行的方法用于重置一下全部本地缓存了的Bean定义
<bean>中不定义id及id重复场景Spring的处理方式
这两天又想到了两个细节问题,<bean>中不定义id或者id重复,这两种场景Spring是如何处理的。首先看一下不定义id的场景,代码在BeanDefinitionParserDelegate类第398行的这个判断这里:
1 2 3 4 5 6 7 8 9 10 11 |
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); ... } |
当bean的id未定义时,即beanName为空,进入第2行的if判断。containingBean能够看一下,这里是由方法传入的,是一个null值,所以进入第9行的判断,即beanName由第9行的方法生成,看一下生成方式,代码最终要追踪到BeanDefinitionReaderUtils的generateBeanName方法:
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 |
public static String generateBeanName( BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) throws BeanDefinitionStoreException { String generatedBeanName = definition.getBeanClassName(); if (generatedBeanName == null ) { if (definition.getParentName() != null ) { generatedBeanName = definition.getParentName() + "$child" ; } else if (definition.getFactoryBeanName() != null ) { generatedBeanName = definition.getFactoryBeanName() + "$created" ; } } if (!StringUtils.hasText(generatedBeanName)) { throw new BeanDefinitionStoreException( "Unnamed bean definition specifies neither " + "'class' nor 'parent' nor 'factory-bean' - can't generate bean name" ); } String id = generatedBeanName; if (isInnerBean) { // Inner bean: generate identity hashcode suffix. id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition); } else { // Top-level bean: use plain class name. // Increase counter until the id is unique. int counter = - 1 ; while (counter == - 1 || registry.containsBeanDefinition(id)) { counter++; id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter; } } return id; } |
这段代码的逻辑很容易看懂,即:
- 假如是innerBean(好比Spring AOP产生的Bean),使用【类全路径+#+对象HashCode的16进制】的格式来命名Bean
- 假如不是innerBean,使用【类全路径+#+数字】的格式来命名Bean,其中数字指的是,同一个Bean出现1次,只要该Bean没有id,就从0开始依次向上累加,好比a.b.c#0、a.b.c#一、a.b.c#2
接着看一下id重复的场景Spring的处理方式,重复id是这样的,Spring使用XmlBeanDefinitionReader读取xml文件,在这个类的doLoadBeanDefinitions的方法中:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource); Document doc = this .documentLoader.loadDocument( inputSource, getEntityResolver(), this .errorHandler, validationMode, isNamespaceAware()); return registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { throw ex; } ... } |
第5行的代码将xml解析成Document,这里的解析使用的是JDK自带的DocumentBuilder,DocumentBuilder处理xml文件输入流,发现两个<bean>中定义的id重复即会抛出XNIException异常,最终将致使Spring容器启动失败。
所以,结论就是:Spring不容许两个<bean>定义相同的id。