版权声明:看什么?6,你和我,走一波! https://blog.csdn.net/qq_31323797/article/details/84958593
1 启动原理
1.1 入口(Springboot27Application.java)
@SpringBootApplication
public class Springboot27Application {
public static void main(String[] args) {
SpringApplication.run(Springboot27Application.class, args);
}
}
1.2 开始启动(SpringBootApplication.java)
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
/*
项目启动分为2步
1: new SpringApplication(primarySources)
创建SpringApplication对象
2: .run(args)
运行run方法
*/
return (new SpringApplication(primarySources)).run(args);
}
1.2.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 = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 1 获取应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 3 从类路径下找到META-INF/spring.factories配置的所有ApplicationListener
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 4 从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
1.2.1.1 获取应用类型
static WebApplicationType deduceFromClasspath() {
// 根据容器中指定的类是否存在来判断应用类型
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;
}
}
return SERVLET;
}
}
1.2.1.2 配置的所有ApplicationContextInitializer
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
......
return instances;
}
- SpringFactoriesLoader.loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
// 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer
// eg: org/springframework/boot/spring-boot-autoconfigure/2.1.0.RELEASE/spring-boot-autoconfigure-2.1.0.RELEASE.jar!/META-INF/spring.factories
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
/*
从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer
eg: org/springframework/boot/spring-boot-autoconfigure/2.1.0.RELEASE/spring-boot-autoconfigure-2.1.0.RELEASE.jar!/META-INF/spring.factories
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
*/
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
......
// 保存起来
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
1.2.1.3 配置的所有ApplicationListener
原理与 1.2.1.2 中一致
1.2.1.4 配置的所有ApplicationListener
1.2.2 运行run方法
public ConfigurableApplicationContext run(String... args) {
// 1 监听
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2 声明一个空的IOC容器
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 3 获取SpringApplicationRunListeners: 底层使用getSpringFactoriesInstances()方法获取,原理与1.2.1.2中一致(从类路径下META-INF/spring.factories)
SpringApplicationRunListeners listeners = this.getRunListeners(args);
// 4 回调所有的获取SpringApplicationRunListener.starting()方法
listeners.starting();
Collection exceptionReporters;
try {
// 5 封装命令行参数(项目启动时,可以在命令行中指定参数)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//6 准备环境,创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 7 打印banner图标
Banner printedBanner = this.printBanner(environment);
// 8 创建ApplicationContext : 创建IOC容器
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
/*
9 准备上下文环境
将配置好的环境放入IOC容器
applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法(1.2.1.2)
回调所有的SpringApplicationRunListener的contextPrepared();
prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded()
*/
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 10 刷新容器 : ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat)
// 扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
/*
11 从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
ApplicationRunner先回调,CommandLineRunner再回调
*/
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
//整个SpringBoot应用启动完成以后返回启动的ioc容器;
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
1.2.2.1 获取SpringApplicationRunListeners
1.2.2.2 准备环境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
// 判断环境是否存在,存在及获取,不存在及创建
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
// 配置环境
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
// 创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
listeners.environmentPrepared((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
1.2.2.3 准备上下文环境
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 将配置好的环境放入IOC容器
context.setEnvironment(environment);
// 后置处理
this.postProcessApplicationContext(context);
// 回调之前保存的所有的ApplicationContextInitializer的initialize方法
this.applyInitializers(context);
// 回调所有的SpringApplicationRunListener的contextPrepared(1.2.1.3)
listeners.contextPrepared(context);
// 日志记录
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 将命令行参数注册进来
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 将banner注册
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
// 回调所有的SpringApplicationRunListener的contextLoaded()
listeners.contextLoaded(context);
}