启动原理
注意:使用版本为spring-boot-2.2.2.RELEASE
springboot启动的入口肯定是main方法啦,那就从main方法入口走起来看看是如何进行启动的
@SpringBootApplication
public class ConsulApp {public static void main(String[] args) {// 调用SpringApplication的静态run方法SpringApplication.run(ConsulApp.class,args);}
}
进入main方法
// 这个primarySources是传入进来的启动类
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {// 先实例化SpringApplicationreturn new SpringApplication(primarySources).run(args);
}
实例化SpringApplication
// this(null, primarySources)
// resourceLoader是null,primarySources是传入进来的启动类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");// 使用set进行去重this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 根据classpath中是否存在org.springframework.web.reactive.DispatcherHandler来判断是否为REACTIVE// 根据classpath中是否存在"javax.servlet.Servlet"和"org.springframework.web.context.ConfigurableWebApplicationContext"来判断是否为SERVLET// web应用的类型,是None表示非web项目 SERVLET表示普通的servlet web项目 REACTIVE表示响应式的web项目this.webApplicationType = WebApplicationType.deduceFromClasspath();// 设置应用上下文初始化器 SpringFactoriesLoader从META-INF/spring.factories加载的,获取 ApplicationContextInitializer 接口的所有配置的类路径名称,并进行实例化setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));// 设置监听器 SpringFactoriesLoader从META-INF/spring.factories加载的,获取ApplicationListener接口的所有配置的类路径名称,并进行实例化setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 推断主启动类,通过构造一个运行时异常,再遍历异常栈中的方法名,获取方法名为 main 的栈帧,从来得到入口类的名字再返回该类this.mainApplicationClass = deduceMainApplicationClass();
}
执行SpringApplication实例的run方法
实例化SpringApplication之后,调用该对象的run方法
- NO1 进行计时,记录整个过程的加载事件
- NO2 初始化应用上下文和异常报告集合,设置headless变量
- NO3 通过SpringFactoriesLoader加载SpringApplicationRunListener监听器,调用starting方法,表示springboot要启动了
- NO4 创建ConfigurableEnvironment,将配置的环境绑定到spring应用中(包括PropertySource和Profile),并调用SpringApplicationRunListener监听器的environmentPrepared方法,应用的environment已经准备完毕
- NO5 Banner打印并创建应用上下文
- NO6 创建应用上下文,根据webApplicationType决定创建不同的上下文
- NO7 准备应用上下文,执行初始化器ApplicationContextInitializer的initialize方法
- NO8 刷新应用上下文
- NO9 计时停止,调用SpringApplicationRunListener监听器的started方法,表示应用上下文已完成
- NO10 执行所有的Runner运行器(ApplicationRunner和CommandLineRunner)
- NO11 调用SpringApplicationRunListener监听器的running方法,表示已经开始运行了
public ConfigurableApplicationContext run(String... args) {// NO1 // 创建计时监控对象,记录整个过程的加载事件StopWatch stopWatch = new StopWatch();// 启动计时监控,记录开始时间stopWatch.start();// NO2// 初始化应用上下文和异常报告集合ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();// 设置系统属性 java.awt.headless,默认trueconfigureHeadlessProperty();// NO3// 创建SpringApplicationRunListeners监听器,通过SpringFactoriesLoader加载,监听器在spring.factories中SpringApplicationRunListener接口,默认是只有org.springframework.boot.context.event.EventPublishingRunListener// 本质是一个事件发布者SpringApplicationRunListeners listeners = getRunListeners(args);// 开始监听,表示springboot要开始启动了// 广播ApplicationStartingEvent事件listeners.starting();try {// NO4// 初始化默认应用参数类ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 加载springboot配置环境// configurePropertySources(environment, args); 配置PropertySource// configureProfiles(environment, args); 配置profiles// 此时广播了一个ApplicationEnvironmentPreparedEvent事件,通知事件监听者,应用的environment已经准备完毕ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);// NO5// Banner打印Banner printedBanner = printBanner(environment);// NO6 创建应用上下文,根据webApplicationType应用类型的不同,创建不同的上下文,通过Class.forName的方式// DEFAULT_CONTEXT_CLASS = "org.springframework.context.annotation.AnnotationConfigApplicationContext"// DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"// DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"context = createApplicationContext();// 异常报告器,在spring.factories中SpringBootExceptionReporter接口exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);// NO7// 准备应用上下文// 给ApplicationContext设置environment// 遍历调用所有的ApplicationContextInitializer的 initialize()方法// 广播ApplicationContextInitializedEvent事件,ApplicationContext初始化事件// 将所有的bean加载到容器中// 广播ApplicationPreparedEvent事件,ApplicationContext准备事件prepareContext(context, environment, listeners, applicationArguments, printedBanner);// NO8// 刷新应用上下文,获取所有的BeanFactoryPostProcessor对容器进行一些额外操作// 其中对于@Configuration、@ComponentScan、@Import、@PropertySource、@ImportResource、@Bean注解都是在这里处理的// 这里的操作就是spring中的refresh方法那一套东西refreshContext(context);// 应用上下文刷新后置处理(该方法为空方法)afterRefresh(context, applicationArguments);// 停止计时监控stopWatch.stop();if (this.logStartupInfo) {// 输出主类名以及时间信息new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}// NO9// 广播ApplicationStartedEvent事件,表示应用上下文已完成listeners.started(context);// NO10// 执行Runner运行器 ApplicationRunner和CommandLineRunner实现类callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {// NO11// 发布应用上下文就绪事件listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;
}
NO7 准备应用上下文
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {// 设置环境context.setEnvironment(environment);// 配置上下文的bean生成器以及资源加载器postProcessApplicationContext(context);// 上下文初始化器执行initialize方法applyInitializers(context);// 触发监听器的contextPrepared事件listeners.contextPrepared(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beans// 注册两个特殊的单例beanConfigurableListableBeanFactory 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");// 加载beanload(context, sources.toArray(new Object[0]));// 触发监听器的contextLoaded事件listeners.contextLoaded(context);
}
NO8 刷新应用上下文
这里实际调用的就是spring中的refresh方法 可参考 源码分析之上下文构建
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.// 设置beanFactory的一些属性// 添加后置处理器// 设置忽略的自动装配接口// 注册一些组件prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException 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();}}
}
https://zhhll.icu/2021/框架/springboot/源码/2.启动原理/