本章是《spring4.1.8初始化源码学习三部曲》系列的终篇,重点是学习AbstractApplicationContext类的refresh()方法;

原文地址:https://blog.csdn.net/boling_cavalry/article/details/81045637

我们先回顾ClassPathXmlApplicationContext类的初始化过程如下代码:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {super(parent);setConfigLocations(configLocations);if (refresh) {refresh();}
}

三部曲的前两篇学习了super(parent)和setConfigLocations(configLocations):
1. 《spring4.1.8初始化源码学习三部曲之一:AbstractApplicationContext构造方法》;
2. 《spring4.1.8初始化源码学习三部曲之二:setConfigLocations方法》;

refresh方法简介

本章来学习refresh方法,具体的源码在AbstractApplicationContext类中,该方法的简介请看下面源码中的注释:

@Override
public void refresh() throws BeansException, IllegalStateException {//startupShutdownMonitor对象在spring环境刷新和销毁的时候都会用到,确保刷新和销毁不会同时执行synchronized (this.startupShutdownMonitor) {// 准备工作,例如记录事件,设置标志,检查环境变量等,并有留给子类扩展的位置,用来将属性加入到applicationContext中prepareRefresh();// 创建beanFactory,这个对象作为applicationContext的成员变量,可以被applicationContext拿来用,// 并且解析资源(例如xml文件),取得bean的定义,放在beanFactory中ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 对beanFactory做一些设置,例如类加载器、spel解析器、指定bean的某些类型的成员变量对应某些对象等prepareBeanFactory(beanFactory);try {// 子类扩展用,可以设置bean的后置处理器(bean在实例化之后这些后置处理器会执行)postProcessBeanFactory(beanFactory);// 执行beanFactory后置处理器(有别于bean后置处理器处理bean实例,beanFactory后置处理器处理bean定义)invokeBeanFactoryPostProcessors(beanFactory);// 将所有的bean的后置处理器排好序,但不会马上用,bean实例化之后会用到registerBeanPostProcessors(beanFactory);// 初始化国际化服务initMessageSource();// 创建事件广播器initApplicationEventMulticaster();// 空方法,留给子类自己实现的,在实例化bean之前做一些ApplicationContext相关的操作onRefresh();// 注册一部分特殊的事件监听器,剩下的只是准备好名字,留待bean实例化完成后再注册registerListeners();// 单例模式的bean的实例化、成员变量注入、初始化等工作都在此完成finishBeanFactoryInitialization(beanFactory);// applicationContext刷新完成后的处理,例如生命周期监听器的回调,广播通知等finishRefresh();}catch (BeansException ex) {logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);// 刷新失败后的处理,主要是将一些保存环境信息的集合做清理destroyBeans();// applicationContext是否已经激活的标志,设置为falsecancelRefresh(ex);// Propagate exception to caller.throw ex;}}
}

接下来逐个分析吧:

prepareRefresh方法

prepareRefresh方法的源码如下:

protected void prepareRefresh() {//记录初始化开始时间this.startupDate = System.currentTimeMillis();//context是否关闭的标志,设置为falsethis.closed.set(false);//context是否激活的标志,设置为truethis.active.set(true);if (logger.isInfoEnabled()) {logger.info("Refreshing " + this);}//留给子类实现的空方法initPropertySources();/**AbstractPropertyResolver类的requiredProperties是个集合,在下面的validateRequiredProperties方法中,都要拿requiredProperties中的元素作为key去检查是否存在对应的环境变量,如果不存在就抛出异常*/getEnvironment().validateRequiredProperties();
}

上述代码中,注意以下两处:
1. initPropertySources是个空方法,是留给子类实现的,以AnnotationConfigWebApplicationContext类为例,就overwrite了initPropertySources方法:

@Override
protected void initPropertySources() {ConfigurableEnvironment env = getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);}
}

跟踪上面的initPropertySources方法,最终找到了WebApplicationContextUtils.initServletPropertySources:

public static void initServletPropertySources(MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) {Assert.notNull(propertySources, "propertySources must not be null");if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,new ServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));}if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));}}

