Spring源码深度解析(郝佳)-学习-源码解析-import标签

20 篇文章 1 订阅
18 篇文章 0 订阅

Boss.java

@Data
public class Boss {
    private Car car;
}

Car.java

@Data
public class Car {
    private Long id ;
    private String brand;
    private int maxSpeed;
}

spring30_child.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
       
    <import resource="classpath:spring_1_100/config_21_30/spring30_import_resource/spring30_parent.xml"></import>
    
    <bean id="boss" class="com.spring_1_100.test_21_30.test30_import_resource.Boss" p:car-ref="car"></bean>
</beans>

测试:

public class Test30 {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring_1_100/config_21_30/spring30_import_resource/spring30_child.xml");
        Boss boss = (Boss) ac.getBean("boss");
        System.out.println(JSON.toJSONString(boss));
    }
}

结果输出:
在这里插入图片描述

DefaultBeanDefinitionDocumentReader.java

protected void importBeanDefinitionResource(Element ele) {
  //  获取 resource 属性
  String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
  //如果导入元素的location属性值为空,则没有导入任何资源,直接返回 | 如果不存在resource属性则不做任何处理
  if (!StringUtils.hasText(location)) {
    getReaderContext().error("Resource location must not be empty", ele);
    return;
  }

  // Resolve system properties: e.g. "${user.dir}"
  // 使用系统变量值解析location属性值 |  解析系统属性,格式如:"${user.dir}"
  location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

  Set actualResources = new LinkedHashSet(4);

  // Discover whether the location is an absolute or relative URI
  // 判断 location 属性是绝对 URI 还是相对 URI
  boolean absoluteLocation = false;
  try {
    absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
  }
  catch (URISyntaxException ex) {
    // 给定导入元素的location属性值不是绝对路径
    // cannot convert to an URI, considering the location relative
    // unless it is the well-known Spring prefix "classpath*:"
  }

  // Absolute or relative?
  // 如果是绝对 URI 则直接根据地址加载对应的配置文件
  if (absoluteLocation) {
    try {
      // 使用资源读入器加载给定路径的bean资源
      int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
      if (logger.isDebugEnabled()) {
        logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
      }
    }
    catch (BeanDefinitionStoreException ex) {
      getReaderContext().error(
          "Failed to import bean definitions from URL location [" + location + "]", ele, ex);
    }
  }
  else {
    // No URL -> considering resource location as relative to the current file.
    // 如果是相对地址,则根据相对地址计算出绝对地址
    try {
      int importCount;
      // resource 存在多个子实现类,如 VfsResource,FileSystemResource 等
      // 而每个 resource 的 createRelative 方法实现都不一样,所以这里先使用子类的方法尝试解析
      Resource relativeResource = getReaderContext().getResource().createRelative(location);
      // 封装的相对路径资源存在
      if (relativeResource.exists()) {
        // 使用资源读入器加载Bean的资源
        importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
        actualResources.add(relativeResource);
      }
      // 封装的相对路径资源不存在
      else {
        // 如果解析不成功,则使用默认的解析器 ResourcePatternResolver 进行解析
        String baseLocation = getReaderContext().getResource().getURL().toString();
        // 根据Spring IOc容器读入器的基本路加载给定导入路径的资源路径
        importCount = getReaderContext().getReader().loadBeanDefinitions(
            StringUtils.applyRelativePath(baseLocation, location), actualResources);
      }
      if (logger.isDebugEnabled()) {
        logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
      }
    }
    catch (IOException ex) {
      getReaderContext().error("Failed to resolve current resource location", ele, ex);
    }
    catch (BeanDefinitionStoreException ex) {
      getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
          ele, ex);
    }
  }
  //解析后进行监听器激活处理
  Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
  // 在解析完成元素之后,发送容器导入其他资源处理完成事件
  getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}

这个代码不难,相信配置注释会很好的理解,我们总结一下大致的流程便于读者更好的梳理,在解析<import标签时,Spring进行解析的步骤大致如下

  • 1.获取resource属性所表示的路径
  • 2.解析路径中的系统属性,格式如"${user.dir}"
  • 3.判断location是绝对路径还是相对路径
  • 4.如果是绝对路径则递归调用bean的解析过程,进行另一次的解析
  • 5.如果是相对路径则计算出绝对路径并返回
  • 6.通知监听器,解析完成

bean的创建,这里就不做过多的缀述了。如果有兴趣,可以去看看我之前的博客

本文 github 地址
https://github.com/quyixiao/spring_tiny/blob/master/src/main/java/com/spring_1_100/test_21_30/test30_import_resource

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值