new SpringApplication()主要过程
根据spring.factories配置文件,找到配置的应用上下文类(#Application Context Initializers)和监听器类(#Application Listeners),并根据反射机制创建相应对象,最后推断出包含main方法的主类。
1.推断应用web类型
默认是servlet
2.设置ApplicationContextInitializer和ApplicationListener
总结:通过读取spring.factories文件获取全部类全限定名--->根据Initializer和ApplicationListener获取对应类全限定名--->根据类全限定名使用反射方法创建对应的对象--->将对象赋值给SpringApplication对象的initializers属性。
this.initializers.addAll(initializers);
6个ApplicationContextInitializer
//核心方法
setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));
Class.forName(url);
class.getConstructor(class...).newInstance(param..)
(1)获取类全限定名
首先读取所有jar包中的spring.factories文件中的类全限定名,然后利用key、value存储到map中。再使用key = org.springframework.context.ApplicationContextInitializer,从map中获取对应的value值,获取到6个Initializer。
[org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,
org.springframework.boot.context.ContextIdApplicationContextInitializer,
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer,
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener]
(2)反射方式创建对象
forName(elementClassName, classLoader);//利用classloader和类全限定名获取class对象
instanceClass.getDeclaredConstructor(parameterTypes);//获取类的构造器
ctor.newInstance(args);//利用构造器创建对象
13个ApplicationListener
设置思路和上述Initializer一样。
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.listeners.addAll(listeners);//将获取到的listener对象设置到SpringApplication对象的属性中
[org.springframework.cloud.bootstrap.BootstrapApplicationListener,
org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,
org.springframework.cloud.context.restart.RestartListener,
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.context.logging.ClasspathLoggingApplicationListener,
org.springframework.boot.context.logging.LoggingApplicationListener,
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,
org.springframework.boot.autoconfigure.BackgroundPreinitializer]
3.推断出当前主类
总结:通过RuntimeException().getStackTrace()获取运行时堆栈信息,遍历堆栈元素方法名是否为“main”,利用Class.forName(className)推断出运行主类。
//根据栈中的方法名是否包含main,推断当前main方法所在的类
this.mainApplicationClass = deduceMainApplicationClass();
//deduceMainApplicationClass()核心代码
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}