上面的代码所做的事情,就是给context增加环境变量数据(数据来自servlet相关的配置信息),这样spring环境就能从context中随时key取得对应的变量了;

  1. getEnvironment().validateRequiredProperties()的作用是用来校验context中是否存在“某些”变量,何谓”某些”?来看validateRequiredProperties方法,追踪到多层调用,最终在AbstractPropertyResolver类的validateRequiredProperties方法中实现:
@Override
public void validateRequiredProperties() {MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();for (String key : this.requiredProperties) {if (this.getProperty(key) == null) {ex.addMissingRequiredProperty(key);}}if (!ex.getMissingRequiredProperties().isEmpty()) {throw ex;}
}

上述代码显示,如果集合requiredProperties中的name在context中找不到对应的变量,就会抛出异常;

那么问题来了,requiredProperties集合是何时设置的呢?spring-framework中并没有调用,但是官方的单元测试源码给我们了启发,如下图:

如上图红框,如果业务需要确保某些变量在spring环境中必须存在,就可以调用setRequiredProperties方法将变量的name传递进去,这样validateRequiredProperties方法就会做检查了,我们可以基于现有的各种ApplicationContext实现自己定制一个Context类,确保在validateRequiredProperties方法调用之前调用setRequiredProperties方法将变量的name传递进去(例如重写initPropertySources),就能让spring帮我们完成检查了;

obtainFreshBeanFactory()

接下来看ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();得到临时变量beanFactory,先看看ConfigurableListableBeanFactory和BeanFactory的关系:

再看看obtainFreshBeanFactory方法:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {//由子类创建beanFactoryrefreshBeanFactory();//取得子类创建好的beanFactory,作为obtainFreshBeanFactory方法的返回值返回ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (logger.isDebugEnabled()) {logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);}return beanFactory;
}

上述代码中有的refreshBeanFactory需要细看;

refreshBeanFactory方法

refreshBeanFactory方法,在AbstractApplicationContext类中是抽象方法,具体实现在子类中,以其子类AbstractRefreshableApplicationContext为例,我们来看看refreshBeanFactory方法的实现:

@Override
protected final void refreshBeanFactory() throws BeansException {//如果beanFactory已经存在,就销毁context管理的所有bean,并关闭beanFactoryif (hasBeanFactory()) {//其实就是调用一些集合的clear方法,解除对一些实例的引用,参考DefaultSingletonBeanRegistry.destroySingletons方法destroyBeans();//关闭当前的beanFactory,其实就是将成员变量beanFactory设置为nullcloseBeanFactory();}try {DefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);loadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}
}
  1. createBeanFactory方法实际上返回的是一个DefaultListableBeanFactory实例:
protected DefaultListableBeanFactory createBeanFactory() {return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

2. 接下来的customizeBeanFactory方法是留给子类OverWrite的,该方法的说明和源码如下,说明中推荐通过OverWrite的方式对现有beanFactory做特别的设置:

/**
* Customize the internal bean factory used by this context.
* Called for each {@link #refresh()} attempt.
* <p>The default implementation applies this context's
* {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
* and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
* if specified. Can be overridden in subclasses to customize any of
* {@link DefaultListableBeanFactory}'s settings.
* @param beanFactory the newly created bean factory for this context
* @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
* @see DefaultListableBeanFactory#setAllowCircularReferences
* @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
* @see DefaultListableBeanFactory#setAllowEagerClassLoading
*/
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {if (this.allowBeanDefinitionOverriding != null) {//allowBeanDefinitionOverriding表示是否允许注册一个同名的类来覆盖原有类(注意是类,不是实例)beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.allowCircularReferences != null) {//allowCircularReferences表示是否运行多个类之间的循环引用beanFactory.setAllowCircularReferences(this.allowCircularReferences);}
}

3. loadBeanDefinitions在AbstractRefreshableApplicationContext类中是个抽象方法,留给子类实现,作用是把所有bean的定义后保存在context中,以AbstractXmlApplicationContext为例,看看loadBeanDefinitions方法做了什么:

/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
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(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);loadBeanDefinitions(beanDefinitionReader);
}

以上代码可见,加载bean的定义是通过XmlBeanDefinitionReader 来完成的,重点关注loadBeanDefinitions方法:

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);}
}

