springboot源码分析-启动流程分析
作者:互联网
1.概述
springboot初始化,每次运行springboot项目都会在main方法里调用
SpringApplication.run(SpringApplication.class, args);
初始化也就是new SpringApplication的过程,初始化会设置当前的运行的一些属性
运行时调用run方法的过程,运行基本上就是创建一个上下文环境加载bean
2.源码
https://blog.csdn.net/qq_39482039/article/details/120603123
3.初始化流程
首先在springApplication这个类里有个静态方法给我们调用,其实就是new了一个SpringApplication并调用它的run方法
/**
* 可用于运行 {@link SpringApplication} 的静态助手
* 使用默认设置指定源。
*
* @param primarySource the primary source to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[]{primarySource}, args);
}
/**
* 可用于运行 {@link SpringApplication} 的静态助手
* 使用默认设置和用户提供的参数指定源。
*
* @param primarySources the primary sources to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
初始化看new SpringApplication方法
/**
* 创建一个新的 {@link SpringApplication} 实例。应用程序上下文将加载
* 来自指定主要来源的 bean(参见 {@link SpringApplication class-level}
* 有关详细信息的文档。调用前可以自定义实例
* {@link #run(String...)}。
*
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//设置当前的资源加载器
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//设置当前的启动入口
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//设置web环境类型,
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从spring.factories文件中加载ApplicationContextInitializer初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//从spring.factories文件中加载ApplicationListener初始化器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//根据堆栈跟踪信息获取执行的main方法的class
this.mainApplicationClass = deduceMainApplicationClass();
}
确定当前应用程序的环境
static WebApplicationType deduceFromClasspath() {
//如果有DispatcherHandler这个类能被加载并且DispatcherServlet和ServletContainer不能加载,当前就是反应式应用程序
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
//如果没有ConfigurableWebApplicationContext和Servlet类不是web应用和反应式应用程序
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
//否则就是基于servlet的Web应用程序
return WebApplicationType.SERVLET;
}
根据堆栈跟踪信息获取执行的main方法的class
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;
}
4.运行流程
根据当前环境创建不同的上下文,
如果是web环境创建AnnotationConfigServletWebServerApplicationContext
如果是反应式环境创建AnnotationConfigReactiveWebServerApplicationContext
如果是默认创建AnnotationConfigApplicationContext
/**
* 运行 Spring 应用程序,创建并刷新一个新的
* {@link ApplicationContext}。
*
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
//记录执行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//在spring.factories文件获取配置的监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
//调用所有监听器的starting方法
listeners.starting();
try {
//将参数封装为applicationArguments对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//创建配置环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//环境中设置忽略的属性
configureIgnoreBeanInfo(environment);
//打印Banner
Banner printedBanner = printBanner(environment);
//创建webServlet上下文环境
context = createApplicationContext();
//在spring.factories文件获取SpringBootExceptionReporter的配置
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[]{ConfigurableApplicationContext.class}, context);
//准备上下文环境
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新上下文环境
refreshContext(context);
//刷新后处理
afterRefresh(context, applicationArguments);
//计时器结束
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//执行监听器的started运行方法
listeners.started(context);
//通知runner,启动后执行
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//执行监听器的running方法
listeners.running(context);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
创建上下文环境
/**
* 用于创建 {@link ApplicationContext} 的策略方法。默认这个
* 方法将尊重任何明确设置的应用程序上下文或应用程序上下文
* 回退到合适的默认值之前的类。
*
* @return the application context (not yet refreshed)
* @see #setApplicationContextClass(Class)
*/
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) {
//设置上下文环境
context.setEnvironment(environment);
//上下文后处理,子类可对其进行拓展
postProcessApplicationContext(context);
//调用容器初始化监听器接口,ApplicationContextInitializer
applyInitializers(context);
//容器上下文准备时调用
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 添加启动特定的单例 bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//如果延迟加载设置添加beanFactory后置处理器LazyInitializationBeanFactoryPostProcessor
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
//获取所有的源,源是在初始化的时候源就是传入的实现了main方法启动的class
//这里也可以传入其他的类型,
//一般用的是javaConfig
//可以是处理Package,SpringApplication.run(Package.getPackage("com.leone.chapter.profiles"), args);
//可以是处理Resource,new ClassPathResource("applicationContext.xml")
//可以是处理String类型,SpringApplication.run("classpath:/applicationContext.xml", args);
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
//调用spring运行监听器的contextLoaded方法
listeners.contextLoaded(context);
}
刷新上下文,调用上下文的refresh方法
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
/**
* 刷新底层 {@link ApplicationContext}。
*
* @param applicationContext the application context to refresh
*/
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
标签:分析,return,springboot,args,SpringApplication,源码,context,new,Class 来源: https://blog.csdn.net/qq_39482039/article/details/120594475