一、前言
在上篇中Spring源码解析(13)之refresh源码分析(一)_jokeMqc的博客-CSDN博客我们已经介绍了ClassPathXmlApplicationContext前两个方法的作用,没有看到我上一篇的文章的可以先去看下上一篇对于ClassPathXmlApplicationContext的介绍。
接下来我们就要对refresh方法的13个方法进行具体的源码分析了,首先我们先来看下refresh的大体代码;
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
/**
* 1.准备上下文的刷新工作,记录bean容器的启动时间,容器活跃状态
* 验证系统中一些属性和属性值的设置等.
* 使用LinkedHashSet初始化earlyApplicationListeners和earlyApplicationEvents
*/
prepareRefresh();
/**
* 2.获取Bean工厂,期间会做解析和加载bean定义的一些列工作.生成BeanDefinition对象.
* 此处返回的beanFactory的真实类型为:DefaultListableBeanFactory
*
*
* 自定义的xsd约束文件也会在该步骤进行解析,通过实现BeanDefinitionParser接口,并实现parse方法
* 解析自定义标签时通过实现NamespaceHandlerSupport接口,并实现init方法进行实现
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/**
* 3.bean工厂的初始化准备工作,设置bean工厂的一些属性
* 比如:创建bean工厂时,需要忽略哪些接口,需要注册哪些bean,需要设置哪些Bean的后置处理器等.
*
* 例如常用的:ApplicationContextAwareBeanPostProcessor, ApplicationListenerDetector
*
* 此外,注册一些和环境相关的bean单实例bean.
*/
prepareBeanFactory(beanFactory);
try {
/**
* 4.Bean定义加载完毕之后实现,目前方法为空实现,留给开发人员进行自定义扩展。
* 和BeanFactoryPostProcessor中的方法postProcessBeanFactory相同
*
* 该方法在Bean定义加载完毕之后,Bean实例化之前会执行
* 比如在BeanFactory加载完所有的Bean定义之后,想要修改某个bean的定义信息,可以通过重写这个方法实现.
* 比如:在xml中配置了<bean id="user"><property name="name" value="wb"></property></bean>
* 如果想在不修改配置文件的情况下修改name的值,可以使用如下的方法:
* class MyApplicationContext extends ClassPathXmlApplicationContext{
public MyApplicationContext(String s){
super(s);
}
@Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
PropertyValue propertyValue=new PropertyValue("name", "www.so.com");
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
*/
postProcessBeanFactory(beanFactory);
/**
* 5.执行beanFactory的后置处理器
*
* 先执行BeanDefinitionRegistryPostProcessor接口的实现类的postProcessBeanDefinitionRegistry方法,
* 执行过程中,也是先执行实现了优先级接口PriorityOrdered的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
* 然后执行实现了Ordered接口的...
* 最后执行未实现PriorityOrdered接口和Ordered接口的...
*
* 然后执行BeanFactoryPostProcessor接口的实现类的postProcessBeanFactory方法
* 执行过程中,也是先执行实现了优先级接口PriorityOrdered的BeanFactoryPostProcessor的postProcessBeanFactory方法
* 然后执行实现了Ordered接口的...
* 最后执行未实现PriorityOrdered接口和Ordered接口的...
*
* 其中也涉及到了排序过程
*
*
* 配置类中的Selector类型的组件和@Component,@ComponentScan中的元数据信息也会在该步骤中进行解析
* 还包括执行条件注解@Condition的回调逻辑
*
*
* ImportBeanDefinitionRegistrar对应的registerBeanDefinitions方法也会在该步骤中调用,给容器中注册自定义的组件.
*/
invokeBeanFactoryPostProcessors(beanFactory);
/**
* 6.注册所有bean的后置处理器.用来拦截Bean的创建
*
* 注册所有实现了BeanPostProcessor接口的后置处理器
* 执行过程中,也是先执行实现了优先级接口PriorityOrdered接口的BeanPostProcessor的addBeanPostProcessor方法
* 然后执行实现了Ordered接口的...
* 最后执行未实现PriorityOrdered接口和Ordered接口的...
*
* 其中也涉及到了排序过程
*/
registerBeanPostProcessors(beanFactory);
/**
* 7.初始化消息源
* 用来做国际化,消息绑定,消息解析等功能
* 一般在SpringMVC中会使用到.
*/
initMessageSource();
/**
* 8.初始化事件派发器,用来发布事件
* 如果容器中有类型为ApplicationEventMulticaster的派发器组件,则直接获取使用
* 如果容器中没有,则默认创建一个类型为SimpleApplicationEventMulticaster的派发器,供容器派发事件使用
*/
initApplicationEventMulticaster();
/**
* 9.用来初始化一些特殊的Bean,目前默认是空方法,未实现,可以通过继承AbstractApplicationContext类,
* 然后覆写该方法进行自定义特殊bean的初始化.
*
* 比如:AbstractRefreshableWebApplicationContext中onRefresh方法用来初始化主题能力.
*
* SpringBoot也是在改步骤中启动内嵌Tomcat容器的
*/
onRefresh();
/**
* 10.注册监听器
* 将监听器绑定到广播器上,将监听器对应的beanName绑定到到第8步初始化的事件派发器中,
* 如果之前有发布的事件,则直接通过事件派发器将事件派发出去.
*/
registerListeners();
/**
* 11.初始化所有剩余的单实例Bean(没有使用懒加载的Bean).整个Spring IOC的核心.
*
* 包括执行@PostConstruct标注的方法.
*
* 注意:SpringMVC的父子容器创建Bean的过程:
* SpringMVC中,存在着父容器和子容器。当父容器启动之后,会通过该方法将所有的Dao和Service对应的Bean创建出来,保存到beanFactory的单例缓存容器中
* 当子容器启动之后,也会通过该方法将所有的Controller,viewResolver,HandlerMapping对应的Bean创建出来,然后放入到beanFactory的单例缓存容器中.
*/
finishBeanFactoryInitialization(beanFactory);
/** 12.发布事件。例如容器中的刷新事件:ContextRefreshedEvent就是在这一步中发布. SpringCloud在该步骤中会启动web服务 */
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
// 清空单实例bean对应的map及缓存
destroyBeans();
// 设置容器的活跃状态为false
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
接下来我们就一一对这个13个方法的源码进行分析。
1.1prepareRefresh
prepareRefresh();
做的事情比较简单:准备上下文,设置其启动日期和活动标志,执行属性源的初始化。
protected void prepareRefresh() {
// 记录容器的启动时间.
this.startupDate = System.currentTimeMillis();
// 记录容器未关闭
this.closed.set(false);
// 记录容器状态为激活状态
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
} else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
/**
* 如果需要在验证系统属性之前,给系统中设置一些默认值。可以通过继承AbstractApplicationContext类,并重写该方法实现。
* Spring留给开发人员的一个扩展点.
*
* 例如子类在方法中设置环境属性中必须需要的变量:getEnvironment().setRequiredProperties("myProp");
*/
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
/**
* 作用:校验设置的必须属性是否能够在系统环境中找到对应的值
*
* 如果在initPropertySources方法中使用getEnvironment().setRequiredProperties(String... keys)设置了必须的属性,而通过this.getProperty(key)
* 没有从系统环境中获取到属性的值,则会抛出MissingRequiredPropertiesException异常
*/
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
/** 在SpringBoot中会有大量的初始化监听器,用于初始化使用 */
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
} else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
/** 定义早期的应用事件 */
this.earlyApplicationEvents = new LinkedHashSet<>();
}
前面主要是初始化一些标记位,然后我们看到initPropertySources这个方法,这个是Spring留给开发人员的一个扩展点,如果需要在验证系统属性之前,给系统中设置一些默认值。可以通过继承AbstractApplicationContext类,并重写该方法实现。如下:
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
public MyClassPathXmlApplicationContext(String... configLocations){
super(configLocations);
}
@Override
protected void initPropertySources() {
System.out.println("扩展initPropertySource");
getEnvironment().setRequiredProperties("username");
}
// ....忽略部分代码
}
然后我们接下来看getEnvironment里面做了那些事情?
@Override
public ConfigurableEnvironment getEnvironment() {
// 如果存在环境则直接返回,如果不存在则创建一个环境对象再返回
if (this.environment == null) {
// StandardEnvironment
this.environment = createEnvironment();
}
return this.environment;
}
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}
public class StandardEnvironment extends AbstractEnvironment {
/** System environment property source name: {@value}. */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
/** JVM system properties property source name: {@value}. */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
/**
* Customize the set of property sources with those appropriate for any standard
* Java environment:
* <ul>
* <li>{@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME}
* <li>{@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}
* </ul>
* <p>Properties present in {@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME} will
* take precedence over those in {@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}.
* @see AbstractEnvironment#customizePropertySources(MutablePropertySources)
* @see #getSystemProperties()
* @see #getSystemEnvironment()
*
* 初始化SystemProperties和SystemEnviroment
*/
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(
new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(
new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
}
从源码可以看出,如果存在一个换进对象则直接返回,如果不存在一个环境对象在则创建一个再返回,然后默认的环境对象是StandardEnvironment,我们看到StandardEnvironment没有默认的构造方法,然后我们具体看他父类的构造方法,父类的构造方法调用了customizePropertySources方法也就是StandardEnvironment中的customizePropertySources方法,我们可以看得到这个方法就是为我们去加载一些系统变量跟环境变量,这个我们在上一篇中也有介绍到过。
然后就是校验对应需要的属性存在不存在,如果不存在就抛出异常。
1.2obtainFreshBeanFactory
获取Bean工厂,期间会做解析和加载bean定义的一些列工作.生成BeanDefinition对象。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
/**
* 刷新bean工厂,判断bean工厂是否已经存在,如果存在需要进行销毁和关闭
* 默认调用的是AbstractRefreshableApplicationContext的refreshBeanFactory方法.
* 刷新Bean工厂时会进行bean定义的加载操作。
*/
refreshBeanFactory();
return getBeanFactory();
}
刷新bean工厂,判断bean工厂是否已经存在,如果存在需要进行销毁和关闭,我们接着继续往下看。
@Override
protected final void refreshBeanFactory() throws BeansException {
// 判断bean工厂是否存在,如果存在需要先销毁和关闭。否则会出现问题
if (hasBeanFactory()) {
// 销毁bean,根据bean的名称将bean工厂中的所有bean都从map中移除
destroyBeans();
// 关闭bean工厂,设置Bean工厂的序列化id为null,并将beanFactory的值赋值为null
closeBeanFactory();
}
try {
// 重新创建bean工厂,默认返回的是Bean工厂类型是:DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置序列化ID,ID: class名称 + "@" + 对象的十六进制值
beanFactory.setSerializationId(getId());
// 定制bean工厂。作用:设置bean定义是否可以被覆盖以及设置bean在创建的时候是否允许循环引用.
customizeBeanFactory(beanFactory);
// 解析并加载bean的定义,默认是通过AbstractXmlApplicationContext类中的loadBeanDefinitions实现
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
refreshBeanFactory一共做了几件事情;
- 判断bean工厂是否存在,如果存在需要先销毁和关闭。否则会出现问题;
- 重新创建bean工厂,默认返回的是Bean工厂类型是:DefaultListableBeanFactory;
- 设置序列化ID,ID: class名称 + "@" + 对象的十六进制值;
- 定制bean工厂。作用:设置bean定义是否可以被覆盖以及设置bean在创建的时候是否允许循环引用.
- 解析并加载bean的定义,默认是通过AbstractXmlApplicationContext类中的loadBeanDefinitions实现;
我们接下来看它是如果创建DefaultListableBeanFactory的。
// AbstractRefreshableApplicationContext
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
// DefaultListableBeanFactory
public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
super(parentBeanFactory);
}
// AbstractAutowireCapableBeanFactory
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory);
}
/**
* Create a new AbstractAutowireCapableBeanFactory.
* ignoreDependencyInterface:方法用来在自动装配时自动忽略类或者接口子类的注入.
*/
public AbstractAutowireCapableBeanFactory() {
super();
// 在Bean自动装配时自动忽略BeanNameAware子类的注入
ignoreDependencyInterface(BeanNameAware.class);
// 忽略BeanFactoryAware接口子类的注入
ignoreDependencyInterface(BeanFactoryAware.class);
// 忽略BeanClassLoaderAware接口子类的注入
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
接下来看下customizeBeanFactory是如何定制BeanFactory的。
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
// 是否允许覆盖Bean的定义
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 该属性在解决Spring Bean的循环依赖中会使用到
// 如果该属性的值为true,而且将要初始化的bean为单例,而且正在创建中,则在初始化属性前会把该bean的信息放入到singletonFactories中.
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
两个属性,allowBeanDefinitionOverriding是否允许覆盖Bean的定义,allowCircularReferences该属性在解决Spring Bean的循环依赖中会使用到。
接下来我们来看下loadBeanDefinitions,这里loadBeanDefinitions是一个重载方法大家看的时候不要被绕晕了。
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建Xml格式的Bean读取器,里面会设置bean工厂的资源加载器及环境信息
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 对象创建bean读取器的时候已经初始化.此处直接获取
beanDefinitionReader.setEnvironment(this.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);
// 会解析xml中的标签属性,并添加到bean定义中.
loadBeanDefinitions(beanDefinitionReader);
}
他首先是创建Xml格式的Bean读取器,里面会设置bean工厂的资源加载器及环境信息,然后对beanDefinitionReader进行一些属性赋值,最后就会解析xml中的标签属性,并添加到bean定义中,我们具体看对应的解析源码;
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 通过另外一个构造函数构造的容器,会使用configResources的方式去加载bean定义
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
// 获取所有的配置文件名称,例如:{"beans.xml"}。主要是xml配置文件的名称
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
很显然没有调用有他一下的这个构造方法:
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
Assert.notNull(paths, "Path array must not be null");
Assert.notNull(clazz, "Class argument must not be null");
this.configResources = new Resource[paths.length];
for (int i = 0; i < paths.length; i++) {
this.configResources[i] = new ClassPathResource(paths[i], clazz);
}
refresh();
}
所以拿到的configResources 为null,我们就继续走下一个方法,获取所有的配置文件,然后把配置文件列表传进去解析。
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int count = 0;
for (String location : locations) {
// 加载bean定义
count += loadBeanDefinitions(location);
}
return count;
}
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
// resourceLoader是在XmlApplicationContext中通过setResourceLoader方法设置进去的属性
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
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;
}
}
我们根据配置文件解析得出一个Resource[]数组,然后将这个Resource[]数组再传进去解析,我们接着往下看。
/**
* 加载资源对应的bean定义.
* @param resources the resource descriptors
* @return
* @throws BeanDefinitionStoreException
*/
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
// 加载bean定义
count += loadBeanDefinitions(resource);
}
return count;
}
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
/**
* Load bean definitions from the specified XML file.
* @param encodedResource the resource descriptor for the XML file,
* allowing to specify an encoding to use for parsing the file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
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);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 执行bean定义加载
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 将xml配置文件通过JDK中的JAXP(Java API for XMLProcessing)解析为Document对象
Document doc = doLoadDocument(inputSource, resource);
// 注册bean定义
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 通过反射创建Bean定义文档读取器,默认类型为:DefaultBeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获取之前已经加载的bean定义数量,直接通过beanDefinitionMap.size获取
int countBefore = getRegistry().getBeanDefinitionCount();
// 执行xml的解析及bean定义注册。在创建bean定义读取器上下文时,会去创建默认的DefaultNamespaceHandlerResolver
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 返回本次注册的bean定义的数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
好了,今天先分析到prepareRefresh跟obtainFreshBeanFactory,后面我们接着继续往下分析。