上述代码中的getConfigResources()和getConfigLocations(),究竟哪个会返回值有效数据呢?这就要去看ClassPathXmlApplicationContext的构造方法了:

//这个方法设置的是configLocations
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {super(parent);setConfigLocations(configLocations);if (refresh) {refresh();}
}//这个方法设置的是这个方法设置的是configResources
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, 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();
}

因此,到底是configLocations 还是configResources ,和我们使用哪个构造方法来实例化applicationContext对象有关;

4. 如果我们实例化applicationContext对象的方式是new ClassPathXmlApplicationContext(“applicationContext.xml”),那么setConfigLocations方法就会被调用,因此loadBeanDefinitions方法内部,实际执行的代码如下:

String[] configLocations = getConfigLocations();if (configLocations != null) {reader.loadBeanDefinitions(configLocations);}

5. 现在可以来看AbstractBeanDefinitionReader类的loadBeanDefinitions(String… locations)方法了:

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {Assert.notNull(locations, "Location array must not be null");int counter = 0;for (String location : locations) {counter += loadBeanDefinitions(location);}return counter;}

展开上面for循环中调用的方法:

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {ResourceLoader resourceLoader = getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");}if (resourceLoader instanceof ResourcePatternResolver) {// Resource pattern matching available.try {Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);int loadCount = loadBeanDefinitions(resources);if (actualResources != null) {for (Resource resource : resources) {actualResources.add(resource);}}if (logger.isDebugEnabled()) {logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");}return loadCount;}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 loadCount = loadBeanDefinitions(resource);if (actualResources != null) {actualResources.add(resource);}if (logger.isDebugEnabled()) {logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");}return loadCount;}}

以上方法中,首先要记得resourceLoader是ClassPathXmlApplicationContext(beanDefinitionReader.setResourceLoader(this)这行代码),所有resourceLoader.getResource(location)这行代码最终会调用PathMatchingResourcePatternResolver类的getResources(String locationPattern)方法得到bean有关的Resource对象;
得到Resource对象后,接着会调用loadBeanDefinitions(Resource… resources)方法来加载bean的定义了,最终是调用XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)方法:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {Assert.notNull(encodedResource, "EncodedResource must not be null");if (logger.isInfoEnabled()) {logger.info("Loading XML bean definitions from " + encodedResource.getResource());}Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();if (currentResources == null) {currentResources = new HashSet<EncodedResource>(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());}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();}}}

上述代码可见,重要的是通过Resource对象得到InputStream,再调用doLoadBeanDefinitions方法:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {Document doc = doLoadDocument(inputSource, resource);return registerBeanDefinitions(doc, resource);}...

上面是加载bean定义的关键代码:先制作Document对象,再调用registerBeanDefinitions方法,最终会将每个bean的定义放入DefaultListableBeanFactory的beanDefinitionMap中,详细的堆栈如下图:

完成了bean定义的注册,可以回到AbstractRefreshableApplicationContext.refreshBeanFactory方法了,看看loadBeanDefinitions(beanFactory)之后的代码:

synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}

至此,refreshBeanFactory方法分析完毕,该方法所做的事情:把xml文件中的bean定义被解析后,存放在DefaultListableBeanFactory的beanDefinitionMap中;

现在回到主线的AbstractApplicationContext.refresh()方法内,obtainFreshBeanFactory()我们已经分析完毕,所有bean定义都被存放在beanFactory这个临时变量对应的实例中;

prepareBeanFactory

