目录
SpringBoot项?的main函数
1.SpringApplication()
推断应?类型deduceWebApplicationType()
?getSpringFactoriesInstances();
?2. run(args)
2.1 获取并启动监听器?
?2.2 构造应?上下?环境
prepareEnvironment()?法
2.3 初始化应?上下?
2.4 刷新应?上下?前的准备阶段
?2.5刷新应?上下?(IOC容器的初始化过程)
SpringBoot项?的main函数
@SpringBootApplication
public class SpringBootMytestApplication{
public static void main(String[] args) {
SpringApplication.run(SpringBootMytestApplication.class, args);
}
}
?点进run?法,primarySource就是引导类SpringBootMytestApplication
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
//调用重载方法
return run(new Class[]{primarySource}, args);
}
进入重载run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
- ??????? SpringApplication()构造?法的作用加载各种配置信息,初始化各种配置对象
- ??????? run(args)初始化容器
1.SpringApplication()
public SpringApplication(Class<?>... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = Collections.emptySet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
//初始化资源加载器为null
this.resourceLoader = resourceLoader;
//断?,加载资源类不能为null
Assert.notNull(primarySources, "PrimarySources must not be null");
//初始化配置类的类名信息(格式转换)将primarySources数组转换为List,最后放到LinkedHashSet集合中
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//【1.1 推断应?类型,后?会根据类型初始化对应的环境。常?的?般都是servlet环境 】
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//【1.2 初始化classpath下 META-INF/spring.factories中已配置的BootstrapRegistryInitializer】
this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
//【1.2 初始化classpath下META-INF/spring.factories中已配置的ApplicationContextInitializer】
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//【1.3 初始化classpath下所有已配置的ApplicationListener。ApplicationListener是spring的事件监听器,典型的观察者模式,实现ApplicationListener接?,通过ApplicationEvent类,可以实现对spring容器全?命周期的监听,当然也可以?定义监听事件】
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//【1.4 根据调?栈,推断出 main ?法的类名 】
this.mainApplicationClass = this.deduceMainApplicationClass();
}
推断应?类型deduceWebApplicationType()
/**
* 判断 应?的类型
* NONE: 应?程序不是web应?,也不应该?web服务器去启动
* SERVLET: 应?程序应作为基于servlet的web应?程序运?,并应启动嵌?式servlet web(tomcat)服务器。
* REACTIVE: 应?程序应作为 reactive web应?程序运?,并应启动嵌?式reactive web服务器。
* @return
*/
static WebApplicationType deduceFromClasspath() {
//classpath下必须存在org.springframework.web.reactive.DispatcherHandler
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
/**classpath环境下存在javax.servlet.Servlet或者
*org.springframework.web.context.ConfigurableWebApplicationContext
*/
return SERVLET;
}
}
????????返回类型是WebApplicationType的枚举类型, WebApplicationType 有三个枚举,三 个枚举的解释如其中注释
????????具体的判断逻辑如下:
- WebApplicationType.REACTIVE classpath下存在org.springframework.web.reactive.DispatcherHandler
- WebApplicationType.SERVLET classpath下存在javax.servlet.Servlet或者 org.springframework.web.context.ConfigurableWebApplicationContext
- WebApplicationType.NONE 不满?以上条件。
?getSpringFactoriesInstances();
????????初始化classpath下 META-INF/spring.factories中已配置的类
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
/**
* 通过指定的classloader 从META-INF/spring.factories获取指定的Spring的
??实例
* @param type
* @param parameterTypes
* @param args
* @param <T>
* @return
*/
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
// Use names and ensure unique to protect against duplicates
//通过指定的classLoader从 META-INF/spring.factories 的资源?件中,
//读取 key 为 type.getName() 的 value
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//创建Spring??实例
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//对Spring??实例排序(org.springframework.core.annotation.Order注解指定的顺序)
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
?????????loadFactoryNames() 这个?法很重要,这个?法是spring-core中提供的从METAINF/spring.factories中获取指定的类(key)的同????法
????????在这?,获取的是key为 org.springframework.context.ApplicationContextInitializer 的类。
?2. run(args)
????????SpringBoot 启动流程最重要的部分run?法,初始化容器
//初始化容器,得到ApplicationContext对象
public ConfigurableApplicationContext run(String... args) {
//记录程序开始运?时间
long startTime = System.nanoTime();
//将系统配置引导信息再次封装为上下文对象
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
//模拟输入输出信号,避免出现因缺少外设导致的信号传输失败,进而引发错误(模拟显示器、鼠标、键盘....),设置了一个java.awt.headless=true的信号,只是为了设备兼容
this.configureHeadlessProperty();
//1、获取当前注册的可运行的监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//监听器执行starting
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//获取参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//2、将前期读取的数据加载成了一个环境对象,用来描述信息,构造应?上下?环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//处理需要忽略的Bean
this.configureIgnoreBeanInfo(environment);
//打印banner
Banner printedBanner = this.printBanner(environment);
//3、初始化应?上下?,创建容器对象,根据前期配置的容器类型进行判定并创建
context = this.createApplicationContext();
//设置启动模式
context.setApplicationStartup(this.applicationStartup);
//4、刷新应?上下?(容器)前的准备阶段,对容器进行设置,参数来源于前期的设定
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//5、刷新应?上下?(容器)
this.refreshContext(context);
//刷新应?上下?(容器)后处理
this.afterRefresh(context, applicationArguments);
//记录程序运行时间
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
//判断是否记录启动时间的日志
if (this.logStartupInfo) {
//创建日志对象,输出日志信息,包含启动时间
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
//监听器执行started
listeners.started(context, timeTakenToStartup);
this.callRunners(context, applicationArguments);
} catch (Throwable var12) {
this.handleRunFailure(context, var12, listeners);
throw new IllegalStateException(var12);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
//监听器执行ready
listeners.ready(context, timeTakenToReady);
return context;
} catch (Throwable var11) {
this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var11);
}
}
?????????在以上的代码中,启动过程中的重要步骤共分为六步
- 第?步:获取并启动监听器
- 第?步:构造应?上下?环境
- 第三步:初始化应?上下?
- 第四步:刷新应?上下?前的准备阶段
- 第五步:刷新应?上下?
- 第六步:刷新应?上下?后的扩展接??
2.1 获取并启动监听器?
获取监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
}
?启动监听器
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
this.doWithListeners("spring.boot.application.starting", (listener) -> {
listener.starting(bootstrapContext);
}, (step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
?2.2 构造应?上下?环境
????????应?上下?环境包括计算机的环境,Java环境,Spring的运?环 境,Spring项?的配置(在SpringBoot中就是那个熟悉的 application.properties/yml)等等。
prepareEnvironment()?法
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
//创建并配置相应的环境
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
//根据?户配置,配置 environment系统环境
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
// 启动相应的监听器,其中?个重要的监听器ConfigFileApplicationListener 就是加载项?配置?件的监听器。
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
Assert.state(!((ConfigurableEnvironment)environment).containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties.");
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(this.getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
?????????法中主要完成的?作,?先是创建并按照相应的应?类型配 置相应的环境,然后根据?户的配置,配置系统环境,然后启动监听器,并加载系 统配置?件。
2.3 初始化应?上下?
2.4 刷新应?上下?前的准备阶段
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//设置容器环境
context.setEnvironment(environment);
//执?容器后置处理
this.postProcessApplicationContext(context);
//执?容器中的 ApplicationContextInitializer 包括spring.factories和通过三种?式?定义的
this.applyInitializers(context);
//向各个监听器发送容器已经准备好的事件
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// Add boot specific singleton beans
//将main函数中的args参数封装成单例Bean,注册进容器
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
//将 printedBanner 也封装成单例,注册进容器
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory)beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new SpringApplication.PropertySourceOrderingBeanFactoryPostProcessor(context));
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加载我们的启动类,将启动类注?容器
this.load(context, sources.toArray(new Object[0]));
//发布容器已加载事件
listeners.contextLoaded(context);
}
?2.5刷新应?上下?(IOC容器的初始化过程)
?到IoC容器的初始化过程,主要分下?三步:
- BeanDefinition的Resource定位
- BeanDefinition的载?
- 向IoC容器注册BeanDefinition
@Override
public void refresh() throws BeansException,IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//刷新上下?环境
prepareRefresh();
// Tell the subclass to refresh the internal bean
factory.
//这?是在?类中启动 refreshBeanFactory() 的地?
@Override
public void refresh() throws BeansException,
IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//刷新上下?环境
prepareRefresh();
// Tell the subclass to refresh the internal bean
factory.
//这?是在?类中启动 refreshBeanFactory() 的地?
//发布容器事件,结束Refresh过程
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during
context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid
dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's
core, since we
// might not ever need metadata for singleton
beans anymore...
resetCommonCaches();
}
}
}
|