您现在的位置是:首页 >技术杂谈 >Spring : XML配置 JavaBean源码解析网站首页技术杂谈
Spring : XML配置 JavaBean源码解析
前言
跟着大佬走!!!! https://github.com/DerekYRC/mini-spring
提示:以下是本篇文章正文内容,下面案例可供参考
一、xml 加载 Bean 对象
大家先了解一下这个图,是作者给的定义
正片开始
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:factory-bean.xml");
获取一个应用程序上下文对象,里面加载了xml 文件,最后将 xml 文件的对象取出,这里对应我们刚开始学 Spring 使用 xml 配置bean 对象。
接下来我们一步步 deBug 深入大佬源码。我会先上图再给注释,上图下描述,DeBug 走起。
先来到集成图的最下面
ClassPathXmlApplicationContext
,这里调用有参构造ClassPathXmlApplicationContext
传入了xml文件名,然后把 classpath:factory-bean.xml 转换成了一个 String 数组,扔给了另一个重载的 有参构造。
到了个有参构造,把 configLocations 文件名数组,赋值给了全局变量 this.configLocations (也是一个字符串数组)。然后会调用 refresh( ) 方法,
refresh( ) 会来到
AbstractApplicationContext
, 会先调用refreshBeanFactory()
方法刷新 bean 工厂,所有会去到子类。
来到子类
AbstractRefreshableApplicationContext
的 refreshBeanFactory() 方法, 会先调用createBeanFactory();
创建默认的 bean 工厂,然后将 工厂扔给了loadBeanDefinitions(beanFactory);
方法,加载 bean定义。
DefaultListableBeanFactory beanFactory = createBeanFactory(); 调用本类方法,创建默认的 bean 工厂
return new DefaultListableBeanFactory(); 会来到
DefaultSingletonBeanRegistry
由于
DefaultListableBeanFactory
集成了三个类,这里要对继承的类进行初始化操作,子类初始化,要先将父类进行加载。
拥有了默认的 bean 工厂后,将工厂扔给 本类的
loadBeanDefinitions(beanFactory);
,但是这是一个抽象方法,还是要到子类进行查看。
值得我们注意的是,这个方法还是抽象方法,由子类进行实现。我们还要跟着去子类,但是这一跟就会回到一开始 debug 的地方。
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory, this);
会去创建 一个 XmlBeanDefinitionReade 对象
总结XML加载Bean对象
首先我们先记住三个继承图
XML文件配置JavaBean要从一个
new ClassPathXmlApplicationContext("classpath:factory-bean.xml");
开始读取XML文件。这个最终继承到AbstractApplicationContext
,当我们传入xml文件时,会先将 文件名转换成一个数组,调用ClassPathXmlApplicationContext的重载方法,传入这个数组,然后依次加载父类,AbstractXmlApplicationContext
,AbstractRefreshableApplicationContext
,AbstractApplicationContext
,DefaultResourceLoader
, 初始化子类需要先加载父类,然后将文件数组赋值给成员变量 private String[] configLocations; 以便于后续获取这个文件名。
然后会调用 refresh(); 方法,这个方法会调用到 AbstractApplicationContext 的 refresh(); 方法 然后执行 refreshBeanFactory();
//创建BeanFactory,并加载BeanDefinition
但是这是个抽象方法 abstract ,需要到子类AbstractRefreshableApplicationContext
去查看,就会到 AbstractRefreshableApplicationContext 对象的 refreshBeanFactory() 方法,会获取到一个DefaultListableBeanFactory
对象, 默认的Bean工厂。
然后就是创建默认 Bean工厂(
第二张继承图
),这时由于 DefaultListableBeanFactory 还是最底层的类,初始化之前,还要去初始化父类,父类依次是AbstractAutowireCapableBeanFactory
,AbstractBeanFactory
,DefaultSingletonBeanRegistry
,到 DefaultSingletonBeanRegistry 会依次加载 Spring 的三级缓存对于Spring的三级缓存,可自行搜索了解
,和一个任意处理的 Bean容器 Map<String, DisposableBean> disposableBeans。然后一路返回到 DefaultListableBeanFactory 默认Bean工厂,返回的路上还会初始化父类的成员属性。
然后会调用 loadBeanDefinitions(beanFactory); 把这个默认的 bean工厂扔进去,很不巧的是,这个还是个抽象方法,就会到AbstractRefreshableApplicationContext
的子类AbstractXmlApplicationContext
来到
AbstractXmlApplicationContext
的 loadBeanDefinitions()方法,会得到一个XmlBeanDefinitionReader 对象
(第三张继承图
),这个对象用来整个前两个继承图的两个体系,在 new XmlBeanDefinitionReader(beanFactory, this); 会传入两个参数,一个是默认的 bean工厂DefaultListableBeanFactory
, this 是谁调用就是谁,我们是从ClassPathXmlApplicationContext
进来的,所以这个 this是ClassPAC ,这样就把两个继承体系整合在了一起。然后调用 getConfigLocations() 方法获取文件名,很不巧这个方法仍然是抽象方法,会去到子类ClassPathXmlApplicationContext 正是我们一开始 DeBUG 的地方
,设计的非常巧妙。
然后调用 XmlBeanDefinitionReader . loadBeanDefinitions(xml文件名 ) 方法, Xmlbean定义读取器加载 xml 文件,然后调用到父类
AbstractBeanDefinitionReader
的loadBeanDefinitions() 方法遍历出文件名。很不巧的是 loadBeanDefinitions 是重载方法,会再次重载到 XmlBeanDefinitionReader . loadBeanDefinitions( ) 这个地方重载的也非常妙。然后就是 getResourceLoader(); 之前 new XmlBeanDefinitionReader ,时传入了一个 ClassPathXmlApplicationContext 这个对象间接实现了 ResourceLoader,所以这里 getResourceLoader()会获取到 ClassPathXmlApplicationContext ;只不过这里使用 ResourceLoader 进行接收,然后调用 getResource (location文件名),后面会将这个文件名封装到一个 InputStream 读取xml 文件,然后调用 resource.getInputStream(); 获取到这个 InputStream 流。
最后到
doLoadBeanDefinitions(InputStream inputStream)
真正执行程序加载 xml 文件,//解析context:component-scan标签并扫描指定包中的类,提取类信息,组装成BeanDefinition
, 标签属性//id优先于name, //如果id和name都为空,将类名的第一个字母转为小写后作为bean的名称 , //beanName不能重名
//注册BeanDefinition
getRegistry().registerBeanDefinition(beanName, beanDefinition);
最后将解析xml 得到的 bean 放到
DefaultListableBeanFactory
默认bean工厂的 beanDefinitionMap 。
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitionMap.put(beanName, beanDefinition);
}
至此 XML 文件配置 Java Bean 结束