接下来是prepareBeanFactory(beanFactory),看一下此方法的源码:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {//设置类加载器beanFactory.setBeanClassLoader(getClassLoader());//设置解析器,用于解析bean的定义中出现的Spel表达式表达式beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//设置一个注册接口,该接口只有一个方法registerCustomEditors,用来设置自定义的转换器beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// 部署一个bean的后置处理器ApplicationContextAwareProcessor,用于将spring的环境信息注入到实例化的bean之中beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));//bean在初始化的时候,如果有属性的类型为ResourceLoaderAware,则该属性不会被依赖注入beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);beanFactory.ignoreDependencyInterface(EnvironmentAware.class);// BeanFactory interface not registered as resolvable type in a plain factory.// MessageSource registered (and found for autowiring) as a bean.//bean如果有个属性的类型为BeanFactory.class,那么该属性会被设置为beanFactorybeanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);// Detect a LoadTimeWeaver and prepare for weaving, if found.if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {// 部署一个bean的后置处理器ApplicationContextAwareProcessor,用于AOP静态代理相关的处理beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));// Set a temporary ClassLoader for type matching.beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}// Register default environment beans.if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {//注册一个beanbeanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());}if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());}if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());}
}

上述代码中有以下几点需要注意:
1. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())),此方法要配合AbstractBeanFactory.registerCustomEditors方法一起看更好理解:addPropertyEditorRegistrar方法向propertyEditorRegistrars属性中放入了一个registrar,之后调用registerCustomEditors方法的时候,会用到propertyEditorRegistrars中的registrar,调用这些registrar的registerCustomEditors方法,完成自定义的转换器的设置;
2. beanFactory.addBeanPostProcessor方法用来注入后置处理器,在bean实例被创建后,初始化方法被执行的前后,后置处理器的postProcessBeforeInitialization、postProcessAfterInitialization这两个方法会分别被调用;
3. beanFactory.ignoreDependencyInterface设置了依赖注入时要忽略的接口,例如bean有个属性类型是ResourceLoaderAware,那么该属性不会被注入ResourceLoaderAware类型的实例;
4. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory)是特殊设置,如果一个bean有个属性的类型是BeanFactory,那么该属性会被设置为beanFactory这个实例;

总的来说prepareBeanFactory方法就是为beanFactory做一些设置工作,传入一些后面会用到的参数和工具类,再在spring容器中创建一些bean;

postProcessBeanFactory

postProcessBeanFactory方法是留给子类扩展的,可以在bean实例初始化之前注册后置处理器(类似prepareBeanFactory方法中的beanFactory.addBeanPostProcessor),以子类AbstractRefreshableWebApplicationContext为例,其postProcessBeanFactory方法如下:

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));beanFactory.ignoreDependencyInterface(ServletContextAware.class);beanFactory.ignoreDependencyInterface(ServletConfigAware.class);WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);}

可见除了WebApplicationContextUtils类的工作之外,其余的都是和prepareBeanFactory方法中类似的处理;

invokeBeanFactoryPostProcessors

invokeBeanFactoryPostProcessors方法用来执行BeanFactory实例的后置处理器BeanFactoryPostProcessor的postProcessBeanFactory方法,这个后置处理器除了原生的,我们也可以自己扩展,用来对Bean的定义做一些修改,由于此时bean还没有实例化,所以不要在自己扩展的BeanFactoryPostProcessor中调用那些会触发bean实例化的方法(例如BeanFactory的getBeanNamesForType方法),源码的文档中有相关说明,如下图红框所示,不要触发bean的实例化,如果要处理bean实例请在BeanPostProcessor中进行;:

registerBeanPostProcessors

registerBeanPostProcessors方法的代码略多,就不在此贴出来了,简单的说,就是找出所有的bean的后置处理器(注意,是bean的后置处理器,不是beanFactory的后置处理器,bean后置处理器处理的是bean实例,beanfactory后置处理器处理的是bean的定义),然后将这些bean的后置处理器分为三类:
1. 实现了顺序接口Ordered.class的,先放入orderedPostProcessors集合,排序后顺序加入beanFactory的bean后处理集合中;
2. 既没有实现Ordered.class,也没有实现PriorityOrdered.class的后置处理器,也加入到beanFactory的bean后处理集合中;
3. 最后是实现了优先级接口PriorityOrdered.class的,排序后顺序加入beanFactory的bean后处理集合中;

