上一篇www.jianshu.com/p/a2d575fb52f5中我们阅读完了构造方法所做的一些的事情。接下来就是SpringApplication中的run方法,いくぞ!!。直接上源码截图:
![](https://img.haomeiwen.com/i1642079/b6f5c0d59dc78856.png)
看着也不是太长,我们先看返回类型,ConfigurableApplicationContext 这是一个interface,单从名字直译成可配置的应用上下文,对spring了解的人肯定知道ApplicationContext,所以猜测估计是跟ApplicationContext有关系。我们看下此接口的父类关系图:
![](https://img.haomeiwen.com/i1642079/77429eb41be8ff54.png)
继承了一个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对应的实现类的名字,并且利用反射构造实例,
![](https://img.haomeiwen.com/i1642079/96a471e9f718eb35.png)
最终得到SpringApplicationRunListener接口的实现类EventPublishingRunListener的对象,并且该对象持有SpringApplication的引用,把EventPublishingRunListener对象实例放到SpringApplicationRunListeners这个容器里面,由SpringApplicationRunListeners对象来管理(其实就是一个ArrayList来存放,里面就一个EventPublishingRunListener实例)SpringApplicationRunListener的对象。
3.listeners.starting();spring正在启动, 此方法会遍历listeners容器(ArrayList)里面所有的SpringApplicationRunListener对象的starting方法,其实就是调用EventPublishingRunListener的starting()。关键的地方来了,请看好:
![](https://img.haomeiwen.com/i1642079/12f0128da73370a5.png)
我们看到starting的实现,里面有个SimpleApplicationEventMulticaster,这个对象就是负责广播ApplicationEvent事件,那么既然是广播事件,我们需要知道几件事情:1.听众是谁 2.什么事件 3听众如何接收.4接受到如何处理。我点开SimpleApplicationEventMulticaster的源码
![](https://img.haomeiwen.com/i1642079/d2720053046fd367.png)
1.事件是什么,事件就是ApplicationStartedEvent(继承ApplicationEvent)。从类名上可以看出其实就是发出了一个应用开始启动的信号了。
2. 听众呢?开始我以为 听众就是SpringApplication里的所有的ApplicationListener对象,这些对象 我们在上一篇中得知SpringApplication的构造函数中已经初始化好了。但是请看SimpleApplicationEventMulticaster里面的第二个multicastEvent方法 会调用getApplciationListeners,这个方法会对 SpringApplication 所持有的所有ApplicationListener对象做一个过滤,过滤那些能处理ApplicationStartedEvent事件的监听器,也就是说不是所有的ApplicationListener都对这个事件感兴趣或者说能处理改事件。最终有5个listener对该事件感兴趣。
![](https://img.haomeiwen.com/i1642079/9e0baba1848401b2.png)
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对象去做该做的事情。
![](https://img.haomeiwen.com/i1642079/07f724ad311e5e41.png)
回到文章的开头,run方法接下来该走到try块里面了
先看DefaultApplicationArguments ex =new DefaultApplicationArguments(args);将传经来的参数args( 本例中其实就是一段字符串“--debug”,因为我是debug运行的)进行包装了一下。
然后ConfigurableEnvironment environment =this.prepareEnvironment(listeners,ex);
![](https://img.haomeiwen.com/i1642079/9237f4d78d1cfe8b.png)
主要创建了WEB环境的上下文,一个StandardEnvironment;方法this.configureEnvironment(environment,applicationArguments.getSourceArgs());配置好系统运行的所需要的环境,里面包含一些配置信息。接着是listeners.environmentPrepared(environment);跟上面的starting方法很像,发出了一个ApplicationEnvironmentPreparedEvent事件,广播给能处理该事件的listener,主要由以下这些:
![](https://img.haomeiwen.com/i1642079/d0b8da23a65494e8.png)
再次回到run方法:
1.Banner printedBanner =this.printBanner(environment);会在控制台打印spring boot项目启动时候的图像等事情。就是下面这货
![](https://img.haomeiwen.com/i1642079/58d3388237632f02.png)
2.接下来是context =this.createApplicationContext();因为成员变量webEnvironment为false会创建一个AnnotationConfigApplicationContext对象,也是run方法返回的对象。
3.newFailureAnalyzers(context);实例化一堆错误分析器,项目启动报错了告诉你错误原因,实例化的过程跟前面实例化listener一模一样,都是套路。b( ̄▽ ̄)b
4.this.prepareContext(context,environment,listeners,ex,printedBanner);这一步做了很多事情,先简要的说下
![](https://img.haomeiwen.com/i1642079/cea45d712324fc1e.png)
1) 设置environment到context中;2)设置context到ApplicationContextInitializer中;3)广播一个contextPrepare事件;4)发起一个contextLoad事件
5.最后是一个contextFinish事件。
总结:spring从启动到启动结束中,各个生命周期广播相应的事件出去,然后各个监听器收到广播消息之后去做对应的事情。下面画的这张图算是自己的初步理解
![](https://img.haomeiwen.com/i1642079/ace8b48331018435.png)
但是第一篇中遗留的问题这篇文章并没有解释。。。留待以后吧!
![](https://img.haomeiwen.com/i1642079/ace632241208a955.jpeg)
网友评论