前言-阅读源码有利于陶冶情操,本文承接前文Spring源码情操陶冶-AbstractApplicationContext

约束:

  1. 本文指定contextClass为默认的XmlWebApplicationContext
  2. 从属AbstractApplicationContext#refresh方法

AbstractApplicationContext#obtainFreshBeanFactory

该方法主要完成创建Bean工厂,涉及到解析spring文件,代码清单如下

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//更新bean工厂,其会销毁已存在的bean内容并重新创建
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

由以上代码所见,关键方法指向子类AbstractRefreshableApplicationContext#refreshBeanFactory,代码清单如下

protected final void refreshBeanFactory() throws BeansException {
//存在已有bean工厂则销毁
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建默认的用List接口存放bean的工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
//这里同contextId
beanFactory.setSerializationId(getId());
//配置allowBeanDefinitionOverriding和allowCircularReferences属性,这里均不设置
customizeBeanFactory(beanFactory);
//调用子类的加载bean定义方法,这里会调用XmlWebApplicationContext子类的复写方法
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

XmlWebApplicationContext#loadBeanDefinitions

加载bean预方法,代码清单如下

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's
// resource loading environment.
//环境为StardEvironment对象
beanDefinitionReader.setEnvironment(getEnvironment());
//资源加载器为XmlWebApplicationContext
beanDefinitionReader.setResourceLoader(this);
//实体分解器为ResourceEntityResolver对象,主要用于javax.xml.parse解析xml所用
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
//此处为空方法
initBeanDefinitionReader(beanDefinitionReader);
//真切的开始加载bean
loadBeanDefinitions(beanDefinitionReader);
}

紧接着查看真实的加载bean方法XmlWebApplicationContext#loadBeanDefinitions(XmlBeanDefinitionReader reader),代码清单如下

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
//获取spring配置文件的位置列表
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
//读取加载
reader.loadBeanDefinitions(configLocation);
}
}
}

AbstractBeanDefinitionReader#loadBeanDefinitions

真实的加载bean内容可追溯到XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader#loadBeanDefinitions(String location, Set<Resource> actualResources)方法,代码清单如下

//此处的actualResources参数传过来为null
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//此处的ResourceLoader为XmlWebApplicationContext
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
//XmlWebApplicationContext符合此条件
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
//调用的是AbstractApplicationContext的getResources方法,追溯一下调用的其实是PathMatchingResourcePatternResolver.getResources方法,其会搜寻指定目录符合条件的文件集合
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//加载某个spring bean文件
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}

略过一些代码调用,直接看XmlBeanDefinitionReader#registerBeanDefinitions(Document doc,Resource resource)注册bean定义方法,代码清单如下

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
//此处的getRegistry()方法返回的实例为DefaultListableBeanFactory类型
int countBefore = getRegistry().getBeanDefinitionCount();
//调用DefaultBeanDefinitionDocumentReader.registerBeanDefinitions方法
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}

DefaultBeanDefinitionDocumentReader#registerBeanDefinitions

代码清单如下

	//解析bean定义
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//此处的root节点一般为<beans>节点
Element root = doc.getDocumentElement();
//具体解析的方法
doRegisterBeanDefinitions(root);
}

解析bean具体方法DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions,代码清单如下

protected void doRegisterBeanDefinitions(Element root) {
//此处针对<beans>的节点属性profile进行的操作
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
return;
}
} // Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
//读取<beans>标签中的default-*属性
this.delegate = createDelegate(this.readerContext, root, parent);
//预处理bean xml配置文件中的自定义标签,默认是为空的
preProcessXml(root);
//解析bean xml配置文件
parseBeanDefinitions(root, this.delegate);
//处理bean xml配置文件中的自定义标签,默认是为空的
postProcessXml(root); this.delegate = parent;
}

从上述的注释可知,我们只需关注DefaultBeanDefinitionDocumentReader#parseBeanDefinitions对bean xml文件的解析,鉴于其重要性,将于下一章节详细解读

下节预告

Spring源码情操陶冶-DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

