springboot的启动都是从main方法开始的,如下:
@SpringBootApplication
public class
Application {
public static void
main
(String[] args) {
SpringApplication.
run
(Application.
class,
args)
;
}
}
后面会进入SpringApplication的初始化方法:
public static
ConfigurableApplicationContext
run
(Object[] sources
,
String[] args) {
return new
SpringApplication(sources).run(args)
;
}
public
SpringApplication
(Object... sources) {
initialize(sources)
;
}
我们进入initialize(Object[] sources)查看逻辑:
private void
initialize
(Object[] sources) {
if
(sources !=
null
&& sources.
length
>
0
) {
this
.
sources
.addAll(Arrays.
asList
(sources))
;
}
this
.
webEnvironment
= deduceWebEnvironment()
;
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.
class
))
;
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.
class
))
;
this
.
mainApplicationClass
= deduceMainApplicationClass()
;
}
deduceWebEnvironment()方法是验证是否有web运行的环境,方法就是查看下tomcat以及spring中的某个类是否存在,以此来验证是否有web环境运行条件,代码如下:
private boolean
deduceWebEnvironment
() {
for
(String className :
WEB_ENVIRONMENT_CLASSES
) {
if
(!ClassUtils.
isPresent
(className
, null
)) {
return false;
}
}
return true;
}
initialize()方法中的第二个方法就是
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
这个方法后面会进入getSpringFactoriesInstances方法,其内容如下:
private Collection extends T> getSpringFactoriesInstances(Class type,
Class>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set names = new LinkedHashSet(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
上面方法中:
- 第一个方法获取了当前加载类的classLoader,即加载第三方类库的AppClassLoader。
- 第二个方法是加载了所有jar包以及classes下面的所有“META-INF/spring.factories”文件,并将其key为“org.springframework.context.ApplicationContextInitializer”的所有value放入了一个集合中,为了避免重复,放入了一个Set集合中将数据返回。其包含的类型有如下几种,即names的Set集合中的值有如下几种:
0 = "org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer"
1 = "org.springframework.boot.context.ContextIdApplicationContextInitializer"
2 = "org.springframework.boot.context.config.DelegatingApplicationContextInitializer"
3 = "org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer"
4 = "org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
5 = "org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer"
3.第三个方法createSpringFactoriesInstances是创建了上述类型的实例,
4.第四个方法AnnotationAwareOrderComparator.sort(instances);会根据AnnotationAwareOrderComparator的排序规则进行排序执行,将instances进行排序。
最后在外面将这些排序好的initializers设置到了SpringApplication的initializers的属性之中。
在springApplication的initialize方法的后面一个方法setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));中是设置org.springframework.context.ApplicationListener类的实例到类SpringApplication的listeners属性当中。
springApplication的initialize方法中的最后一个方法this.mainApplicationClass = deduceMainApplicationClass();是获取启动类,其方法如下:
private Class> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
是通过RuntimeException寻找栈轨迹打印的方法中获取main方法的类,以此来获得启动类。
至此,关于initialize方法的所有过程就说完了。下面我们就要进入run方法的过程说明了。