今天看了一下Spring Boot的run函数运行过程,发现它调用了Context中的refresh函数。所以先分析一下Spring context的refresh过程,然后再分析Spring boot中run的流程。

首先我们找到spring-context组件的AbstractApplicationContext类下的refresh函数:

    @Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
initMessageSource(); // Initialize event multicaster for this context.
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
onRefresh(); // Check for listener beans and register them.
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
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.
destroyBeans(); // Reset 'active' flag.
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();
}
}
}

prepareRefresh()

    protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true); ...... // Initialize any placeholder property sources in the context environment.
initPropertySources(); // Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties(); // Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
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<>();
}

可以看到,这个函数做了一些准备工作,记录了refresh的开始时间,调用了留给子类重写的initPropertySources()函数。

验证了环境中必要的参数,并且将earlyListeners加入到应用程序的监听器列表中。

obtainFreshBeanFactory()

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}

可以看见,refreshBeanFactory()和getBeanFactory()都是abstract函数,这两个函数设计出来就是为了让子类重写,根据子类实现具体功能,从函数名可以推断出这两个函数一个是用来初始化beanFactory,另外一个则是拿到beanFactory的实例,我们以AbstractRefreshableApplicationContext类的代码为例:

refreshBeanFactory:

    @Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {//如果beanFactory已经被初始化过,则在此销毁
destroyBeans();
closeBeanFactory();
}
try {//这里其实就是new了一个DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//客制化beanFactory,例如设置能否循环引用,能否重写bean等
customizeBeanFactory(beanFactory);
//将xml中的bean定义加载到spring-core的注册中心中
loadBeanDefinitions(beanFactory);
//设置beanFactory,供getBeanFactory取得
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

getBeanFactory:不难想象,这个函数从this类中拿到beanFactory实例并返回。

prepareBeanFactory(beanFactory)

篇幅原因就不贴这部分代码,实在太长,这个函数主要做了如下几件事:

1. 设置了beanFactory的classloader

2. 设置了SpEL的解析器

3. 设置了PropertyEditor,这个是用来将xml里面的占位符解析成具体值的,例如xml里面写<... value="${predefined-var}"/>,在PropertyEditor可以将${predefined-var}解析为某个具体值,并且到时候生成的beanDefinition对应的field就是这个具体的值。这一步会发生在xml被转换为beanDefinition之前

4. 增加ApplicationContextAwareProcessor的BeanPostProcessor,这个是为了让实现了ApplicationContextAware接口的bean在初始化后自身被注入当前的ApplicationContext,实现对自己所在的Context的感知

5. 忽略下述接口的依赖注入:

EnvironmentAware.class
EmbeddedValueResolverAware.class
ResourceLoaderAware.class
ApplicationEventPublisherAware.class
MessageSourceAware.class
ApplicationContextAware.class

观察上述接口的特征,发现这些都是Aware系列接口,用于使Bean感知环境中的参数(例如当前Context)。自动装配不会对这些接口进行处理,实际上实现了这些接口的类会在Spring中有专门的函数进行处理。

6. 对于一些特定的接口实现,定义默认的注入值:

BeanFactory.class
ResourceLoader.class
ApplicationEventPublisher.class
ApplicationContext.class

这些接口是用来获取关于Spring本身相关的信息的,例如Spring本身的BeanFactory等。

7. 注册一些环境相关的bean,例如systemProperties、systemEnvironment和environment

postProcessBeanFactory(beanFactory)

这个函数实际上是空的:

    /**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for registering special
* BeanPostProcessors etc in certain ApplicationContext implementations.
* @param beanFactory the bean factory used by the application context
*/
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

通过上面的注释,我们可以知道,当所有的xml已经被载入并且产生了对应的beanDefinition时,这个函数将会被调用,此时bean的实例都没有产生,在此处可以对beanDefinition的属性进行修改、抑或是注册特别的beanPostProcessor用于对实例化的bean做最终处理。

这里函数留空是为了让用户能够子类化,然后在里面写入自己需要的修改,典型的模板设计模式

invokeBeanFactoryPostProcessors(beanFactory)

调用所有在容器中注册的BeanFactoryPostProcessor

registerBeanPostProcessors(beanFactory)

注册BeanPostProcessors,将所有在xml中定义的beanPostProcessors加入到当前BeanFactory的列表,以便在getBean的时候调用。

initMessageSource()

初始化消息源

initApplicationEventMulticaster()

protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}