registerBeanPostProcessors方法执行完毕后,beanFactory中已经保存了有序的bean后置处理器,在bean实例化之后,会依次使用这些后置处理器对bean实例来做对应的处理;

initMessageSource

initMessageSource方法用来准备国际化资源相关的,将实现了MessageSource接口的bean存放在ApplicationContext的成员变量中,先看是否有配置,如果有就实例化,否则就创建一个DelegatingMessageSource实例的bean;

initApplicationEventMulticaster

spring中有事件、事件广播器、事件监听器等组成事件体系,在initApplicationEventMulticaster方法中对事件广播器做初始化,如果找不到此bean的配置,就创建一个SimpleApplicationEventMulticaster实例作为事件广播器的bean,并且保存为applicationContext的成员变量applicationEventMulticaster;

onRefresh

onRefresh是个空方法,留给子类自己实现的,在实例化bean之前做一些ApplicationContext相关的操作,以子类AbstractRefreshableWebApplicationContext为例,看看它的onRefresh方法:

@Override
protected void onRefresh() {this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}

可见是做了主题相关的初始化,并保存在ApplicationContext的成员变量中;

registerListeners

方法名为registerListeners,看名字像是将监听器注册在事件广播器中,但实际情况并非如此,只有一些特殊的监听器被注册了,那些在bean配置文件中实现了ApplicationListener接口的类还没有实例化,所以此处只是将其name保存在广播器中,将这些监听器注册在广播器的操作是在bean的后置处理器中完成的,那时候bean已经实例化完成了,我们看代码:

protected void registerListeners() {// 注册的都是特殊的事件监听器,而并非配置中的beanfor (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let post-processors apply to them!// 根据接口类型找出所有监听器的名称String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {// 这里只是把监听器的名称保存在广播器中,并没有将这些监听器实例化!!!getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}
}

finishBeanFactoryInitialization

finishBeanFactoryInitialization方法做了两件事:
1. beanFactory对象的初始化;
2. 我们在bean配置文件中配置的那些单例的bean,都是在finishBeanFactoryInitialization方法中实例化的;

看代码:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// Initialize conversion service for this context.// 实例化类型转换的bean,并保存在ApplicationContext中if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.// 实例化LoadTimeWeaverAware接口的bean,用于ApsectJ的类加载期织入的处理String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);}// Stop using the temporary ClassLoader for type matching.// 确保临时的classLoader为空,临时classLoader一般被用来做类型匹配的beanFactory.setTempClassLoader(null);// Allow for caching all bean definition metadata, not expecting further changes.// 将一个标志设置为true,表示applicationContext已经缓存了所有bean的定义,这些bean的name都被保存在applicationContext的frozenBeanDefinitionNames成员变量中,相当于一个快照,记录了当前那些bean的定义已经拿到了beanFactory.freezeConfiguration();// 实例化所有还未实例化的单例beanbeanFactory.preInstantiateSingletons();
}

上述代码中,beanFactory.preInstantiateSingletons()需要展开仔细看:

public void preInstantiateSingletons() throws BeansException {if (this.logger.isDebugEnabled()) {this.logger.debug("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {// 获取bean的定义,该定义已经和父类定义做了合并RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);// 非抽象类、是单例、非懒加载if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//FactoryBean的处理if (isFactoryBean(beanName)) {final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {@Overridepublic Boolean run() {return ((SmartFactoryBean<?>) factory).isEagerInit();}}, getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}else {//非FactoryBean的实例化、初始化getBean(beanName);}}}// Trigger post-initialization callback for all applicable beans...// 单例实例化完成后,如果实现了SmartInitializingSingleton接口,afterSingletonsInstantiated就会被调用,此处用到了特权控制逻辑AccessController.doPrivilegedfor (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {smartSingleton.afterSingletonsInstantiated();return null;}}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}}
}

上述代码中,要重点关注getBean(beanName),这里面会实例化bean,由于内容太多不适合在本章细说,这里先将实例化bean的调用路径整理出来:

AbstractBeanFactory.getBean(String name)->AbstractBeanFactory.doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly)->DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory)->AbstractBeanFactory.doGetBean中的匿名类的getObject方法->AbstractAutowireCapableBeanFactory.createBean(String beanName, RootBeanDefinition mbd, Object[] args) ->
AbstractAutowireCapableBeanFactory.doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args)->AbstractAutowireCapableBeanFactory.createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)->instantiateBean(final String beanName, final RootBeanDefinition mbd)->SimpleInstantiationStrategy.instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner)->BeanUtils.instantiateClass(Constructor<T> ctor, Object... args)->Constructor.newInstance(Object ... initargs)->bean的构造方法