Spring源码情操陶冶-AbstractApplicationContext#obtainFreshBeanFactory的更多相关文章

  1. Spring源码情操陶冶-AbstractApplicationContext#prepareBeanFactory

    阅读源码有助于陶冶情操,本文承接Spring源码情操陶冶-AbstractApplicationContext#obtainFreshBeanFactory 瞧瞧官方注释 /** * Configur ...

  2. Spring源码情操陶冶-AbstractApplicationContext#prepareRefresh

    前言-阅读源码有利于陶冶情操,本文承接前文Spring源码情操陶冶-AbstractApplicationContext 约束: 本文指定contextClass为默认的XmlWebApplicati ...

  3. Spring源码情操陶冶-AbstractApplicationContext#finishBeanFactoryInitialization

    承接前文Spring源码情操陶冶-AbstractApplicationContext#registerListeners 约定web.xml配置的contextClass为默认值XmlWebAppl ...

  4. Spring源码情操陶冶-AbstractApplicationContext#registerListeners

    承接前文Spring源码情操陶冶-AbstractApplicationContext#onRefresh 约定web.xml配置的contextClass为默认值XmlWebApplicationC ...

  5. Spring源码情操陶冶-AbstractApplicationContext#onRefresh

    承接前文Spring源码情操陶冶-AbstractApplicationContext#initApplicationEventMulticaster 约定web.xml配置的contextClass ...

  6. Spring源码情操陶冶-AbstractApplicationContext#initApplicationEventMulticaster

    承接前文Spring源码情操陶冶-AbstractApplicationContext#initMessageSource 约定web.xml配置的contextClass为默认值XmlWebAppl ...

  7. Spring源码情操陶冶-AbstractApplicationContext#initMessageSource

    承接前文Spring源码情操陶冶-AbstractApplicationContext#registerBeanPostProcessors 约定web.xml配置的contextClass为默认值X ...

  8. Spring源码情操陶冶-AbstractApplicationContext#registerBeanPostProcessors

    承接前文Spring源码情操陶冶-AbstractApplicationContext#invokeBeanFactoryPostProcessors 瞧瞧官方注释 /** * Instantiate ...

  9. Spring源码情操陶冶-AbstractApplicationContext#invokeBeanFactoryPostProcessors

    阅读源码有利于陶冶情操,承接前文Spring源码情操陶冶-AbstractApplicationContext#postProcessBeanFactory 约定:web.xml中配置的context ...

随机推荐

  1. RSA加密通信小结(四)--RSA加解密的实际操作与流程小结

    在上一篇文章中,我们已经将密钥的生成方法和流程,归纳总结.而本篇主要是讲如何利用密钥进行加解密. 首先,在上一篇文章中的我们生成了很多密钥,证书等等. 在上述生成的文件中,接收服务端加密报文:pkcs ...

  2. [编织消息框架][netty源码分析]8 Channel 实现类NioSocketChannel职责与实现

    Unsafe是托委访问socket,那么Channel是直接提供给开发者使用的 Channel 主要有两个实现 NioServerSocketChannel同NioSocketChannel 致于其它 ...

  3. 什么是Css Hack?ie6,7,8的hack分别是什么?

    针对不同的浏览器写不同的CSS code的过程,就是CSS hack. 示例如下: 1 2 3 4 5 6 7 8 9 10 11 12 #test       { width:300px; heig ...

  4. JAVA项目省市县加载兼容浏览器异常

    最近同僚遇到个在IE8及IE8以下浏览器上出现地址加载问题,初始加载没问题,问题出在事件上. 先来一段初始加载地址的代码:(也可以修改或者增加第二个事件地址) var select1 = new Li ...

  5. 第一次接触Axure

    现在已经是凌晨4:21了,我的第一份Axure.RP文件终于接近尾声,我带着些许疲倦些许兴奋的状态写下这篇博客,记录我和Axure的初遇.       三天前,我加入了湖南大学金山俱乐部,参加了第一次 ...

  6. 学习php语法--数据库扩展(总结篇)

      前  言  php  php中的数据库扩展mysql语法--本篇学习都是通过使用数字天堂的HBuider开发环境,连接mysql数据.介绍php连接mysql数据库的代码与函数. 本篇学习主要有两 ...

  7. Jenkins插件开发

    一.环境配置 不赘述,直接看wiki:https://wiki.jenkins.io/display/JENKINS/Extend+Jenkins 二.内容说明 1.插件代码结构 src/main/j ...

  8. 安装gcc提示no acceptable C compiler found in $PATH

    安装gcc提示no acceptable C compiler found in $PATH 从所报错可以看出是缺少了c编译器,因为gcc就是c编译器,所以没有安装gcc就没有c编译器. 之所以报这样 ...

  9. AospExtended K3 Note最新官方版 Android7.1.2 极速 省电 流畅 Galaxy XIAOMI Moto Lenovo Coolpad 均支持

    AospExtended 最新官方版 Android7.1.2 极速 省电 流畅 Galaxy  XIAOMI Moto  Lenovo  Coolpad  均支持 之前用过1629开发版等,体验了很 ...

  10. 如何使用jedis进行发布订阅

    jedis实现发布订阅,是通过让发布者和订阅者同时对某个channel(频道)进行操作,订阅者订阅了某个频道例如channel1,发布者往这个channel1里面publish东西,在pubsubli ...