05document转为BeanDefinition并注册过程
接着之前的文章4继续分析,文章4里的步骤三的C_3里调用xmlReader(XmlBeanDefinitionReader)的
doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法,该方法最后一行进入
registerBeanDefinitions(doc, resource)方法里,该方法最终调用他的好友
documentReader.registerBeanDefinitions(doc, createReaderContext(resource))方法
Ⅰ、代码流程
一、程序入口位于documentReader的registerBeanDefinitions方法 //DefaultBeanDefinitionDocumentReader.registerBeanDefinitions public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement();//获得docuemnt的根元素 doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { //1、检查根节点的profile属性 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { //this.environment就是beanFactory的environment即StandardEnvironment Assert.state(this.environment != null, "Environment must be set for evaluating profiles"); //解析得到比如dev,uat这样的数组 String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); //让environment去判断spring.profiles.active或SPRING_PROFILES_ACTIVE的值是否包含dev(uat), //包含说明当前整个xml是active的,可以继续,否则直接return if (!this.environment.acceptsProfiles(specifiedProfiles)) { return; } } //2、创建委托对象,交给委托对象解析<beans>标签 // 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;//表面上看该属性为空,但是当 //<beans>里面嵌套有<beans>时会引起递归调用当前方法,此时该属性不为空,该对象 //表示上次解析<beans>时的委托对象,每一个delegate对象对应一个<beans>标签, //当存在内外嵌套<beans>场景时,内层的部分属性继承外层的,所以递归到内层 //<beans>时要拿到外层的delegate对象做相关处理 this.delegate = createDelegate(this.readerContext, root, parent);//就是BeanDefinitionParserDelegate preProcessXml(root);//模板空方法,允许开发者覆盖之后,实现在解析document之前先解析xml里的自定义标签 parseBeanDefinitions(root, this.delegate); postProcessXml(root);//同preProcessXml,也是空方法,实现扩展功能用 this.delegate = parent; } protected BeanDefinitionParserDelegate createDelegate( XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { //这句createHelper方法创建了个寂寞 BeanDefinitionParserDelegate delegate = createHelper(readerContext, root, parentDelegate); if (delegate == null) { delegate = new BeanDefinitionParserDelegate(readerContext, this.environment); delegate.initDefaults(root, parentDelegate); } return delegate; } @Deprecated protected BeanDefinitionParserDelegate createHelper( XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { return null; } 二、documentReader开始解析root节点 delegate作为documentReader的助手角色参与其中 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //如果是默认命名空间 if (delegate.isDefaultNamespace(root)) {//正常进入该分支 NodeList nl = root.getChildNodes(); //遍历<beans>下的所有节点 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); } } //delegate.isDefaultNamespace public boolean isDefaultNamespace(Node node) { return isDefaultNamespace(getNamespaceURI(node)); } //delegate.getNamespaceURI public String getNamespaceURI(Node node) { return node.getNamespaceURI();//比如当前是<beans>则返回http://www.springframework.org/schema/beans } //delegate.isDefaultNamespace public boolean isDefaultNamespace(String namespaceUri) { return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri)); //内部有个常量public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans"; } 三、documentReader开始解析root下的子节点,比如<bean>、<import>、<alise>、<beans> 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)) { // recurse doRegisterBeanDefinitions(ele);//这里就会递归到上面步骤一的doRegisterBeanDefinitions方法里 } } protected void importBeanDefinitionResource(Element ele) { //1、解析import标签的resource属性得到被引入xml的路径字符串 String location = ele.getAttribute(RESOURCE_ATTRIBUTE); //2、利用environment把带有占位符的路径字符串变成真正的路径字符串 location = environment.resolveRequiredPlaceholders(location); //3、借助之前的xmlReader去再次解析xml //context类似threadLocal用法,该上下文里的reader就是xmlReader,等于 //程序执行流程又回到了文章4的步骤6的第三个loadBeanDefinitions方法。 int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); //4、发出事件,触发关心者去处理import事件,暂时不考虑那么细,略 getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); } //暂时略 protected void processAliasRegistration(Element ele) { } 四、documentReader开始解析<bean>节点,交给助手delegate去做 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //1、交给delegate去解析<bean>节点,注意这里得到的是holder对象 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { //2、判断如果有自定义属性调用自定义处理器装饰下bdHolder对象 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); //decorateBeanDefinitionIfRequired方法里判断如果当前<bean>存在自定义 //属性,则调用NamespaceHandlerResolver对象根据自定义属性的命名空间得到 //NamespaceHandler命名空间处理器,用该处理器解析属性得到被装饰后的 //holder对象(就是上面bdHolder,等于这里调用开发者的处理器把bdHolder进行处理了) //该方法代码见附录1 try { //3、注册bdHolder到beanFactory里,getReaderContext().getRegistry()是beanFactory,最终修改如下内存,到此doc变为BeanDefinition对象流程结束。 beanFactory bd属性 |-beanDefinitionMap 类型Map<String, BeanDefinition>,key是beanName,value是bd对象 |-beanDefinitionNames 类型List<String>,元素是beanName // 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)); } } 五、delegate开始解析<bean>标签 //delegate.parseBeanDefinitionElement(ele) public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } //delegate.parseBeanDefinitionElement(ele, containingBean) public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { //1、解析id和name属性 String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); //2、判断name属性如果带逗号说明是别名,分割后加入别名list List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } //3、如果id为空并且别名list不为空时,取第一个别名作为beanName 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"); } } //4、检查beanName必须唯一,不唯一就报错 if (containingBean == null) {//正常进入该分支 checkNameUniqueness(beanName, aliases, ele);//通过usedNames检查beanName是否唯一 } //5、得到Definition对象 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) {//正常不会进入该分支,如果xml里去掉id="person"则进入这里 try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition);//DefaultBeanNameGenerator.generateBeanName-->BeanDefinitionReaderUtils.generateBeanName内部规则为class完全限定名learn.dto.Person+#+序号,这里是learn.dto.Person#0 //为了向后兼容,用完全限定名作为别名,这里beanClassName是learn.dto.Person // 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);//beanClassName是learn.dto.Person } } 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); //6、返回holder,即BeanDefinitionHolder对象。 //BeanDefinitionHolder参见:https://blog.csdn.net/cgsyck/article/details/88880196 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; } public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { //1、parseState是模仿栈的数据结构,用于记录当前解析进度,方便错误信息输出,略 this.parseState.push(new BeanEntry(beanName)); //2、解析节点的class属性 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { //3、解析节点的parent属性 String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } //4、创建BeanDefinition实例对象 AbstractBeanDefinition bd = createBeanDefinition(className, parent);//就是new GenericBeanDefinition //5、解析节点的scope、singleton、abstrace、lazy-init、autowire、dependency-check、 //depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method、 //factory-bean属性,把这些属性的值设置到bd的相应属性里。 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);//方法代码下面不列了 //6、解析节点下的<description>子节点,把该子节点的值设置到相应属性里 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //7、解析节点下的子节点的标签值是否等于meta,没细看,暂时略 parseMetaElements(ele, bd); //8、解析节点下的子节点的标签值是否等于lookup-method,暂时略 //参见:https://blog.csdn.net/weixin_46909938/article/details/138535529 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //9、解析节点下的子节点的标签值是否等于replaced-method,暂时略 //参见:https://www.jianshu.com/p/06f71d241866 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //10、解析构造参数 parseConstructorArgElements(ele, bd); //11、解析bean的属性 parsePropertyElements(ele, bd); //12、解析qualifier子元素,暂时略 parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource());//这个Resource对象就是applicationContext //一开始把路径字符串得到的Resource对象 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; } protected AbstractBeanDefinition createBeanDefinition(String className, String parentName){ return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader()); //this.readerContext.getBeanClassLoader()就是xmlReader.getBeanClassLoader(),此处 //的ClassLoader为null } //BeanDefinitionReaderUtils.createBeanDefinition() public static AbstractBeanDefinition createBeanDefinition( String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setParentName(parentName); if (className != null) { if (classLoader != null) { bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else {//正常走这个分支 bd.setBeanClassName(className); } } return bd; } 六、beanFactory注册BeanDefinition //BeanDefinitionReaderUtils.registerBeanDefinition public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); //调用beanFactory对象的方法来进行注册,详细参见附录2 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); } } }
Ⅱ、总结:
spring框架通过documentReader和delegate完成了document到BeanDefinition的转换工作。
附录:
1、delegate对象的装饰bdHolder对象方法
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) { return decorateBeanDefinitionIfRequired(ele, definitionHolder, null); } public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) { BeanDefinitionHolder finalDefinition = definitionHolder; // Decorate based on custom attributes first. NamedNodeMap attributes = ele.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node node = attributes.item(i); finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } // Decorate based on custom nested elements. NodeList children = ele.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } } return finalDefinition; }
2、beanFactory注册beanDefinition过程
//DefaultListableBeanFactory.registerBeanDefinition 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"); //1、校验bd对象是否有效 //GenericBeanDefinition父类是AbstractBeanDefinition,所以会进入该分支 if (beanDefinition instanceof AbstractBeanDefinition) { try { //validate方法内部校验规则 //1、为不能同时存在“方法覆盖methodOverrides”和“factoryMethodName”这两种配置项, //2、如果配了方法覆盖,校验要覆盖的方法名在对应bean的class里有没有,没有报错 ((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); //按道理应该为null,想不到什么场景下会不为null 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);//加入到beanDefinitionNames this.frozenBeanDefinitionNames = null; } this.beanDefinitionMap.put(beanName, beanDefinition);//加入到beanDefinitionMap } //重置当前bean resetBeanDefinition(beanName); } //重置当前bean,即清空缓存 protected void resetBeanDefinition(String beanName) { //1、这个不清楚,暂时略 // Remove the merged bean definition for the given bean, if already created. clearMergedBeanDefinition(beanName); // Remove corresponding bean from singleton cache, if any. Shouldn't usually // be necessary, rather just meant for overriding a context's default beans // (e.g. the default StaticMessageSource in a StaticApplicationContext). //2、从缓存里销毁bean实例 destroySingleton(beanName); //3、清空allBeanNamesByType和singletonBeanNamesByType // Remove any assumptions about by-type mappings. clearByTypeCache();//->this.allBeanNamesByType.clear();this.singletonBeanNamesByType.clear(); //4、把当前bean所有子递归的进行重置操作 // Reset all bean definitions that have the given bean as parent (recursively). for (String bdName : this.beanDefinitionNames) { if (!beanName.equals(bdName)) { BeanDefinition bd = this.beanDefinitionMap.get(bdName); if (beanName.equals(bd.getParentName())) { resetBeanDefinition(bdName); } } } } protected void clearMergedBeanDefinition(String beanName) { this.mergedBeanDefinitions.remove(beanName); } public void destroySingleton(String beanName) { // Remove a registered singleton of the given name, if any. removeSingleton(beanName); // Destroy the corresponding DisposableBean instance. DisposableBean disposableBean; synchronized (this.disposableBeans) { disposableBean = (DisposableBean) this.disposableBeans.remove(beanName); } destroyBean(beanName, disposableBean); } protected void removeSingleton(String beanName) { synchronized (this.singletonObjects) { this.singletonObjects.remove(beanName); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.remove(beanName); } } private void clearByTypeCache() { this.allBeanNamesByType.clear(); this.singletonBeanNamesByType.clear(); }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战