以上调用路径可以看出,bean对象的创建是BeanUtils.instantiateClass方法通过反射来创建的;

再来看看bean的成员变量是什么时候被注入值的,如下图,AbstractAutowireCapableBeanFactory.doCreateBean方法中,先调用createBeanInstance创建bean的对象(绿框所示),再调用populateBean方法给成员变量注入内容(红框所示):

将注入值的调用堆栈整理如下,可见是也是通过反射完成注入的:

AbstractAutowireCapableBeanFactory.populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw)->AbstractAutowireCapableBeanFactory.applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)->AbstractPropertyAccessor.setPropertyValues(PropertyValues pvs)->BeanWrapperImpl.setPropertyValue(PropertyValue pv)->Method.invoke(Object obj, Object... args)

看过了成员变量注入的逻辑后,还有个重要的逻辑也请关注,就是bean的初始化(bean的配置文件中的init-method属性),AbstractAutowireCapableBeanFactory.doCreateBean方法中,在调用populateBean方法给成员变量注入值之后,马上调用initializeBean方法进行初始化操作,调用堆栈整理如下:

AbstractAutowireCapableBeanFactory.initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)->AbstractAutowireCapableBeanFactory.invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)->AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)->Method.invoke(Object obj, Object... args)

可见依旧是通过反射来执行初始化方法;

finishRefresh

最后一个方法是finishRefresh,这是在bean的实例化、初始化等完成后的一些操作,例如生命周期变更的回调,发送applicationContext刷新完成的广播等,展开看看:

protected void finishRefresh() {// 检查是否已经配置了生命周期处理器,如果没有就new一个DefaultLifecycleProcessorinitLifecycleProcessor();// 找到所有实现了Lifecycle接口的bean,按照每个bean设置的生命周期阶段进行分组,再依次调用每个分组中每个bean的start方法,完成生命周期监听的通知getLifecycleProcessor().onRefresh();// 创建一条代表applicationContext刷新完成的事件,交给广播器去广播publishEvent(new ContextRefreshedEvent(this));// 如果配置了MBeanServer,就完成在MBeanServer上的注册LiveBeansView.registerApplicationContext(this);
}

至此,整个初始化流程咱们已经过了一遍了,但是篇幅有限,很多细节都没有展开,另外很多子类也有自己独特的扩展,这些都需要花时间去细看,希望本文能帮您整理思路,从总体上了解初始化的各个关键步骤,以免过早陷入细节;

