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

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

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. // Prepare this context for refreshing.
  5. prepareRefresh();
  6.  
  7. // Tell the subclass to refresh the internal bean factory.
  8. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  9.  
  10. // Prepare the bean factory for use in this context.
  11. prepareBeanFactory(beanFactory);
  12.  
  13. try {
  14. // Allows post-processing of the bean factory in context subclasses.
  15. postProcessBeanFactory(beanFactory);
  16.  
  17. // Invoke factory processors registered as beans in the context.
  18. invokeBeanFactoryPostProcessors(beanFactory);
  19.  
  20. // Register bean processors that intercept bean creation.
  21. registerBeanPostProcessors(beanFactory);
  22.  
  23. // Initialize message source for this context.
  24. initMessageSource();
  25.  
  26. // Initialize event multicaster for this context.
  27. initApplicationEventMulticaster();
  28.  
  29. // Initialize other special beans in specific context subclasses.
  30. onRefresh();
  31.  
  32. // Check for listener beans and register them.
  33. registerListeners();
  34.  
  35. // Instantiate all remaining (non-lazy-init) singletons.
  36. finishBeanFactoryInitialization(beanFactory);
  37.  
  38. // Last step: publish corresponding event.
  39. finishRefresh();
  40. }
  41.  
  42. catch (BeansException ex) {
  43. if (logger.isWarnEnabled()) {
  44. logger.warn("Exception encountered during context initialization - " +
  45. "cancelling refresh attempt: " + ex);
  46. }
  47.  
  48. // Destroy already created singletons to avoid dangling resources.
  49. destroyBeans();
  50.  
  51. // Reset 'active' flag.
  52. cancelRefresh(ex);
  53.  
  54. // Propagate exception to caller.
  55. throw ex;
  56. }
  57.  
  58. finally {
  59. // Reset common introspection caches in Spring's core, since we
  60. // might not ever need metadata for singleton beans anymore...
  61. resetCommonCaches();
  62. }
  63. }
  64. }

prepareRefresh()

  1. protected void prepareRefresh() {
  2. // Switch to active.
  3. this.startupDate = System.currentTimeMillis();
  4. this.closed.set(false);
  5. this.active.set(true);
  6.  
  7. ......
  8.  
  9. // Initialize any placeholder property sources in the context environment.
  10. initPropertySources();
  11.  
  12. // Validate that all properties marked as required are resolvable:
  13. // see ConfigurablePropertyResolver#setRequiredProperties
  14. getEnvironment().validateRequiredProperties();
  15.  
  16. // Store pre-refresh ApplicationListeners...
  17. if (this.earlyApplicationListeners == null) {
  18. this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
  19. }
  20. else {
  21. // Reset local application listeners to pre-refresh state.
  22. this.applicationListeners.clear();
  23. this.applicationListeners.addAll(this.earlyApplicationListeners);
  24. }
  25.  
  26. // Allow for the collection of early ApplicationEvents,
  27. // to be published once the multicaster is available...
  28. this.earlyApplicationEvents = new LinkedHashSet<>();
  29. }

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

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

obtainFreshBeanFactory()

  1. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  2. refreshBeanFactory();
  3. return getBeanFactory();
  4. }

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

refreshBeanFactory:

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

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)

这个函数实际上是空的:

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

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

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

invokeBeanFactoryPostProcessors(beanFactory)

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

registerBeanPostProcessors(beanFactory)

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

initMessageSource()

初始化消息源

initApplicationEventMulticaster()

  1. protected void initApplicationEventMulticaster() {
  2. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  3. if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
  4. this.applicationEventMulticaster =
  5. beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
  6. if (logger.isTraceEnabled()) {
  7. logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
  8. }
  9. }
  10. else {
  11. this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
  12. beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
  13. if (logger.isTraceEnabled()) {
  14. logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
  15. "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
  16. }
  17. }
  18. }

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

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

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

onRefresh()

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

