通过查看springboot主配置类的main方法中,调用的是springApplication中的静态的run方法
@SpringBootApplication
public class SpringbootWebRestfulcrudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebRestfulcrudApplication.class, args);
}
进入到run方法中发现,springboot启动分为俩步,一个是实例化SpringApplication,将主配置类存到class数组中作为构造方法参数传进去
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
第一步:创建SpringApplication对象
一路点进来,我们发现最后调用的这个构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
//这里判断是否有主配置类,如果没有,则抛一个异常,这个异常如果被处理后可以继续向下执行,如果没被处理,程序不会向下执行
Assert.notNull(primarySources, "PrimarySources must not be null");
//将主配置类存到一个HashSet集合中,赋值
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//同样也是给属性赋值,这个是web程序的属性,在WebApplicationType中会有三个属性NONE,SERVLET,REACTIVE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//给initializers属性赋值,在getSpringFactoriesInstances里面我们可以找到调用了loadSpringFactories方法,最后获取的jar包中META-INF包下的Apring.factories这个配置文件中的ApplicationContextInitializer对应的属性
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//给listeners赋值,一样的道理,获取的是ApplicationListener对应的属性
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
这个deduceFromClasspath()方法中最重要的功能 是加载class功能,而class加载是依赖jar包是否引起而判断的,所以如果引入了javax.servlet.Servlet的jar,则会启动Servlet模式,如果引入的jar是spring-boot-starter-webflux,而且没引入servlet相关的jar,则会启动Reactive模式。
//判断当前的应用服务属于什么类型
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
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";
loadSpringFactories里面可以看到获取了FACTORIES_RESOURCE_LOCATION属性,这个FACTORIES_RESOURCE_LOCATION属性就是"META-INF/spring.factories"也就是说获取META-INF包下的spring.factories文件里面ApplicationContextInitializer属性对应的值以集合的形式返回赋值给initializers属性
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
最后调用的deduceMainApplicationClass方法,作用是获取主配置类的main方法,将这个类信息返回
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;
}
第二步:运行程序
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//这里是从META-INF下spring.factories里面获取SpringApplicationRunListener对应的值
SpringApplicationRunListeners listeners = getRunListeners(args);
//这里遍历所有的SpringApplicationRunListeners,并且执行里面的starting方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备环境(先创建环境,创建完成后,回调SpringApplicationRunListeners里面的environmentPrepared方法,表示环境准备完成)
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 创建ioc容器,根据webApplicationType里面的属性来判断是创建web环境还是其他的
context = createApplicationContext();
//做异常分析
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备上下文环境,给ioc容器中的属性赋值
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新容器,ioc容器初始化(如果是web容器还会创建嵌入式的tomcat)
//扫描,创建,加载,所有组件的地方(配置类,组件,自动配置)
refreshContext(context);
//这个在牢版本里面调用了callRunners方法,新版本里面为空方法,callRunners在下面有调用
afterRefresh(context, applicationArguments);
//在这里,1.0版本有调用SpringApplicationRunListeners里面的finish方法,新版本的SpringApplicationRunListeners里面已经没有了finish方法
//保存当前应用状态
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//在ioc容器创建完成,保存状态之后执行该方法
//执行SpringApplicationRunListeners里面的started方法(在1.0版本没有这个步骤)
listeners.started(context);
//从ioc里面获取所有的ApplicationRunner和CommandLineRunner,遍历回调,先将所有的ApplicationRunner回调完,再回调CommandLineRunner
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
//在这里面会执行SpringApplicationRunListeners的failed方法(1.0版本没有该方法)
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//在callRunners方法执行完,ApplicationRunner,CommandLineRunner加载完之后执行,类似于老版本的finish方法
// 执行SpringApplicationRunListeners里面的running方法(在1.0版本没有这个步骤)
listeners.running(context);
}
catch (Throwable ex) {
//在这里面会执行SpringApplicationRunListeners的failed方法(1.0版本没有该方法)
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
//整个spring应用完成后,返回spring的ioc容器
return context;
}
准备环境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
创建ioc容器,根据webApplicationType里面的属性来判断(SERVLET,REACTIVE),最后使用BeanUtils反射创建ioc容器
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
配置上下文环境
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//给ioc容器中的environment赋值(配置环境)
context.setEnvironment(environment);
//ioc的后置组件
postProcessApplicationContext(context);
//之前new SpringApplication的时候,已经从各个jar包的META-INF下的spring.favtories里面获取到的ApplicationContextInitializer,调用里面的initialize方法
applyInitializers(context);
//listeners还要回调contextPrepared这个方法
listeners.contextPrepared(context);
//在listeners准备执行完成之后,还要调用ApplicationContextInitializer里面的contextLoaded方法
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}