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