接下来学习 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();
// 得到刷新后的 BeanFactory
return getBeanFactory();
}
spring-web | org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactoryprotected final void refreshBeanFactory() throws BeansException {
// 有的话销毁
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建一个新的BeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 将序列化ID及工厂添加至缓存,Map<String, Reference<DefaultListableBeanFactory>>
beanFactory.setSerializationId(getId());
// 自定义配置,例如是否允许bean定义覆盖,是否允许循环引用等。默认都是允许的。
customizeBeanFactory(beanFactory);
// 加载bean定义
loadBeanDefinitions(beanFactory);
// ApplicationContext 设置 BeanFactory
this.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 possible
if (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
代码如下所示:
@Override
public String[] getConfigLocations() {
return super.getConfigLocations();
}
// 代码位置:org/springframework/web/context/support/AbstractRefreshableWebApplicationContext
AbstractRefreshableConfigApplicationContext
@Nullable
protected String[] getConfigLocations() {
return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
}
// 代码位置: org.springframework.context.support.AbstractRefreshableConfigApplicationContext
XmlWebApplicationContext
@Override
protected 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
解析配置文件
@Override
public 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,AnnotationConfigApplicationContext
if (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
@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;
}
进入子类解析方法
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions
@Override
public 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)