obtainFreshBeanFactory()方法概述

定义BeanFactory,并加载以下两种bean的定义,装配到BeanFactory:

1.配置文件中定义的bean

2.通过<context:component-scan base-package="..." />配置的路径下的,且经过相应注解标注的所有类,注解包括:@Controller、@Service、@Component、@Repository

源码解读

主要流程总结:

1.创建BeanFactory:DefaultListableBeanFactory

2.解析web.xml配置,读取spring配置文件,封装为Resource对象

3.把Resource对象封装为Document对象

4.开始层层遍历Document的节点。

以下是细节:

先来看该方法的实现,注:这里会把无关代码删掉,以方便阅读。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新bean工厂
     this.refreshBeanFactory();
    //创建bean工厂
    return this.getBeanFactory();
 } 

重点看刷新bean工厂部分:

protected final void refreshBeanFactory() throws BeansException {
       //创建bean工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
       //这里加载beanDefinition,并赋给bean工厂
       loadBeanDefinitions(beanFactory);
}
createBeanFactory()好理解,就是new了个工厂对象。
有了工厂对象后,就需要往里面装载东西,装什么呢?这里是

接下来看loadBeanDefinitions(beanFactory)方法的具体实现:创建xml文件读取器

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 以下这一堆内容就是为了准备一个xml文件读取器,仅作了解
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
     beanDefinitionReader.setEnvironment(this.getEnvironment());
     beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));   initBeanDefinitionReader(beanDefinitionReader);
    //这里才是核心,加载beanDefinition的工作还没开始
loadBeanDefinitions(beanDefinitionReader);
}

继续跟进去,这里依然“没干正事”:加载spring配置文件

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
  //核心代码
    reader.loadBeanDefinitions(configLocations);
}
}

接着看核心代码

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader instanceof ResourcePatternResolver) {
// 通配符模式匹配资源,转换为Resource对象。spring提供了多种ResourceLoader,根据通配符匹配,生成对应类型的Resource
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
          //【继续把加载工作往后放】
          int loadCount = loadBeanDefinitions(resources);return loadCount;
}
}
else {
// 以绝对路径加载单个资源文件,转换为Resource对象
Resource resource = resourceLoader.getResource(location);
       //【继续把加载工作往后放】
int loadCount = loadBeanDefinitions(resource);return loadCount;
}
}

通过上面一步,把配置资源转化为Resource对象,然后作为参数传入loadxxx方法里进行解析。

进入下面的实现发现,依然在做准备工作:将Resource读取为流

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
//
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//终于到do...是不是这里就开始真正的执行加载了?
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}

来看下,删除非核心代码,就做了两件事,先读取资源对象Resource,封装成Document对象;再“注册”beanDefinition。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
    //生成Document对象
Document doc = doLoadDocument(inputSource, resource);
        //注册BeanDefinition
return registerBeanDefinitions(doc, resource); }

中间又经历了n个准备环境,最终进入方法parseBeanDefinitions,拿到了Document对象的根节点,开始调用解析方法解析节点:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}

具体的解析逻辑,可以参考以下文章:https://blog.csdn.net/v123411739/article/details/86669952

BeanDefinition包含的主要内容:

@todo

解析完成后,依然是注入到BeanFactory中缓存起来,供后续使用,主要的内容是两部分:

1.beanDefinitionNames

2.beanDefinitionMap

总结:

obtainFreshBeanFactory()方法的主要作用:
1.创建beanFactory
2.根据web.xml中contextConfigLocation配置的路径,读取Spring配置文件,封装为Resource
3.根据Resource加载XML配置文件(bean文件)并解析为Document对象
4.遍历Document,解析为beanDefinition。

最新文章

  1. c 语言的位运算符复习
  2. Css中的Position属性
  3. 用PowerMock mock 临时变量
  4. HBase配置项详解
  5. C++中int,float,string,char*的转换(待续)
  6. Caffe 源碼閱讀(二) SyncedMemory.hpp
  7. animation of android (3)
  8. [ActionScript 3.0] AS3 绘制12面体
  9. django的模板页面里,如何获取一个集合的数据?
  10. u-boot Makefile整体解析
  11. Mongodb数据更新命令
  12. 根据反射获取属性信息并创建DataTable
  13. scala 异常处理机制
  14. CARVARS 圆形进度条
  15. ABP文档笔记 - 通知
  16. B+树的Copy-on-Write设计
  17. VS2017 异常 Editor or Editor Extension
  18. excel vba 不可查看
  19. HDU 6020---MG loves apple(枚举)
  20. c# 简易绘制C语言头文件包含关系图 v2.0

热门文章

  1. 020_CSS3
  2. Redis常用数据类型及其存储结构(源码篇)
  3. TypeError: Object of type &#39;datetime&#39; is not JSON serializable
  4. 将日志发送到log日志文件中
  5. 如何让别人访问我的电脑的vue项目
  6. C++Template 模版的本质
  7. JavaScript:什么是回调?
  8. Django3.0 + nginx + uwsgi 部署
  9. arch 安装笔记
  10. POJ-2253(最短路变形+dijikstra算法+求解所有路径中所有最长边中的一个最小值)