接下来学习 AbstractApplicationContext # obtainFreshBeanFactory() 都干了啥!
主要功能
- 就是获得 BeanFactory;
 - 解析所有的 xml 配置文件,将其中定义的 bean 解析定义成 BeanDefinition ;
 - 同时也会将使用指定注解(@Controller、@Service、@Component、@Repository)的 bean 定义也同样封装成 BeanDefinition。
主干流程
spring-web | org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory
进入刷新方法:protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {// 刷新 BeanFactory ,见 AbstractRefreshableApplicationContext # refreshBeanFactory()refreshBeanFactory();// 得到刷新后的 BeanFactoryreturn getBeanFactory();}
spring-web | org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactoryprotected final void refreshBeanFactory() throws BeansException {// 有的话销毁if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 创建一个新的BeanFactoryDefaultListableBeanFactory beanFactory = createBeanFactory();// 将序列化ID及工厂添加至缓存,Map<String, Reference<DefaultListableBeanFactory>>beanFactory.setSerializationId(getId());// 自定义配置,例如是否允许bean定义覆盖,是否允许循环引用等。默认都是允许的。customizeBeanFactory(beanFactory);// 加载bean定义loadBeanDefinitions(beanFactory);// ApplicationContext 设置 BeanFactorythis.beanFactory = beanFactory;}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for "+ getDisplayName(), ex);}}
获取一个新的 beanFactory
进入方法 createBeanFactory() ,容器启动后我们的 WebApplicationContext,并没有 parent。所以这整个方法其实就是 new 了一个DefaultListableBeanFactory。 ```java protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); } // 代码位置: spring-context | org.springframework.context.support.AbstractRefreshableApplicationContext 
protected BeanFactory getInternalParentBeanFactory() { return (getParent() instanceof ConfigurableApplicationContext ? ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent()); } // 代码位置: spring-context | org.springframework.context.support.AbstractApplicationContext
`DefaultListableBeanFactory`的父类关系:<br /><a name="f84db307"></a>### 缓存 BeanFactory```java// 将序列化ID及工厂添加至缓存,Map<String, Reference<DefaultListableBeanFactory>>beanFactory.setSerializationId(getId());
public void setSerializationId(@Nullable String serializationId) {if (serializationId != null) {serializableFactories.put(serializationId, new WeakReference<>(this));}else if (this.serializationId != null) {serializableFactories.remove(this.serializationId);}this.serializationId = serializationId;}// 代码位置: spring-context | org.springframework.context.support.DefaultListableBeanFactory
这段代码字面很好理解,就是将序列化 ID 作为 Key 缓存起来。注意还是个虚引用。在需要的时候可以通过 ID 获取对应的工厂。
自定义配置
// 自定义配置,例如是否允许bean定义覆盖,是否允许循环引用等,默认都是允许的。customizeBeanFactory(beanFactory);
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {if (this.allowBeanDefinitionOverriding != null) {beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.allowCircularReferences != null) {beanFactory.setAllowCircularReferences(this.allowCircularReferences);}}
设置下BeanFactory是否允许Bean定义的覆盖,及循环引用。
这个两个配置在 DefaultListableBeanFactory 中都是允许的。
加载 Bean 定义
这个是关键的一步,将配置文件中的 Bean 定义解析成 BeanDefinition 并缓存起来。
首先就是创建配置文件的解析器,设置环境,资源加载器等。可以通过方法 initBeanDefinitionReader 来自定义 XmlBeanDefinitionReader。
spring-web | org.springframework.web.context.support.XmlWebApplicationContext#loadBeanDefinitions。
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.beanDefinitionReader.setEnvironment(getEnvironment());beanDefinitionReader.setResourceLoader(this);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);loadBeanDefinitions(beanDefinitionReader);}
 第 1 步:
