注:1.本文内容不是很细致,只能帮助大家了解个大概流程-_-||
2.方法里会删减无关的内容
spring beanDefinition加载,在方法obtainFreshBeanFactory中完成
refreshBeanFactory方法
createBeanFactory:创建容器,会获取parent容器作为参数传入
loadBeanDefinition:先创建beanDefinitionReader
获取resource,也就是配置的xml文件
将resource读入,解析成document对象
主要方法在这,传入doc节点,开始解析
parseDefaultElement方法解析标签import、alias、bean、beans四种
import解析
获取标签中resource的值,会根据location是否是绝对路径,走不同的分支。
将location解析为resource后,递归对该resource执行loadBeanDefinitions方法,
protected void importBeanDefinitionResource(Element ele) {
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
boolean absoluteLocation = false;
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
if (absoluteLocation) {
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
}
else {
Resource relativeResource = getReaderContext().getResource().createRelative(location);
if (relativeResource.exists()) {
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
else {
String baseLocation = getReaderContext().getResource().getURL().toString();
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
}
Resource[] actResArray = actualResources.toArray(new Resource[0]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
alias解析
读取name、alias两个属性的值
1.如果alias和name相同,则aliasMap中移除这个alias。
2.根据alias查询aliasmap中是否已存在,已存在并且name相同则不再处理,已存在但name不同,则根据是否允许alias覆盖(allowAliasOverriding),来决定是否抛出异常。
3.检查name是否已经存在alias,存在则抛异常
bean标签解析
将元素转为BeanDefinitionHolder,注册beanDefinition
1.获取bean标签中的id、name属性的值
2.name不为空,则根据逗号、分号将name分割为数组
3.如果没有设置id,但是设置了name,会取第一个name作为beanName
4.检查beanName唯一性
5.parseBeanDefinitionElement方法会解析标签中的属性,并对beanDefinition进行赋值
6.beanName为空,则会产生一个,还会放入aliasmap。规则:class全路径名称+#+数字(从0开始自增,如果存在则继续下一个数字)
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
beans标签解析
递归过程,不再描述
以上是parseDefaultElement解析过程,只解析标签beans、bean、alias、import四种
其余例如aop标签解析,则在下面方法中。
获取namespaceurl,也就是
根据namespaceurl找到相应的handler
再根据具体的标签名,找到parser
具体的解析过程都在parser的parse方法里,例如component-scan
先找base-package属性的值,
调用scan方法,先找出包下的所有类,再根据类上的注解@Component、@ManagedBean进行筛选,注册到容器中
其余标签解析也是这个流程,大家可以自行debug看看