docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(一):准备SpringApplication.md
̽ springboot ģʹõ demo λ?gitee/funcy.
Demo01Application#main(...)?ʼspringboot ʽdzһУ
@SpringBootApplication
public class Demo01Application {
public static void main(String[] args) {
// һоspringboot
SpringApplication.run(Demo01Application.class, args);
}
}
ȻǾͽʲô
public class SpringApplication {
...
// primarySource Ǵ Demo01Application.class
// args main() IJ
public static ConfigurableApplicationContext run(
Class<?> primarySource, String... args) {
// primarySource װ飬 run(...)
return run(new Class<?>[] { primarySource }, args);
}
// primarySources Ǵ Demo01Application.class װɵ飬
// args main() IJ
public static ConfigurableApplicationContext run(
Class<?>[] primarySources, String[] args) {
// ↑ʼ
return new SpringApplication(primarySources).run(args);
}
...
}
ͨһȥ?SpringApplication#run(Class<?>[], String[])?ؼ£
return new SpringApplication(primarySources).run(args);
ҪԲ֣
SpringApplication#SpringApplication(Class<?>...)SpringApplication#run(String...)springboot ˣǾ
SpringApplication``SpringApplication#SpringApplication(Class<?>...)public class SpringApplication {
public SpringApplication(Class<?>... primarySources) {
//
this(null, primarySources);
}
/**
* յõĹ췽
* resourceLoader Ϊ null
* primarySources Ϊ Demo01Application.class
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 1\. resourceLoaderõԱֵΪnull
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 2\. primarySourcesõԱֵΪ Demo01Application.class
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 3\. ǰ web ӦͣREACTIVENONESERVLET
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 4\. óʼgetSpringFactoriesInstances META-INF/spring.factories лȡ
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 5\. ügetSpringFactoriesInstances META-INF/spring.factories лȡ
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 6\. ذmain()class
this.mainApplicationClass = deduceMainApplicationClass();
}
}
»DZȽģݶڴעˣЩҪչǾ
WebApplicationType.deduceFromClasspath()WebApplicationType.deduceFromClasspath()?ƶϵǰĿʲô͵ģ£
public enum WebApplicationType {
// web Ӧ
NONE,
// servlet ͵ web Ӧ
SERVLET,
// reactive ͵ web Ӧ
REACTIVE;
...
private static final String[] SERVLET_INDICATOR_CLASSES = {
"javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS
= "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS
= "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS
= "org.glassfish.jersey.servlet.ServletContainer";
static WebApplicationType deduceFromClasspath() {
// classpath н WEBFLUX
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
// classpath SERVLET
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// Ĭ web Ϊ SERVLET
// Ҳ˵ͬʱ WEBFLUX SERVLET ࣬շص SERVLET
return WebApplicationType.SERVLET;
}
...
}
Կspringboot ĿͣNONE( web Ӧ)SERVLET(servlet?͵ web Ӧ)REACTIVE(reactive?͵ web Ӧ)WebApplicationType.deduceFromClasspath()?ִ£
classpath?н?WEBFLUX?࣬ǰĿ?reactive?͵ web Ӧãأclasspath?в?SERVLET?࣬ǰĿ web Ӧãأservlet?͵ web Ӧádemo ?spring-boot-starter-web?˵ǰĿ?servlet?͵ web Ӧá
setInitializers(...)£
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
дΪ:
ApplicationContextInitializer``getSpringFactoriesInstances(ApplicationContextInitializer.class)setInitializers(...)ȡ?ApplicationContextInitializer?̣£
public class SpringApplication {
...
// type Ϊ ApplicationContextInitializer.class
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
/**
* type Ϊ ApplicationContextInitializer.class
* parameterTypes Ϊ ew Class<?>[] {}
* args Ϊ null
*/
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// META-INF/spring.factories
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// ʵʹõķ
List<T> instances = createSpringFactoriesInstances(
type, parameterTypes, classLoader, args, names);
// Ƚϵ @Order ע⣬ʵֵ Orderd ӿ
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
...
}
ϴȽϼȴ?META-INF/spring.factories?ȡݣȻʹ÷ʵٷء
?SpringFactoriesLoader.loadFactoryNames(...)ջ?META-INF/spring.factories?ݣMETA-INF/spring.factories?Ϊһļkey Ϊ type÷ϸԲο?springboot Զװ֮Զװ
ջжٸ?ApplicationContextInitializer?ؽأͨԣһ 7
7 ?ApplicationContextInitializer˵£
ConfigurationWarningsApplicationContextInitializer IOC һЩĴContextIdApplicationContextInitializer Spring Ӧĵ IDDelegatingApplicationContextInitializer?application.properties??context.initializer.classes?õRSocketPortInfoApplicationContextInitializer?RSocketServer?ʵʹõļ˿д뵽?Environment?ServerPortInfoApplicationContextInitializer servlet ʵʹõļ˿д뵽?Environment?SharedMetadataReaderFactoryContextInitializerһ?SpringBoot??ConfigurationClassPostProcessor?õ?CachingMetadataReaderFactory?ConditionEvaluationReportLoggingListener?ConditionEvaluationReport?д־ȡ?ApplicationContextInitializer?setInitializers(...)?
public class SpringApplication {
...
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<>(initializers);
}
...
}
һ?setter?ľֻóԱ
setListeners(...)üĴ£
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
ʽϿͬ?Initializer?һҲȴ?META-INF/spring.factories?м?ApplicationListenerȻӵԱУֱӿܻȡЩ?listener
ԿһԻȡ 11 ?listenerЩ?listener?£
ClearCachesApplicationListenerӦļɺԻParentContextCloserApplicationListener˫ӦĵĹر¼ԼӦдCloudFoundryVcapEnvironmentPostProcessor?CloudFoundry?ṩ֧FileEncodingApplicationListenerϵͳļӦûǷһ£ϵͳļӦûı벻ֹͬӦAnsiOutputApplicationListener?spring.output.ansi.enabled??AnsiOutputConfigFileApplicationListenerӳЩԼλöȡļDelegatingApplicationListener¼ת?application.properties?õ?context.listener.classes?ļClasspathLoggingApplicationListenerԻ¼?ApplicationEnvironmentPreparedEvent?Ӧʧ¼?ApplicationFailedEvent?ӦLoggingApplicationListener?LoggingSystemʹ?logging.config?ָûȱʡLiquibaseServiceLocatorApplicationListenerʹһԺ?SpringBoot?ִ jar Ϲİ汾滻?LiquibaseServiceLocatorBackgroundPreinitializerʹһ̨߳̾紥һЩʱijʼ?SpringApplication#setListeners
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList<>(listeners);
}
Ҳһ?setter?
deduceMainApplicationClass()ν࣬ǰ?main(String[])Ҳǵǰ spring Ӧõ࣬SpringApplication#deduceMainApplicationClass?£
private Class<?> deduceMainApplicationClass() {
try {
// ȡջ
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
// ջ main
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
Ҫͨ?new RuntimeException().getStackTrace()?ȡջȻõ?main?࣬õĵջ£
Կmain()?Ͱڵջˡ
Ҫǽ?SpringApplication?Ĵ̣ص¼㣺
ApplicationContextInitializerApplicationListenerԭӣhttps://my.oschina.net/funcy/blog/4877610?߸ˮƽд֮ӭָԭףҵתϵȨҵתע