spring boot 启动源码阅读(二)

上一篇www.jianshu.com/p/a2d575fb52f5中我们阅读完了构造方法所做的一些的事情。接下来就是SpringApplication中的run方法,いくぞ!!。直接上源码截图:

spring boot 启动源码阅读(二)_第1张图片
run方法

看着也不是太长,我们先看返回类型,ConfigurableApplicationContext  这是一个interface,单从名字直译成可配置的应用上下文,对spring了解的人肯定知道ApplicationContext,所以猜测估计是跟ApplicationContext有关系。我们看下此接口的父类关系图:


spring boot 启动源码阅读(二)_第2张图片
ConfigurableApplicationContext

继承了一个Closeable 接口,一个Lifecyle 生命周期接口,还有一个ApplicationContext接口,我们注意看ApplicationContext主要继承了BeanFactory和ResourceLoader的一些列子接口,加上一个ApplicationEventPublisher(事件发布)。也就是说ConfigurableApplicationContext具有资源加载,事件发布,IOC容器等功能。


然后我们看run的方法体。StopWatch类里面没什么东西,就是记录一些运行时间,运行的状态记录等,接着往下走。

1.this.configureHeadlessProperty() 设置是否是headless模式(java se的系统的一种设置模式,我也不清楚,具体请搜索),上一遍中构造函数初始化的其中一个成员变量headless在这里起到作用。

2.SpringApplicationRunListeners listeners =this.getRunListeners(args);  这个方法getRunListeners(args)跟构造函数的中的setInitializers和setListeners方法类似,会在spring.factories文件中寻找SpringApplicationRunListener对应的实现类的名字,并且利用反射构造实例,


spring boot 启动源码阅读(二)_第3张图片
图1

最终得到SpringApplicationRunListener接口的实现类EventPublishingRunListener的对象,并且该对象持有SpringApplication的引用,把EventPublishingRunListener对象实例放到SpringApplicationRunListeners这个容器里面,由SpringApplicationRunListeners对象来管理(其实就是一个ArrayList来存放,里面就一个EventPublishingRunListener实例)SpringApplicationRunListener的对象。

3.listeners.starting();spring正在启动, 此方法会遍历listeners容器(ArrayList)里面所有的SpringApplicationRunListener对象的starting方法,其实就是调用EventPublishingRunListener的starting()。关键的地方来了,请看好:


spring boot 启动源码阅读(二)_第4张图片
图2

我们看到starting的实现,里面有个SimpleApplicationEventMulticaster,这个对象就是负责广播ApplicationEvent事件,那么既然是广播事件,我们需要知道几件事情:1.听众是谁 2.什么事件 3听众如何接收.4接受到如何处理。我点开SimpleApplicationEventMulticaster的源码


spring boot 启动源码阅读(二)_第5张图片
SimpleApplicationEventMulticaster

    1.事件是什么,事件就是ApplicationStartedEvent(继承ApplicationEvent)。从类名上可以看出其实就是发出了一个应用开始启动的信号了。

    2. 听众呢?开始我以为 听众就是SpringApplication里的所有的ApplicationListener对象,这些对象 我们在上一篇中得知SpringApplication的构造函数中已经初始化好了。但是请看SimpleApplicationEventMulticaster里面的第二个multicastEvent方法 会调用getApplciationListeners,这个方法会对    SpringApplication  所持有的所有ApplicationListener对象做一个过滤,过滤那些能处理ApplicationStartedEvent事件的监听器,也就是说不是所有的ApplicationListener都对这个事件感兴趣或者说能处理改事件。最终有5个listener对该事件感兴趣。


spring boot 启动源码阅读(二)_第6张图片
处理ApplicationStartedEvent事件的ApplicationListener

    3.接下来就是事件的处理了,我们从SimpleApplicationEventMulticaster可以得出其实就是ApplicationListener的onApplication的方法处理接受到的event。那么这5个类如何处理,其实可以通过类名去猜测出一些东西,具体先留着后面去一个一个去解析。

稍微梳理一下就是 SpringApplicationRunListeners 这个对象是SpringApplicationRunListener对象集合的代理,整个应用的生命周期会触发SpringApplicationRunListeners里面的各个状态方法(starting,environmentPrepared,contextPrepared,contextLoaded,finished),换种说法就是监听着spring的各个生命周期。比如刚刚说的应用的starting状态,SpringApplicationRunListeners会让集合中的所有SpringApplicationRunListener对象的starting方去处理(在本例中,集合中只有一个对象 就是EventPublishingRunListener)。EventPublishingRunListener的处理方式就是让SpringApplication的的ApplicationListener的一些列相应对象去处理,具体就是通过SimpleApplicationEventMulticaster来广播各种事件给ApplicationListener。也就是说整个应用的几个状态或者说生命周期(启动状态,环境准备状态,上下文准备状态,上下文加载状态,结束状态),都会通知相应的ApplicationListener对象,然后ApplicationListener对象去做该做的事情。


spring boot 启动源码阅读(二)_第7张图片
EventPublishingRunListener



回到文章的开头,run方法接下来该走到try块里面了

先看DefaultApplicationArguments ex =new DefaultApplicationArguments(args);将传经来的参数args( 本例中其实就是一段字符串“--debug”,因为我是debug运行的)进行包装了一下。

然后ConfigurableEnvironment environment =this.prepareEnvironment(listeners,ex);


spring boot 启动源码阅读(二)_第8张图片
prepareEnvironment

主要创建了WEB环境的上下文,一个StandardEnvironment;方法this.configureEnvironment(environment,applicationArguments.getSourceArgs());配置好系统运行的所需要的环境,里面包含一些配置信息。接着是listeners.environmentPrepared(environment);跟上面的starting方法很像,发出了一个ApplicationEnvironmentPreparedEvent事件,广播给能处理该事件的listener,主要由以下这些:


spring boot 启动源码阅读(二)_第9张图片
处理ApplicationEnvironmentPreparedEvent事件的listener

再次回到run方法:

1.Banner printedBanner =this.printBanner(environment);会在控制台打印spring boot项目启动时候的图像等事情。就是下面这货


spring boot 启动源码阅读(二)_第10张图片

2.接下来是context =this.createApplicationContext();因为成员变量webEnvironment为false会创建一个AnnotationConfigApplicationContext对象,也是run方法返回的对象。

3.newFailureAnalyzers(context);实例化一堆错误分析器,项目启动报错了告诉你错误原因,实例化的过程跟前面实例化listener一模一样,都是套路。b( ̄▽ ̄)b

4.this.prepareContext(context,environment,listeners,ex,printedBanner);这一步做了很多事情,先简要的说下

spring boot 启动源码阅读(二)_第11张图片
prepareContext


1) 设置environment到context中;2)设置context到ApplicationContextInitializer中;3)广播一个contextPrepare事件;4)发起一个contextLoad事件

5.最后是一个contextFinish事件。

总结:spring从启动到启动结束中,各个生命周期广播相应的事件出去,然后各个监听器收到广播消息之后去做对应的事情。下面画的这张图算是自己的初步理解


spring boot 启动源码阅读(二)_第12张图片
spring boot启动的生命周期


但是第一篇中遗留的问题这篇文章并没有解释。。。留待以后吧!



spring boot 启动源码阅读(二)_第13张图片

你可能感兴趣的:(spring boot 启动源码阅读(二))