registerListeners()

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

  1. protected void registerListeners() {
  2. // Register statically specified listeners first.
  3. for (ApplicationListener<?> listener : getApplicationListeners()) {
  4. getApplicationEventMulticaster().addApplicationListener(listener);
  5. }
  6.  
  7. // Do not initialize FactoryBeans here: We need to leave all regular beans
  8. // uninitialized to let post-processors apply to them!
  9. String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
  10. for (String listenerBeanName : listenerBeanNames) {
  11. getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  12. }
  13.  
  14. // Publish early application events now that we finally have a multicaster...
  15. Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
  16. this.earlyApplicationEvents = null;
  17. if (earlyEventsToProcess != null) {
  18. for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
  19. getApplicationEventMulticaster().multicastEvent(earlyEvent);
  20. }
  21. }
  22. }

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

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

finishBeanFactoryInitialization(beanFactory)

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

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

finishRefresh()

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

  1. protected void finishRefresh() {
  2. // Clear context-level resource caches (such as ASM metadata from scanning).
  3. clearResourceCaches();
  4.  
  5. // Initialize lifecycle processor for this context.
  6. initLifecycleProcessor();
  7.  
  8. // Propagate refresh to lifecycle processor first.
  9. getLifecycleProcessor().onRefresh();
  10.  
  11. // Publish the final event.
  12. publishEvent(new ContextRefreshedEvent(this));
  13.  
  14. // Participate in LiveBeansView MBean, if active.
  15. LiveBeansView.registerApplicationContext(this);
  16. }

实际上它:

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. 攻防世界 reverse 进阶 notsequence

    notsequence  RCTF-2015 关键就是两个check函数 1 signed int __cdecl check1_80486CD(int a1[]) 2 { 3 signed int ...

  2. java位运算求一个整数的绝对值

    1 import java.util.Scanner; 2 3 public class Question1 { 4 public static void main(String[] args) { ...

  3. 第28 章 : 理解容器运行时接口 CRI

    理解容器运行时接口 CRI CRI 是 Kubernetes 体系中跟容器打交道的一个非常重要的部分.本文将主要分享以下三方面的内容: CRI 介绍 CRI 实现 相关工具 CRI 介绍 在 CRI ...

  4. CyclicBarrier:人齐了,老司机就可以发车了!

    上一篇咱讲了 CountDownLatch 可以解决多个线程同步的问题,相比于 join 来说它的应用范围更广,不仅可以应用在线程上,还可以应用在线程池上.然而 CountDownLatch 却是一次 ...

  5. 问题笔记 - element表格 操作状态值

    1.必须从传到表里的数据源中取值(scope.row.star)

  6. 【算法学习笔记】组合数与 Lucas 定理

    卢卡斯定理是一个与组合数有关的数论定理,在算法竞赛中用于求组合数对某质数的模. 第一部分是博主的个人理解,第二部分为 Pecco 学长的介绍 第一部分 一般情况下,我们计算大组合数取模问题是用递推公式 ...

  7. [面试仓库]HTML面试题汇总

      HTML这一块呢,说简单也简单,说难也不是那么容易.但我们在各个面试要求中,大部分都把HTML这一条摆在了第一位,重要性可想而知.这个位置算是有关HTML的一个汇总点了,亦会在这里及时补充. 1, ...

  8. oo第四单元与课程总结

    Part1 本单元三次作业架构设计总结 1.组织结构 由于官方代码中已经给我们提供了许多零散的类元素,如UmlClass``UmlAssociation``UmlParameter等,因此我首先将某些 ...

  9. JDBC_05_ResorceBundle(资源绑定器) 绑定配置文件

    ResorceBundle(资源绑定器) 绑定配置文件 jdbc.proprtise 需要在src目录下新建一个文件夹然后将jdbc.proprtise放在文件中然后右键该文件夹选择 Rebuild ...

  10. elasticsearch jvm优化

    测试环境elasticsearch jvm 4G jdk1.8 [serveradm@test-log-server elasticsearch]$ java -version java versio ...