通过Spring容器得到一个applicationEventMulticaster,如果Spring容器没有定义,则创建SimpleApplicationEventMulticaster作为applicationEventMulticaster。

通过SimpleApplicationEventMulticaster的代码我们也能推断出这个类的作用,就是向Context里面的EventListener发布消息:

    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
//将当前的事件event发送给当前Context的每一个Listener
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//如果有executor则使用executor执行
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
//否则直接在当前线程执行
invokeListener(listener, event);
}
}
}

onRefresh()

这是模板方法,留给子类实现并执行想要的操作

registerListeners()

这一步将注册Listener,供前面initApplicationEventMulticaster注册的EventMulticaster进行广播,代码如下:

    protected void registerListeners() {
// Register statically specified listeners first.
for (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);
} // Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

这段代码将静态注册的Listener和Spring中注册的Listener bean都添加到EventMulticaster中,这样从EventMulticaster中发布的消息,每个Listener都能监听到,典型的观察者模式。

值得注意的是,Context中包含earlyApplicationEvents,所有的Listener就绪后,会先接收到这个事件。

finishBeanFactoryInitialization(beanFactory)

通过上面的注释:Instantiate all remaining (non-lazy-init) singletons.

我们可以知道,这个方法初始化所有的非懒加载单例实例,代码很复杂,后面会开一个专题分析这段代码的。

finishRefresh()

从函数名可以知道这个是完成刷新,代码如下:

    protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches(); // Initialize lifecycle processor for this context.
initLifecycleProcessor(); // Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh(); // Publish the final event.
publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}

实际上它:

1. 清空了资源缓存

2. 初始化了生命周期处理器,用于处理Bean生命周期

3. 使用生命周期处理器传播刷新事件

4. 在Context内发布刷新事件

5. 将本Context注册到ListBeansView中

至此,Context的refresh分析完毕,下一部该分析Spring Boot的run进行了什么操作了。

Spring context的refresh函数执行过程分析的更多相关文章

  1. 当spring 容器初始化完成后执行某个方法

    在做web项目开发中,尤其是企业级应用开发的时候,往往会在工程启动的时候做许多的前置检查. 比如检查是否使用了我们组禁止使用的Mysql的group_concat函数,如果使用了项目就不能启动,并指出 ...

  2. Spring Context 你真的懂了吗

    今天介绍一下大家常见的一个单词 context 应该怎么去理解,正确的理解它有助于我们学习 spring 以及计算机系统中的其他知识. 1. context 是什么 我们经常在编程中见到 contex ...

  3. 8 -- 深入使用Spring -- 5...2 使用@Cacheable执行缓存

    8.5.2 使用@Cacheable执行缓存 @Cacheable可用于修饰类或修饰方法,当使用@Cacheable修饰类时,用于告诉Spring在类级别上进行缓存 ------ 程序调用该类的实例的 ...

  4. 【报错】spring整合activeMQ,pom.xml文件缺架包,启动报错:Caused by: java.lang.ClassNotFoundException: org.apache.xbean.spring.context.v2.XBeanNamespaceHandler

    spring版本:4.3.13 ActiveMq版本:5.15 ======================================================== spring整合act ...

  5. MFC的执行过程分析

    MFC程序的执行细节剖析 MFC程序也是Windows程序,所以它应该也有一个WinMain.可是在程序中看不到它的踪影.事实上在程序进入点之前.另一个(并且仅有一个)全局对象(theApp).这就是 ...

  6. Spring容器的refresh()介绍

    Spring容器的refresh()[创建刷新]; 1.prepareRefresh()刷新前的预处理; 1).initPropertySources()初始化一些属性设置;子类自定义个性化的属性设置 ...

  7. Hi3559AV100 NNIE开发(2)-RFCN(.wk)LoadModel及NNIE Init函数运行过程分析

    之后随笔将更多笔墨着重于NNIE开发系列,下文是关于Hi3559AV100 NNIE开发(2)-RFCN(.wk)LoadModel及NNIE Init函数运行过程分析,通过对LoadModel函数及 ...

  8. Spring @Transaction 注解是如何执行事务的?

    前言 相信小伙伴一定用过 @Transaction 注解,那 @Transaction 背后的秘密又知道多少呢? Spring 是如何开启事务的?又是如何进行提交事务和关闭事务的呢? 画图猜测 在开始 ...

  9. 【转】Spring bean处理——回调函数

    Spring bean处理——回调函数 Spring中定义了三个可以用来对Spring bean或生成bean的BeanFactory进行处理的接口,InitializingBean.BeanPost ...

