为了弄清楚Bean是怎么来的,花费了大把功夫,现在要把Bean Definition的加载、解析、处理、注册到bean工厂的过程记下来。这只是bean definition 的加载、解析、处理、注册过程中的一种。
好记性不如烂笔头。
首先我已经知道bean definition 存在了哪里:它就存在一个Map对象中,如果使用的是DefaultListableBeanFactory的话,它就存在一个ConcurrentHashMap对象中。
/** bean 的名字为键,BeanDefinition为值,初始容量为256 */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
现在将BeanDefinition是如何一步步走到这个Map对象中的。
一、BeanDefinition的加载
过程比较长,得对着源码慢慢看。
这里讲的是使用xml配置文件的方式来配置bean.
既然是使用的xml配置文件的方式来配置bean,那么首先要读取xml文件。
一)、AbstractBeanDefinitionReader类中
这一步只是说加载bean definition,但是这里方法参数resources 所指的资源并不确定是什么样的,有可能是xml文件,也有可能是属性文件,或者是脚本。
@Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { counter += loadBeanDefinitions(resource);//这个方法有几个实现,如下 } return counter; }
上面的代码中的一行 counter += loadBeanDefinitions(resource); 这行代码有好几个实现类都实现了它。如下图:
我这里使用实现类XmlBeanDefinitionReader中的实现,所以这里的资源是xml文件。
二)、XmlBeanDefinitionReader类中
从指定的xml文件中加载bean definition,但是他这里只是将Resource转化为EncodedResource对象。然后把这个任务递交给它的重载方法来做。
三)、XmlBeanDefinitionReader类中
从指定的XML文件中加载bean definition。但还不是真正的加载bean定义,只是做准备。
/** * Load bean definitions from the specified XML file. * @param encodedResource the resource descriptor for the XML file, * allowing to specify an encoding to use for parsing the file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ 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(); } } }
四、XmlBeanDefinitionReader类中
这里是真正的从xml 文件中加载的bean definition 。主要有两个步骤:①、加载指定的文档,得到一个Document对象。②、将Document对象和Resource交给registerBeanDefinitions(...)方法来完成注册
/** * Actually load bean definitions from the specified XML file. * @param inputSource the SAX InputSource to read from * @param resource the resource descriptor for the XML file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors * @see #doLoadDocument * @see #registerBeanDefinitions */ protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { //省略捕获异常的代码 } }
五)、XmlBeanDefinitionReader类中
注册指定的Document对象中的bean definition。这里实际上是创建了一个BeanDefinitionDocumentReader对象然后让它来完成。
/** * Register the bean definitions contained in the given DOM document. * Called by {@code loadBeanDefinitions}. * <p>Creates a new instance of the parser class and invokes * {@code registerBeanDefinitions} on it. * @param doc the DOM document * @param resource the resource descriptor (for context information) * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of parsing errors * @see #loadBeanDefinitions * @see #setDocumentReaderClass * @see BeanDefinitionDocumentReader#registerBeanDefinitions */ 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; }
二、BeanDefinition的解析
六)、DefaultBeanDefinitionDocumentReader类中
DefaultBeanDefinitionDocumentReader是BeanDefinitionDocumentReader的一个实现类。这一步主要是解析文档解析的是<beans/>。比如xml文件是XSD的还是DTD的。
这里主要是获得一个Element对象。这个对象就代表xml文件中的<beans/>节点。在这个节点下包含着文件中的所有<bean/>节点。然后将这个Element对像交给的doRegistrerBeanDefinitions(Element)方法来处理。
七)、DefaultBeanDefinitionDocumentReader类中
这个方法将</beans>节点下的每一个<bean/>相对应的bean definition注册。但是真正做这件事的是另一个方法 parseBeanDefinitions(root, this.delegate);
不过在调用parseBeanDefinitions(root,this.delegate)方法之前和之后都可以对这个这个方法参数中的Element对象进行处理。
/** * Register each bean definition within the given root {@code <beans/>} element. */ 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; 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; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
八、DefaultBeanDefinitionDocumentReader类中
用一个for循环遍历<beans/>节点下的所有子节点,也就是所有的<bean/>,然后对<bean/>节点进行解析。注意,刚才是对<beans/>进行解析。不过这个解析的任务交给parseDefaultElement(Element ele,BeanDefinitionParserDelegate delegate)方法来完成。
九)、DefaultBeanDefinitionDocumentReader类中
这个方法用到了递归,因为bean是可以嵌套的,所以<beans/>节点下的每一个<bean/>节点都可能在嵌套有很多bean。所以它会判断这个bean是不是嵌套bean,如果不是就进行处理,如果是就进行递归。
处理bean元素的任务交给了三个方法,如图。我这里用processBeanDefinition(ele,delegate)方法举例。
三、BeanDefinition的处理
十)、DefaultBeanDefinitionDocumentReader类中
在这个方法中它将的Element对象转化成了BeanDefinitionHolder对象。这个BeanDefinitionHolder对象中持有的BeanDefinition实例的引用,还有beanName,还有bean的别名。
然后将BeanDefinitionHolder对象和特定的bean工厂作为参数交个BeanDefinitionReaderUtils类来处理来进行注册。
第301行代码中如何创建BeanDefinitionHolder的??BeanDefinition的创建
四、BeanDefinition的注册
十一)、BeanDefinitionReaderUtils类中
这个方法先根据BeanDefinitionHolder获取beanName和BeanDefinition,然后将其注册到Bean工厂中Map对象中。比如bean工厂是DefaultListableBeanFactory。
上面红色方框中的代码 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());这个方法有好几个实现类实现了它,如下图:
我选择了DefaultListableBeanFactory
十二)、DefaultListableBeanFactory类中,在这个方法中,将BeanDefinition 注册到了开头所说的ConcurrentHashMap对象中了。
//--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry interface //--------------------------------------------------------------------- @Override 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); } } BeanDefinition oldBeanDefinition; oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
五、总结
BeanDefinition的加载、解析、处理、注册主要涉及到了四个类。
①、XMLBeanDefinitionReader:主要是的任务是把XML文件加载到内存中以Document对象的形式存在。
②、DefaultBeanDefinitionDocumentReader:完成解析和处理的任务。最后将处理得到的BeanDefinitionHolder交给了BeanDefinitionReaderUtils进行注册。
③、BeanDefinitionReaderUtils:BeanDefinitionHolder有了,Bean工厂也有了,它就负责把BeanDefinitionHolder中的BeanDefinition和BeanName等取出来,然后注册到Bean工厂中。
④、DefaultListableBeanFactory(bean工厂):它有一个ConcurrentHashMap成员变量,以beanName为键,BeanDefinition为值保存注册的bean。