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