@huangyichun
        
        2017-07-25T01:29:50.000000Z
        字数 16495
        阅读 1138
    Spring
注意该源码基于Spring 3.2版本分析的
public class MyTestBean {private String testStr = "testStr";public String getTestStr() {return testStr;}public void setTestStr(String testStr) {this.testStr = testStr;}}
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="myTestBean" class="chapter2.MyTestBean"/></beans>
public class BeanFactoryTest {@Testpublic void testSimpleLoad() {ClassPathResource resource = new ClassPathResource("MyTestBean.xml");DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);reader.loadBeanDefinitions(resource);MyTestBean bean = (MyTestBean) beanFactory.getBean("myTestBean");Assert.assertEquals("testStr", bean.getTestStr());}}
总体时序图:
上面是Bean加载,解析,注册的时序图,下面先认识一些类的作用:
BeanDefinitionReader: 主要定义资源文件读取并转换为BeanDefinition的各个功能。
DocumentLoader: 定义从资源文件加载到转换为Document的功能
BeanDefinitionDocumentReader: 定义读取Document并注册BeanDefition功能
BeanDefinitionParseDelegate:定义解析Element的各种方法
BeanDefinitionReaderUtil:提供BeanDefinition的一些操作方法
BeanDefinitionRegistry: 定义对BeanDefinition的各种增删改查
DefaultListableBeanFactory: Spring Ioc容器的一种,同时也是实现了BeanDefinitionRegistry接口
//loadBeanDefinitions的具体实现,而EncodedResource主要用于对资源文件的处理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());}//检查是否重复加载xml配置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!");}// 调用DefaultResourceLoader的getResources方法完成具体的Resource定位try {//从EncodedResource中获取已经封装的Resource对象并再次从Resource中获取inputStreamInputStream 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();}}}/*** 真正的核心处理部分* 如果不考虑冗余的代码,其实只做三件事:* 1.获取XML文件的验证模式* 2.加载XML,并获取Document.* 3.返回的Document,注册Bean*/protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {//获取XML验证模式,默认为XSDint validationMode = getValidationModeForResource(resource);// 取得XML文件的Document对象, 这个解析过程由DefaultDocumentLoader完成Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());// 启动对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);}}
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);if (logger.isDebugEnabled()) {logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");}DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);//解析Xml文件,返回Documentreturn builder.parse(inputSource);}
通过上面的过程已经完成了XML文件的加载,并且转换成document,接下来是提取和注册Bean。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {//获取DefaultBeanDefinitionDocumentReader对Xml的BeanDefiniton进行解析BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();//设置环境变量documentReader.setEnvironment(this.getEnvironment());//记录统计前BeanDefinition的加载个数int countBefore = getRegistry().getBeanDefinitionCount();//核心代码,加载及注册beandocumentReader.registerBeanDefinitions(doc, createReaderContext(resource));//返回本次加载的BeanDefinition个数return getRegistry().getBeanDefinitionCount() - countBefore;}
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;logger.debug("Loading bean definitions");//获取document的rootElement root = doc.getDocumentElement();doRegisterBeanDefinitions(root);//核心代码}//--------------------------------------------------------protected void doRegisterBeanDefinitions(Element root) {String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if (StringUtils.hasText(profileSpec)) {Assert.state(this.environment != null, "environment property must not be null");//处理root的profile属性,Spring存在两套配置方案,开发时和生产时,分别使用<beans profile="dev">...</beans>和<beans profile="product">..</beans>来进行配置String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);if (!this.environment.acceptsProfiles(specifiedProfiles)) {return;}}//该类主要负责定义解析Element的各种方法BeanDefinitionParserDelegate parent = this.delegate;this.delegate = createHelper(readerContext, root, parent);// 解析Bean定义之前, 增强解析过程的可扩展性preProcessXml(root);parseBeanDefinitions(root, this.delegate);//核心代码// 解析Bean定义之后, 增强解析过程的可扩展性postProcessXml(root);this.delegate = parent;}protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {// 获取Document对象根元素的所有子节点并循环解析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)) {// 解析Spring的Bean规则默认元素节点parseDefaultElement(ele, delegate);}else {//解析自定义节点元素delegate.parseCustomElement(ele);}}}}else {// 解析自定义元素根节点delegate.parseCustomElement(root);}}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);//Bean处理的核心代码}// 解析内嵌beans元素, 作为根节点递归解析else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// 递归解析doRegisterBeanDefinitions(ele);}}
从代码可直接看出,Spring首先获取Document的根元素,然后取得根元素所有的子节点并循环解析这些子节点;如果子节点在Spring默认的命名空间内,则按照Spring Bean定义规则来解析,否则按照自定义的节点解析。在按照Spring Bean定义规则进行解析的parseDefaultElement方法中,完成了对< import/>、< alias/>、< bean/>、< beans/>等元素的解析。
BeanDefinitionParserDelegate类,主要定义了Spring默认的标签并且提供了Element的解析方法
这里只关注Spring对< bean >元素的解析过程
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {// 具体的解析委托给BeanDefinitionParserDelegate来完成// BeanDefinitionHolder是BeanDefinition的封装类, 封装了BeanDefinition、Bean的名字和别名, 用它来完成向IoC容器注册.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));}}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {return parseBeanDefinitionElement(ele, null);}public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {// 解析Bean定义资源文件中的<Bean>元素,主要处理<Bean>元素的id,name和aliase属性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, MULTI_VALUE_ATTRIBUTE_DELIMITERS);aliases.addAll(Arrays.asList(nameArr));}String beanName = id;// 如果<Bean>元素中没有配置id属性时, 将别名中的第一个值赋值给beanNameif (!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);//为解析的Bean使用别名注册时, 为了向后兼容(Spring1.2/2.0给别名添加类名后缀)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;}//该方法解析Bean生成一个BeanDefinitionpublic AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {this.parseState.push(new BeanEntry(beanName));// 这里只读取<Bean>元素中配置的class名字, 然后载入到BeanDefinition中去// 只是记录配置的class名字, 并不实例化, 对象的实例化在依赖注入时完成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);}// 根据<Bean>元素配置的class名称和parent属性值创建BeanDefinition, 为载入Bean定义信息做准备AbstractBeanDefinition bd = createBeanDefinition(className, parent);// 对当前<Bean>元素中配置的一些属性进行解析, 如singleton、abstract等parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));// 对<Bean>元素的meta(元数据)、lookup-method、replaced-method等子元素进行解析parseMetaElements(ele, bd);parseLookupOverrideSubElements(ele, bd.getMethodOverrides());parseReplacedMethodSubElements(ele, bd.getMethodOverrides());parseConstructorArgElements(ele, bd);// 解析<Bean>元素的构造方法参数parsePropertyElements(ele, bd);// 解析<Bean>元素的<property>设置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;}
从上面分析可以看出,BeanDefinition就被载入到IoC容器后,就可以在容器中建立了数据映射了,剩下的就是BeanDefinition注册了。
该方法在上面已经分析过了,主要是将bean元素解析为BeanDefinition,并且将返回的BeanDefinition封装为BeanDefinitionHolder交给Ioc容器进行处理
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());//注册BeanDefinition}catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name '" +bdHolder.getBeanName() + "'", ele, ex);}// Send registration event.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));}}
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {// Register bean definition under primary name.String beanName = definitionHolder.getBeanName();// 向IoC容器注册BeanDefinitionregistry.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);}}}
这里的registry是DefaultListableBeanFactory,我们可以从下面的调用看出 

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");// 对解析得到的BeanDefinition校验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);//将beanDefinition放入map容器中}resetBeanDefinition(beanName);}//这个是Ioc容器中Bean的存储位置private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
以上是简单的Ioc容器bean解析,注册的所有过程。
总结下以上步骤:
使用ResourceLoader将配置文件读取为Resource,这里使用的是ClassPathLoader进行读取的。Resource代表着Spring的资源文件
调用DefaultDocumentLoader的loadDocument()方法,返回一个Document对象
调用DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法解析上面得到的document对象,具体的Element交给BeanDefinitionParserDelegate进行解析,得到BeanDefinitionHolder对象
使用BeanDefinitionReaderUtils的registerBeanDefinition注册上面的BeanDefinitionHolder对象,实际是将BeanDefinition注册到DefaultListableBeanFactory的ConcurrentHashMap对象中