注明:以下内容基于spring-boot-1.4.2,starter为spring-boot-starter-web。

第一步,从启动过程开始。

上面是官方提供的一个简单的启动类,就从这几行简单的代码开始学习框架吧。
和普通java程序一样,main作为入口函数。在启动类中只有一行,直接调用org.springframework.boot.SpringApplication类中的静态run方法,传入启动类的Class对象与启动时所带的参数【可选】;通过该静态方法,实例化SpringApplication,同时调用实例run方法。

在SpringApplication的构造函数中,调用私有的initialize方法进行变量的初始化。

初始化内容包括4项,分别为sources,webEnvironment,初始化器,监听器和mainApplicationClass,除了sources为直接填充外,其它几项都是通过调用方法完成初始化。接下来我们逐一来看。
webEnvironment初始化
调用私有方法deduceWebEnvironment,在该方法中会检查项目中是否引入了web工程所必要的类并且可以被加载,包括javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext,在ClassUtils.isPresent方法中会尝试找到并且进行类加载,任何一个类不满足要求,都会返回false。因为webEnvironment的含义应该是是否满足web工程运行条件。

初始化器Initializers
首先通过调用私有的getSpringFactoriesInstances方法获取ApplicationContextInitializer或者其子类的实例集合。

获取初始化器的方法步骤比较多,有多层嵌套,我们一层层看。第一步是获取当前线程所运行的类加载器,这个没有疑问。第二步是加载配置文件,获取到初始化器的类名。

我们再看看spring.factories中包含的内容,key为org.springframework.context.ApplicationContextInitializer。

此时Set names中包含了上述四个类名。紧接这就是实例化。

在私有方法createSpringFactoriesInstances中,使用反射机制对获取的4个类分别进行了实例化,放在ArrayList中并返回对象集合。在这里,这四个初始化器都实现了ApplicationContextInitializer接口,实现了仅有的initialize方法,各自负责不同的模块初始化逻辑。

到这里,涉及到的初始化器的实例全部准备就绪,但是初始化工作还没有开展,每个初始化器的具体工作会在执行初始化的时候再详细介绍。在代码中有两个工具类用屡次被使用:
1. 一个是org.springframework.beans.BeanUtils,这个类中包含了一些java bean的静态方法,主要使用反射机制来初始化类,检查属性,拷贝属性等。
2.还有一个是org.springframework.util.ClassUtils,这个类包含各种Class对象操作,包括获取报名,方法名等等。
以上工具类主要在spring内部使用,但是很多静态方法都是公共的,在自己的程序中如果有需要应该也可以使用吧。
在获取了初始化器实例以后,还需要对实例进行排序,

使用的比较器就是AnnotationAwareOrderComparator,在上述四个初始化器中,只有DelegatingApplicationContextInitializer实现了Ordered接口,并设置order值为0,其它初始化器没有设置,使用默认的最低优先级,从而区分出在集合中与后续执行的先后顺序,并全部填充到SpringApplication的initializers中去。
设置监听器
获取监听器实例的过程和获取初始化器的过程是相同的,不同的是监听器的配置key在spring.factories中使用的是org.springframework.context.ApplicationListener。
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener
同样,这个key也是上述监听器共同的实现接口。不同的监听器职责不同,详细的职责还需要再进一步深入挖掘。

设置mainApplicationClass
通过RuntimeException的异常实例的错误栈信息来获取main函数所在的类,并返回类的Class对象。比直接使用传进来的sources更保险。

自此,才完成SpringApplication的实例化。
网友评论