ConfigurableListableBeanFactory是Spring中非常重要的容器,继承于ListableBeanFactory、AutowireCapableBeanFactory和ConfigurableBeanFactory,下面是继承图:
Spring为什么要让ConfigurableListableBeanFactory继承这么多接口来实现一个Bean工厂呢?其实每个接口都有自己独特的功能,如ListableBeanFactory表示这些Bean是可列表的,AutowireCapableBeanFactory定义了Bean的自动装配规则,ConfigurableBeanFactory允许Bean工厂自定义配置,如是单例模式还是原型模式。这样拆分再合并就可以按照接口的约束和规范来进行扩展操作。
ConfigurableListableBeanFactory最重要的是通过map存储了BeanDefinition。Spring通过以下方法创建ConfigurableListableBeanFactory,解析XML文件,加载BeanDefinition
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
点进这个方法后 ,进入refreshBeanFactory()方法,ConfigurableListableBeanFactory就是在此处创建的。
customizeBeanFactory方法是设置是否允许覆盖BeanDefinition信息和是否允许循环依赖的地方,这两个值默认都是true。
loadBeanDefinitions方法是加载BeanDefinition的方法。总结就是创建一个读取器,解析配置文件,解析步骤为获取配置文件路径数组,遍历数组去获取资源数组,遍历资源数组解析资源
获取配置文件路径的代码
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);
}
}
遍历文件路径数组的代码
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int count = 0;
for (String location : locations) {
count += loadBeanDefinitions(location);
}
return count;
}
获取资源数组的代码
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
遍历资源数组的代码
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
count += loadBeanDefinitions(resource);
}
return count;
}
后面就是解析Resource,加载BeanDefinition,Spring针对不同的文件有不同的资源解析器,如xml、propertie等,还可以自定义资源解析器
加载xml文件中的BeanDefinition
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}