月泉的博客

Spring源码系列- Spring Beans - Spring Beans-XmlBeanFactory(上)

月泉 JavaSpring

在上一篇说了DefaultListableBeanFactory这个类,本篇将会分析它的一个子类XmlBeanFactory,老规矩先看看它的类关系图 XmlBeanFactory 类关系图

2333,忽略它已经被废弃了,虽然被废弃了我个人感觉还是很有必要从该类入手的,根据类关系图很直接它继承至DefaultListableBeanFactory,现在来看下该类是如何使用的,(^V^虽然大家应该都会用)

Resource resource = new ClassPathResource("application.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Person person = (Person) beanFactory.getBean("person");
System.out.println(person != null);
System.out.println(person.toString());

很简单,获取资源文件,将获取的资源文件传入XmlBeanFactory,然后再从中获取定义的Bean,接下来正式开始吧。

XmlBeanFactory 源码

根据源码可以发现该类定义了2个构造函数

  • XmlBeanFactory(Resource resource)
  • XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)

第一个:该构造函数直接传入resourcenull至另一个构造函数

第二个:resource该参数就不用解释了,parentBeanFactory该参数代表该BeanFactory实例的上一级的BeanFactory,不理解没关系,日后会写到的。

首先该构造函数调用了父类的构造函数将parentBeanFactory参数传递了过去,然后又调用了reader.loadBeanDefinitions(resource)方法,敲黑板!重点在这里。

接着继续往里走

loadBeanDefinitionReader(Resource resource) 根据代码片段的截图,该方法调用了另一个同名的重载函数

loadBeanDefinitionReader(EncodedResource encodedResource)

预防资源文件的编码问题,会先将resrouce采用EncodeResource进行封装,代码很简单想深入查看EncodeResource的可以自行去查看源码,到了这里想暂停一下,为了更加系统一点,我们应当先看下这个类的关系结构

XmlBeanDefinitionReader 类关系结构图 自然从最上面的EnvironmentCapableBeanDefinitionReader接口开始

EnvironmentCapable EnvironmentCapable 源码

该接口用作于环境标识,其只定义了一个接口方法getEnvironment()用于获取当前环境,额,应该会有人问我环境吧,去看下Spring的profile这个东西,可以利用profile来区分生产环境、测试环境、开发环境的配置等,233333扯远的,如果有朋友对这一块感兴趣,可以私下探讨。

BeanDefinitionReader BeanDefinitionReader 源码 该接口主要是定义了加载资源、解析资源、加载Bean

AbstractBeanDefinitionReader AbstractBeanDefinitionReader 源码

该类最重要的方法便是212行的loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources)方法,我们来具体看看该方法 首先获取了当前的ResourceLoader,接着判断了resourceLoader的类型是否是ResourcePatternResolver类型,ResourcePatternResolver是一个批量加载资源的接口,好了这里不必细究,仅是判断了资源的加载类型,首先假设if(true)

try {
	//从指定位置获取资源
	Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
	//通过resources加载bean并获取加载的数量
	int loadCount = loadBeanDefinitions(resources);
	if (actualResources != null) {
		for (Resource resource : resources) {
			//将资源加载至传递进来的actualResources中去
			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);
}

来看下该类调用的loadBeanDefinitions(Resource... resources)方法

@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
	Assert.notNull(resources, "Resource array must not be null");
	int counter = 0;
	for (Resource resource : resources) {
		//调用了子类的loadBeanDefinitions来加载bean
		counter += loadBeanDefinitions(resource);
	}
	return counter;
}

稍等在往下看loadBeanDefinitions(Resource resource)方法,先把else的片段看了,因为它也调用了2333333,一次性解决。

//从指定的绝对路径加载一个资源
Resource resource = resourceLoader.getResource(location);
//调用了子类的loadBeanDefinitions来加载bean
int loadCount = loadBeanDefinitions(resource);
	if (actualResources != null) {
		//将资源加载至传递进来的actualResources中去
		actualResources.add(resource);
	}
	if (logger.isDebugEnabled()) {
		logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
	}
	//返回数量
	return loadCount;

现在我们再回来看子类 该方法也是XmlBeanFactoryreader实例所所调用的loadBeanDefinitions(resource);

接下来直接涉及到该类是如何实现解析xml中所定义的bean,并且加载进来,内容比较长………所以放在下一篇吧。

月泉
伪文艺中二青年,热爱技术,热爱生活。