随机推荐

  1. python工业互联网应用实战11—客户端UI

    这个章节我们将演示用户端界面的开发,当前演示界面还是采用先实现基本功能再逐步完善的"敏捷"模式.首先聚焦在功能逻辑方面实现普通用户与系统的交互,普通用户通过url能查看到当前任务的 ...

  2. day-04-列表

    列表的初识 容器型数据类型,可以承载大量的数据,有序的数据 why:int bool str:'123 True 太白' str: 存储少量的数据. str:切片还是对其进行任何操作,获取的内容全都是 ...

  3. [Fundamental of Power Electronics]-PART I-1.引言-1.2 1.3 电力电子技术的几个应用、本书内容

    1.2 电力电子技术的几个应用 高效开关变换器面临的功率范围从 (1)小于1瓦(电池供电的便携式设备内的DC-DC转换器)到(2)计算机及办公设备中的几十,几百,数千瓦到(3)变速电机驱动器中上千瓦及 ...

  4. ognl表达式应用场景和用法

    ognl表达式的用法和应用场景 1.配置文件 //书写方式是:'${@类全限定名@常量}' dic_city.type=${@com.imooc.constant.DictionaryConstant ...

  5. 1-Hyperledger Fabric概念详解

    目录 一.Hyperledger Fabric概述 二.基本术语 1.共享账本ledger 2.通道Channel 3.组织Org 4.智能合约Chaincode 5.背书Endorse 6.各种节点 ...

  6. Civil3d中 如何用管轴线的变坡点桩号控制其他纵断面数据的显示?

    如何用管轴线的变坡点桩号控制其他纵断面数据的显示?如下图所示: 主要进行两步操作,下面以地面高程为例. 第1步: 右键纵断面图,打开纵断面图特性对话框,选择"标注栏"选项卡,分别设 ...

  7. 浅入Kubernetes(11):了解 Service 和 Endpoint

    目录 Srevice Service 的创建及现象 Service 定义 Endpoint slices 创建 Endpoint.Service Service 创建应用 创建 Endpoint 浅入 ...

  8. 你已经用上 5G 网络了吗?

    随着各大手机厂商陆续推出 5G 手机,智能手机全面迎来 5G 浪潮.可能有人会发问:如此推崇 5G,5G 能为我们带来什么,我们的生活又会因此而改变多大呢? 什么是 5G? 简单地说,5G 就是第五代 ...

  9. 2021S软件工程——案例分析作业

    2021S软件工程--案例分析作业 18231169 黄思为 项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任建) 这个作业的要求在哪里 案例分析作业 我在这个课程的目标是 了解并熟悉 ...

  10. 1025 PAT Ranking

    Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of Zhe ...