spring 3源码解析之如何解析"import", "alias", "bean"标签

本文详细介绍了Spring MVC在启动过程中如何加载配置文件,并解析其中的import、alias和bean等标签,从而实现组件的注册。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解析的步骤: 
1、加载web.xml、加载监听器 
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
2、ContextLoaderListener 
初始化initWebApplicationContext方法创建 
org.springframework.web.context.support. XmlWebApplicationContext对象 
3、XmlWebApplicationContext 
调用loadBeanDefinitions方法,该方法主要做两件事情:初始化XmlBeanDefinitionReader、获取applicationContext.xml配置文件的路径、然后把事情交给XmlBeanDefinitionReader来处理 
4、XmlBeanDefinitionReader 
获取到applicationContext.xml配置文件的路径、读取配置文件的内容得到一个输入流、对输入流转码操作、然后封装成一个inputSource对象、再然后封装成一个document对象;在生成document对象的同事也生成了一个Resource对象、这两个对象分部是:document对象承载配置文件的主要内容信息、Resource承载配置文件的描述信息以及一些验证信息。 
再由Resource对象创建一个XmlReaderContext。完成了以上操作XmlBeanDefinitionReader就把document对象和XmlReaderContext对象交给DefaultBeanDefinitionDocumentReader来处理 
5、DefaultBeanDefinitionDocumentReader 
1)、对XmlReaderContext装饰成一个BeanDefinitionParserDelegate对象; 
2)、迭代document对象、把document对象拆分成Element元素逐个逐个解析; 
3)、使用BeanDefinitionParserDelegate装饰对象解析Element元素或者说标签。 
这里的Element元素有两种:一种是DefaultElement、另一种是CustomElement;DefaultElement包括alias、import、bean,CustomElement包括DefaultElement以外的所有元素 
我们所关心的应该是第一中元素DefaultElement,看下DefaultBeanDefinitionDocumentReader解析该元素的方法: 
Java代码  收藏代码
  1. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {  
  2.         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {  
  3.             importBeanDefinitionResource(ele);  
  4.         }  
  5.         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {  
  6.             processAliasRegistration(ele);  
  7.         }  
  8.         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {  
  9.             processBeanDefinition(ele, delegate);  
  10.         }  
  11.     }  


解析import标签的方法: 
Java代码  收藏代码
  1. protected void importBeanDefinitionResource(Element ele) {  
  2.         String location = ele.getAttribute(RESOURCE_ATTRIBUTE);  
  3.         if (!StringUtils.hasText(location)) {  
  4.             getReaderContext().error("Resource location must not be empty", ele);  
  5.             return;  
  6.         }  
  7.   
  8.         // Resolve system properties: e.g. "${user.dir}"  
  9.         location = SystemPropertyUtils.resolvePlaceholders(location);  
  10.   
  11.         Set<Resource> actualResources = new LinkedHashSet<Resource>(4);  
  12.   
  13.         // Discover whether the location is an absolute or relative URI   
  14.         boolean absoluteLocation = false;  
  15.         try {  
  16.             absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();  
  17.         }  
  18.         catch (URISyntaxException ex) {  
  19.             // cannot convert to an URI, considering the location relative  
  20.             // unless it is the well-known Spring prefix "classpath*:"  
  21.         }  
  22.   
  23.         // Absolute or relative?  
  24.         if (absoluteLocation) {  
  25.             try {  
  26.                 int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);  
  27.                 if (logger.isDebugEnabled()) {  
  28.                     logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");  
  29.                 }  
  30.             }  
  31.             catch (BeanDefinitionStoreException ex) {  
  32.                 getReaderContext().error(  
  33.                         "Failed to import bean definitions from URL location [" + location + "]", ele, ex);  
  34.             }  
  35.         }  
  36.         else {  
  37.             // No URL -> considering resource location as relative to the current file.  
  38.             try {  
  39.                 int importCount;  
  40.                 Resource relativeResource = getReaderContext().getResource().createRelative(location);  
  41.                 if (relativeResource.exists()) {  
  42.                     importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);  
  43.                     actualResources.add(relativeResource);  
  44.                 }  
  45.                 else {  
  46.                     String baseLocation = getReaderContext().getResource().getURL().toString();  
  47.                     importCount = getReaderContext().getReader().loadBeanDefinitions(  
  48.                             StringUtils.applyRelativePath(baseLocation, location), actualResources);  
  49.                 }  
  50.                 if (logger.isDebugEnabled()) {  
  51.                     logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");  
  52.                 }  
  53.             }  
  54.             catch (IOException ex) {  
  55.                 getReaderContext().error("Failed to resolve current resource location", ele, ex);  
  56.             }  
  57.             catch (BeanDefinitionStoreException ex) {  
  58.                 getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",  
  59.                         ele, ex);  
  60.             }  
  61.         }  
  62.         Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);  
  63.         getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));  
  64.     }  

解析alias标签的方法: 
Java代码  收藏代码
  1. protected void processAliasRegistration(Element ele) {  
  2.     String name = ele.getAttribute(NAME_ATTRIBUTE);  
  3.     String alias = ele.getAttribute(ALIAS_ATTRIBUTE);  
  4.     boolean valid = true;  
  5.     if (!StringUtils.hasText(name)) {  
  6.         getReaderContext().error("Name must not be empty", ele);  
  7.         valid = false;  
  8.     }  
  9.     if (!StringUtils.hasText(alias)) {  
  10.         getReaderContext().error("Alias must not be empty", ele);  
  11.         valid = false;  
  12.     }  
  13.     if (valid) {  
  14.         try {  
  15.             getReaderContext().getRegistry().registerAlias(name, alias);  
  16.         }  
  17.         catch (Exception ex) {  
  18.             getReaderContext().error("Failed to register alias '" + alias +  
  19.                     "' for bean with name '" + name + "'", ele, ex);  
  20.         }  
  21.         getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));  
  22.     }  
  23. }  

解析bean标签的方法: 
Java代码  收藏代码
  1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {  
  2.     BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  
  3.     if (bdHolder != null) {  
  4.         bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  
  5.         try {  
  6.             // Register the final decorated instance.  
  7.             BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  
  8.         }  
  9.         catch (BeanDefinitionStoreException ex) {  
  10.             getReaderContext().error("Failed to register bean definition with name '" +  
  11.                     bdHolder.getBeanName() + "'", ele, ex);  
  12.         }  
  13.         // Send registration event.  
  14.         getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  
  15.     }  
  16. }  


方法调用关系图: 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值