过程解析
我们的程序执行到SpringApplication.run()时,第一步就是先调用SpringApplication的构造函数,入参就是带了@SpringBootApplication注解的启动类。
我们主要是看initialize里面做了什么。
SpringApplication(Object... sources)
// sources就是带了@SpringBootApplication注解的启动类
——》initialize(sources);
// this.sources是一个LinkedHashSet,将我们入参的第一个class参数加到数组里面
——》this.sources.addAll(Arrays.asList(sources));
/** 推断是否是web环境,[javax.servlet.Servlet, org.springframework.web.context.ConfigurableWebApplicationContext]这两个类都在应用环境中存在就是web环境
通过ClassUtils.isPresent(className, null)判断应用环境中是否存在一个className
判断逻辑:
1、先到primitiveTypeNameMap(只缓存double等基本数据类型)这个HashMap查看有没有
2、再到commonClassCache(缓存java.lang.Throwable等常用的bean)这个HashMap查看有没有
3、使用AppClassLoader类加载器初始化类,若初始化不成功,使用Class.forName(name)初始化,完整的逻辑是:return (clToUse != null ? clToUse.loadClass(name) : Class.forName(name));
*/
——》this.webEnvironment = deduceWebEnvironment();
/**
从META-INF/spring.factories中读取应用上下文初始化器ApplicationContextInitializer实现类的类列表,并将初始化后的应用上下文初始化器,加到List<ApplicationContextInitializer<?>> initializers中提供给后面的步骤使用
读取到的配置有6个:分别从spring-boot-xxx.jar、spring-boot-autoconfigure-xxx.jar中读取
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
*/
——》setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
/**
从META-INF/spring.factories中读取应用监听器ApplicationListener实现类的类列表,并将初始化后的应用监听器加到List<ApplicationListener<?>> listeners;中提供给后面的步骤使用
读取到的配置有13个:
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,\
org.springframework.boot.autoconfigure.BackgroundPreinitializer,\
org.springframework.cloud.bootstrap.BootstrapApplicationListener,\
org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,\
org.springframework.cloud.context.restart.RestartListener\
*/
——》setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
/** 推断带有main函数的类是哪个,从我们程序的调用栈中查找,函数名等于main的就是,返回初始化后的类
org.springframework.boot.SpringApplication.deduceMainApplicationClass
org.springframework.boot.SpringApplication.initialize
org.springframework.boot.SpringApplication.<init>
org.springframework.boot.SpringApplication.run
org.springframework.boot.SpringApplication.run
com.dameng.booking.HairBookingApplication.main
*/
——》this.mainApplicationClass = deduceMainApplicationClass();
总结
构造SpringApplication(Object... sources)主要做了几件事情
1、判断是否web环境赋给变量this.webEnvironment
2、读取META-INF/spring.factories配置的应用初始化器,并将初始化后的应用上下文初始化器,加到List<ApplicationContextInitializer<?>> initializers中提供给后面的步骤使用
3、读取META-INF/spring.factories配置的应用监听器,并将初始化后的应用监听器加到List<ApplicationListener<?>> listeners;中提供给后面的步骤使用
4、推断启动类是哪个,并赋给变量this.mainApplicationClass