spring IOC 容器启动加载过程

在Springboot下容器启动的处理方法分析:
下个这个方法就是启动调用的方法了,下面分析下

第一个方法:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
ArrayList exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
//获取SpringApplicationRunListener实例,#getRunListeners方法根据SpringApplicationRunListener接口类型去加载其在springboot jar包下的spring.factories配置的实现类。有且只有一个EventPublishingRunListener实现。该类初始化一个spring事件传播管理器 SimpleApplicationEventMulticaster,后续实现 ApplicationEvent接口的事件类型均由该类去处理。
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//发布一个ApplicationStartingEvent事件
listeners.starting();

    Collection exceptionReporters1;
    try {
  //获取命令行启动参数,并作为IOC容器的环境变量初始化进去
        DefaultApplicationArguments ex = new DefaultApplicationArguments(args);
 //创建environment,装配PropertySources ,values: 

“defaultProperties”,"springApplicationCommandLineArgs",配置activeProfiles。发布ApplicationEnvironmentPreparedEvent 事件(可以通过实现该事件监听来修改IOC环境变量,在启动阶段),
最后将处理化好的environment 关联至 ”configurationProperties“ 属性上。
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, ex);
this.configureIgnoreBeanInfo(environment);
//可以配置启动时日志打印的banner
Banner printedBanner = this.printBanner(environment);
//根据webApplicationType 类型来创建,一般web容器使用的 AnnotationConfigServletWebServerApplicationContext,默认 AnnotationConfigApplicationContext,reactive 峰哥使用 AnnotationConfigReactiveWebServerApplicationContext,目前我们主要使用的是 第一种。
//AnnotationConfigApplicationContext类的构造时会调用refresh方法,该方法会构造IOC的核心。可转至下面refresh方法分析。
context = this.createApplicationContext();
exceptionReporters1 = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, new Object[]{context});
//这个可以用于springboot 特有的功能,比如上面的事件SpringApplicationRunListener接口可以拓展这个接口的实现方法contextPrepared 方法的调用用于applicationContext 的处理。以及特有的Bean实例的注册。
this.prepareContext(context, environment, listeners, ex, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, ex);
stopWatch.stop();
if(this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}

        listeners.started(context);
        this.callRunners(context, ex);
    } catch (Throwable var10) {
        this.handleRunFailure(context, var10, exceptionReporters, listeners);
        throw new IllegalStateException(var10);
    }

    try {
        listeners.running(context);
        return context;
    } catch (Throwable var9) {
        this.handleRunFailure(context, var9, exceptionReporters1, (SpringApplicationRunListeners)null);
        throw new IllegalStateException(var9);
    }
}

第二个方法:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//如果是servlet 容器,需要将servletConfig 加载进 environment
//初始化 earlyApplicationEvents 可以尽早执行的事件,等到 事件传播器一旦可以使用就去执行。
// Prepare this context for refreshing.
prepareRefresh();
//构建beanFactory,可以发现实际上 new DefaultListableBeanFactory。可以配置beanFactory 是否支持 allowBeanDefinitionOverriding,allowCircularReferences(单例bean之间是可以相互引用的)。然后进行beanDefine 的加载。这其中就不得不提到 ClassPathBeanDefinitionScanner ,这个类主要干的是就是将 @Component注解、@ManagedBean、@Name 标注的类信息扫描进registry 中。
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 在这过程中实在配置上面beanFactory,包括aware接口类型应该在后续autoaware时被忽略注入,以及BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext这类接口实现类应该在后续辅助解析依赖时得到应用。其中有两个beanPostProcess 实现类被加入beanFactory的beanPostProcessors列表中
ApplicationContextAwareProcessor 类的作用是对 实现了aware接口的bean 的对应属性的赋值。
ApplicationListenerDetector 类的作用是在Bean 在初始化后来判断当前bean 是够是一个事件监听单例bean是就会把当前bean 加在事件传播器中。

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        try {
                             //运行其子类自己特有的beanPostProcess 添加进去来完成beanPostProcess列表的完善。
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);
                            //调用 BeanFactoryPostProcessor 接口实现类,如果为 
                           BeanDefinitionRegistryPostProcessor接口实现类,则说明该类还会做一些beanDefinition 的解析工作。其他的实现类被区分为 常规的beanFactoryPostProcess 实现类。按照优先级先后执行BeanDefinitionRegistryPostProcessor实现类的方法。最后再按照优先级再去执行常规的beanProcess 。实现优先级的排序可参考实现 PriorityOrdered.class 或者 Order.class接口。
            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);
                              //这里是注册BeanPostProcess 接口实现类,也是按照优先级前后,再按照如果是 MergedBeanDefinitionPostProcessor 要优先于常规类先去处理,
            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();
                            //初始化事件传播器,spring-boot是在一开始就初始化了
            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();
                            //一个是将已经初始化好的listener Bean 加入传播器列表,二是将 listener bean的全部beanName 加入列表,这个地方是说 factoryBeans 还未初始化,三是将earlyApplicationEvents中的事件去执行。
            // Check for listener beans and register them.
            registerListeners();
                            //再去完善一下beanFactory 的属性:PropertyPlaceholderConfigurer的EmbeddedValueResolver,值解析器,最后出发非延迟加载Bean 的初始化。
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
                            //发布 ContextRefreshedEvent事件,并将bean注册进Mbean 管理。
            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();
        }
    }
}

第三部分:
关于Factorybean 的初始化,实现factorybean 接口的bean 会被spring先初始化,其beanName 为$beanName,
其getObject() 返回的beanName 的bean 会根据适配条件去看是否会同步被初始化。如果是 实现的 SmartFactoryBean 接口的bean 并且其isEagerInit 方法被覆写成 true,怎会同步被初始化。

第四部分:doGetBean 的方法 也就是 bean 的初始化过程

这部分方法叙述一下,在调用 createBean 方法时, 的实现类会被调用,再到执行 doCreateBean 方法,其中的 populateBean 方法可以在初始化化bean 前给一次修改bean field 的机会如果存在 InstantiationAwareBeanPostProcessor 接口的实现类。再执行initializeBean方法,先执行

BeanNameAware-》BeanClassLoaderAware-》BeanFactoryAware 属性的设值。再去执行 beanProcessor#postProcessBeforeInitializatio所有方法。再去执行 InitializingBean 的初始化方法。最后执行
beanProcessor#postProcessAfterInitialization来完成bean 初始化。

总结一下,spring框架中很多地方都是使用beanProcessor 接口来干预 bean 的生成。这是因为单例bean 在生成的过程中少不了执行其中的方法。

第五部分关于几个注解的处理逻辑位置:
@AutoAware @Value @Inject->AutowiredAnnotationBeanPostProcessor

@PostConstruct @PreDestroy-》CommonAnnotationBeanPostProcessor

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容