spring4.1.8初始化源码学习三部曲之三:AbstractApplicationContext.refresh方法相关推荐

  1. jQuery源码学习之五 (jQUery继承方法)

    jQuery 利用extend进行扩展. 参考jQuery API关于extend 的用法: $.extend([deep],target,object1,objectN) $.fn.extend(o ...

  2. 【源码学习】ScatteringByteChannel的read方法

    ScatteringByteChannel在java.nio.channels包中,继承了AutoCloseable, Channel, Closeable, ReadableByteChannel接 ...

  3. Spring IoC容器初始化源码(1)—容器初始化入口以及setConfigLocations设置容器配置信息【一万字】

      基于最新Spring 5.x,对于基于XML的Spring IoC容器初始化过程中的setConfigLocations设置容器配置信息方法的源码进行了详细分析,最后给出了比较详细的方法调用时序图 ...

  4. Spring Cloud 源码学习之 Hystrix 入门

    欢迎访问陈同学博客原文 Hystrix 功能非常多,本文仅对 Hystrix 源码做入门学习.为便于阅读,文中源码有较大删减,仅保留入门学习必要的源码,降低其他逻辑的干扰. 从 Hystrix 名字说 ...

  5. 菜鸟学源码之Nacos v1.1.3源码学习-Client模块(1):NacosNamingService初始化

    摘要: 本文是Nacos源码学习的第一篇,基于Nacos v1.1.3版本对Nacos源码进行学习,本片主要从exmaple的App示例入手,切入Nacos客户端NacosNamingService的 ...

  6. Spark-Core源码学习记录 3 SparkContext、SchedulerBackend、TaskScheduler初始化及应用的注册流程

    Spark-Core源码学习记录 该系列作为Spark源码回顾学习的记录,旨在捋清Spark分发程序运行的机制和流程,对部分关键源码进行追踪,争取做到知其所以然,对枝节部分源码仅进行文字说明,不深入下 ...

  7. Electron源码学习: Electron组成与初始化流程

    Electron源码学习: Electron组成与结构 前言 ​ 最近研究学习Electron的源码结构已经有一些小的进展, 越接触Electron就越发现组成这个软件的大集合不得了.现在学习到的仍然 ...

  8. Shiro源码学习之一

    一.最基本的使用 1.Maven依赖 <dependency><groupId>org.apache.shiro</groupId><artifactId&g ...

  9. mutations vuex 调用_Vuex源码学习(六)action和mutation如何被调用的(前置准备篇)...

    前言 Vuex源码系列不知不觉已经到了第六篇.前置的五篇分别如下: 长篇连载:Vuex源码学习(一)功能梳理 长篇连载:Vuex源码学习(二)脉络梳理 作为一个Web前端,你知道Vuex的instal ...

最新文章

  1. 如何理解机器学习中的嵌入 (Embeddings)?
  2. getInitParameter方法
  3. c语言 char operator,C语言取模运算符(modulus operator)“%”的作用是什么
  4. vb.net2019- 对象 (Visual Basic)
  5. 物流×科技,易流如何用IoT技术加速物流业数字化升级?...
  6. 《深度学习 500 问》已更新,GitHub 标星 2.6W
  7. mobile兼容性调整,根据rem,字体大小,视窗宽度
  8. 【C语言】03-第一个C程序代码分析
  9. python 定时任务 web管理_Selenium+WebDriver+Python 定时控制任务
  10. Typora主要常用快捷键
  11. c语言 字符串提取连续数字,c语言一串字符串中提取数字并相加的问题
  12. 手写SSH2服务器连接池
  13. 时区的转换nbsp;格林尼治标准时间(GMT…
  14. 金三银四:蚂蚁金服JAVA后端面试题及答案之二面
  15. Verilog语言初学1
  16. 《批量处理图片》批量把文件夹中的图片放到Excel中-Excel批量上传图片
  17. 华为交换机删除配置命令access_华为交换机基本配置命令
  18. 【Nexus】Nexus简介与安装
  19. 测试流程和测试用例设计方法
  20. 我愿称之为最容易上手的编程语言——Yaklang(I)

热门文章

  1. java rowid_什么是rowid?
  2. Laptop Ubuntu16.04/14.04 安装Nvidia显卡驱动
  3. php 去字符串空格函数,PHP 字符串去除空格函数trim
  4. 大一html5期末大作业 :基于html实现非遗文化网页设计题材-(坝漆国漆 2页 响应式)
  5. 三星s7android7,三星S7刷安卓7.0后,传承了Note7的一个卖点
  6. 2022-孤勇者-序言
  7. 是什么影响了MySQL索引B+树的高度?
  8. Unity动画☀️二、什么是按钮动画?什么是2D精灵动画?如果你想知道,我现在就带你研究!
  9. 超简单实现JavaScript在线编译器
  10. npm库v9介绍:对种子或磁力链截屏