实例化 XmlBeanDefinitionReader (注意:spring-beans 模块对象),参数为我们的 DefaultListableBeanFactory 。
通过 XmlBeanDefinitionReader 的父类 AbstractBeanDefinitionReader 的构造方法可以得知:
- registry 被设置为 DefaultListableBeanFactory;
 - DefaultListableBeanFactory 并不是 ResourceLoader 的子类,所以 XmlBeanDefinitionReader 的 resourceLoader 被设置为 PathMatchingResourcePatternResolver;
 DefaultListableBeanFactory 并不是 EnvironmentCapable 的子类,所以 XmlBeanDefinitionReader 的 environment 被设置为 StandardEnvironment。
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");this.registry = registry;// Determine ResourceLoader to use.if (this.registry instanceof ResourceLoader) {this.resourceLoader = (ResourceLoader) this.registry;}else {this.resourceLoader = new PathMatchingResourcePatternResolver();}// Inherit Environment if possibleif (this.registry instanceof EnvironmentCapable) {this.environment = ((EnvironmentCapable) this.registry).getEnvironment();}else {this.environment = new StandardEnvironment();}}
第 2 步:
设置环境对象,如果第一步设置了就用,没有的话创建一个 StandardEnvironment。
第 3 步:
设置资源加载器,这里优先使用 ApplicationContext 的设置覆盖第一步的配置。
第 4 步:
设置 ResourceEntityResolver 解析器
第 5 步:
自定义调整 XmlBeanDefinitionReader 的设置,这个是一个扩展点。
第 6 步:
准备工作已经完毕,最终到了 loadBeanDefinitions(beanDefinitionReader);
接下来:找配置文件、解析路径、解析配置文件内容。protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {// 得到配置文件的位置String[] configLocations = getConfigLocations();if (configLocations != null) {for (String configLocation : configLocations) {reader.loadBeanDefinitions(configLocation);}}}
找配置文件位置
获取配置文件:getConfigLocations() ;
结论:它会从这个几个地方获取配置文件:
- web.xml 配置的 context-param 中 contextConfigLocation , 例如:classpath:spring/application.xml
 - 如果没有的话就从 getDefaultConfigLocations() 方法中获取配置文件,如果没有 Namespace 的话,就去默认的位置找,默认位置为:
/WEB-INF/applicationContext.xml 
代码如下所示:
@Overridepublic String[] getConfigLocations() {return super.getConfigLocations();}// 代码位置:org/springframework/web/context/support/AbstractRefreshableWebApplicationContextAbstractRefreshableConfigApplicationContext@Nullableprotected String[] getConfigLocations() {return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());}// 代码位置: org.springframework.context.support.AbstractRefreshableConfigApplicationContextXmlWebApplicationContext@Overrideprotected String[] getDefaultConfigLocations() {if (getNamespace() != null) {return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX+ getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};}else {return new String[] {DEFAULT_CONFIG_LOCATION};}}// 代码位置:spring-web | org.springframework.web.context.support.XmlWebApplicationContext
解析配置文件
@Overridepublic int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {return loadBeanDefinitions(location, null);}// org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions
来到父类的方法
spring-beans | org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {ResourceLoader resourceLoader = getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");}// 判断是否为ResourcePatternResolver子类,// 比如:ClassPathXmlApplicationContext,FileSystemXmlApplicationContext,AnnotationConfigApplicationContextif (resourceLoader instanceof ResourcePatternResolver) {// Resource pattern matching available.try {// 得到配置文件位置Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);// 解析,得到bean数量int count = loadBeanDefinitions(resources);if (actualResources != null) {Collections.addAll(actualResources, resources);}if (logger.isTraceEnabled()) {logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");}return count;} 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 count = loadBeanDefinitions(resource);if (actualResources != null) {actualResources.add(resource);}if (logger.isTraceEnabled()) {logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");}return count;}}
然后进入解析方法
spring-beans | org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions
@Overridepublic 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;}
进入子类解析方法
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions
@Overridepublic int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {return loadBeanDefinitions(new EncodedResource(resource));}
接下来的步骤,我们以前了解过:Spring5.2源码学习 - 读取XML的Bean配置信息.
解析的结果
最终解析的结果就是把他们缓存到 BeanFactory 中,有以下几个重要的缓存:
- beanDefinitionNames:bean 的 beanName 集合;
 - beanDefinitionMap:beanName - BeanDefinition 映射;
 - aliasMap:bean 的 beanName - 别名映射。(SimpleAliasRegistry)
 
