这是我参与8月更文挑战的第24天,活动详情查看:8月更文挑战
前言
Tell the subclass to refresh the internal bean factory.
告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从子类的refreshBeanFactory()方法启动
Spring 源码分析系列
源码分析obtainFreshBeanFactory
前面分析了
- 入口ClassPathXmlApplicationContext 构造函数
- 获取资源加载器AbstractApplicationContext
- 解析配置路径 setConfigLocations()
- 容器启动流程 refresh()
第一步prepareRefresh 比较简单这里不再赘述, obtainFreshBeanFactory 是一个比较核心的方法。
该方法的主要作用是将bean定义beandefinition加载到BeanFactory中。
-
该方法会解析所有 Spring 配置文件(application-**.xml),将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中。
-
常见的,如果解析到<context:component-scan base-package="" /> 注解时,会扫描 base-package 指定的目录,将该目录下使用指定注解(@Controller、@Service、@Component、@Repository)的配置也同样封装成 BeanDefinition,加载到 BeanFactory 中。
三个重要的缓存:
- beanDefinitionNames缓存:所有被加载到 BeanFactory 中的bean的beanName 集合。
- beanDefinitionMap缓存:所有被加载到 BeanFactory 中的bean的beanName和 BeanDefinition 映射。
- aliasMap缓存:所有被加载到 BeanFactory 中的bean的beanName和别名映射。
AbstractApplicationContext#obtainFreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 1. 刷新BeanFactory,有子类 AbstractRefreshableApplicationContext 实现
refreshBeanFactory();
// 2. 拿到刷新后的BeanFactory
return getBeanFactory();
}
1.1 AbstractRefreshableApplicationContext#refreshBeanFactory()
刷新BeanFactory,有子类 AbstractRefreshableApplicationContext 实现
@Override
protected final void refreshBeanFactory() throws BeansException {
// 1. 判断是否存在BeanFactory, 如果存在先销毁,关闭该BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 2. 创建新的BeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 3. 加载bean定义, 由XmlWebApplicationConetxt实现
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
1.2 XmlWebApplicationContext#loadBeanDefinitions
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// 1. 为BeanFactory 创建 XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
// 2. 使用此上下文资源加载环境配置
beanDefinitionReader.setEnvironment(getEnvironment());
// setResourceLoader 为 XmlBeanDefinitionReader
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);
// 3. 加载bean定义
loadBeanDefinitions(beanDefinitionReader);
}
1.3 XmlWebApplicationContext#loadBeanDefinitions
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
// 1. 获取配置文件路径
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
// 2. 根据配置文件路径加载Bean定义
reader.loadBeanDefinitions(configLocation);
}
}
}
1.4 AbstractBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
// 1. 获取 resourceLoader, 这边为 XmlWebApplicationContext
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
// 2. 判断 resourceLoader 是否为 ResourcePatternResolver 的实例
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
// 2.1 根据路径查找到该路径下面所有符合的配置文件,并封装成Resource
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
// 2.2 根据Resource定义,加载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.
// 3. 只能通过绝对URL路径加载单个资源
Resource resource = resourceLoader.getResource(location);
// 3.1 根据 resource 加载bean定义
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
基本流程
- 获取 resourceLoader
- 判断 resourceLoader 是否为 ResourcePatternResolver 的实例
2.1 根据路径拿到该路径下所有符合的配置文件,并封装成 Resource
2.2 根据 Resource,加载 bean 定义
1.5 AbstractBeanDefinitionReader#loadBeanDefinitions(Resource... resources)
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
// 1. 遍历所有的Resource
for (Resource resource : resources) {
// 2. 根据 Resource 加载Bean定义,XmlBeanDefinitionReader实现
count += loadBeanDefinitions(resource);
}
return count;
}
根据 Resource 加载 bean 定义,由 XmlBeanDefinitionReader 实现
1.6 XmlBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
// 1. 当前正在加载的EncodedResource
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
// 2. 将当前的 encodedResource 添加到 currentResources
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
// 3. 拿到 encodedResource 的 inputStream
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
// 4. 将 inputStream 封装成 org.xml.sax.InputSource
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 5. 加载bean定义, 真正加载bean定义的do方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
1.6 AbstractBeanDefinitionReader#doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 1. 根据imputResource和resource 加载XML文件并封装Document
Document doc = doLoadDocument(inputSource, resource);
// 2. 根据返回的Document 注册Bean信息
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
// ....
}
}
1.7 AbstractBeanDefinitionReader#doLoadDocument
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
// 1. 获取XML文件的验证方式
// 2. 加载XML文件并得到 Document
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
1.7.1 getValidationModeForResource
protected int getValidationModeForResource(Resource resource) {
int validationModeToUse = getValidationMode();
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
int detectedMode = detectValidationMode(resource);
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
// Hmm, we didn't get a clear indication... Let's assume XSD,
// since apparently no DTD declaration has been found up until
// detection stopped (before finding the document's root tag).
return VALIDATION_XSD;
}
1.7.2 loadDocument
@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
// 1. 创建DocumentBuilderFactory
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
// 2. 通过 DocumentBuilderFactory 创建 DocumentBuilder
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
// 3. 使用DocumentBuilder解析并返回Document对象
return builder.parse(inputSource);
}
1.8 registerBeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 1. 使用DefaultBeanDefinitionDocumentReader 实例化 BeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 2. 记录统计BeanDifinition加载的个数
int countBefore = getRegistry().getBeanDefinitionCount();
// 3. createReaderContext, 根据resource创建XmlReaderContext
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
1.9 createReaderContext
- 根据 resource 构建一个 XmlReaderContext,用于存放解析时会用到的一些上下文信
- 其中 namespaceHandlerResolver 会创建默认的 DefaultNamespaceHandlerResolver,DefaultNamespaceHandlerResolver的handlerMappingsLocation 属性会使用默认的值 “META-INF/spring.handlers”,并且这边有个重要的属性 handlerMappings,handlerMappings 用于存放命名空间和该命名空间handler类的映射.
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
public NamespaceHandlerResolver getNamespaceHandlerResolver() {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return this.namespaceHandlerResolver;
}
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());
return new DefaultNamespaceHandlerResolver(cl);
}
1.10 registerBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
// 构件BeanDefinitionParserDelegate
this.delegate = createDelegate(getReaderContext(), root, parent);
// 1. 校验Root节点命名空间是否是默认的命名空间
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
// 2. 校验profile
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}