启动过程

- 启动主类调用main()方法开始。
- 调用 SpringApplication的构造方法,实例一个Spirng应用对象。在构造方法里主要完成启动环境初始化工作,如推断主类,spring应用类型,加载配置文件,读取spring.factories文件等。
- 调用run方法,所有的启动工作在该方法内完成,主要完成加载配置资源,准备上下文,创建上下文,刷新上下文,过程事件发布等
@SpringBootApplication 注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration //注册为配置类 @EnableAutoConfiguration //配置可自动装配 @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { }
@SpringBootConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration @Indexed public @interface SpringBootConfiguration { }
@EnableAutoConfiguration
@EnableAutoConfiguration借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器,会根据类路径中的jar依赖为项目进行自动配置,如:添加spring-boot-starter-web依赖,会自动添加Tomcat和Spring MVC的依赖,Spring Boot会对Tomcat和Spring MVC进行自动配置。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { /** * Environment property that can be used to override when auto-configuration is * enabled. */ String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; /** * Exclude specific auto-configuration classes such that they will never be applied. * @return the classes to exclude */ Class<?>[] exclude() default {}; /** * Exclude specific auto-configuration class names such that they will never be * applied. * @return the class names to exclude * @since 1.3.0 */ String[] excludeName() default {}; }
最关键的要属@Import(EnableAutoConfigurationImportSelector.class) ,借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。
@ComponentScan
@ComponentScan的功能就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。
创建SpringApplication对象
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); //判断当前程序类型 this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //使用SpringFactoriesLoader 实例化所有可用的初始器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 使用SpringFactoriesLoader 实例化所有可用的监听器 this.mainApplicationClass = deduceMainApplicationClass(); // 配置应用主方法所在类 }
判断当前程序类型
根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
启动方法(RUN)
初始化完成之后就进到run方法,run方法完成所有Spring的整个启动过程:
-
准备Environment
-
发布事件
-
创建上下文、bean
-
刷新上下文
-
结束
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); //开启时钟计时 stopWatch.start(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; //spring上下文 configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); //初始化SpringApplicationRunListener 监听器,并进行封装 listeners.starting(bootstrapContext, this.mainApplicationClass); // try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); //Environment 的准备 configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); //创建上下文实例 context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //容器初始化 refreshContext(context); //刷新上下文容器 afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }
SpringApplicationRunListener 的使用
通过getSpringFactoriesInstances 获取到所有实现SpringApplicationRunListener 接口的实例,默认情况下该接口的实现类只有 EventPublishingRunListener 他的主要作用是作为springboot 的一个广播器
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup); }
prepareEnvironment
写业务代码时,使用的都是只读类型的接口Environment,该接口是对运行程序环境的抽象,是保存系统配置的中心,而在启动过程中使用的则是可编辑的ConfigurableEnvironment。接口的UML类图如下,提供了合并父环境、添加active profile以及一些设置解析配置文件方式的接口。
其中一个比较重要的方法MutablePropertySources getPropertySources();,该方法返回一个可编辑的PropertySources,在启动阶段自定义环境的PropertySources的需求,就可以通过该方法设置。
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // Create and configure the environment ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); //填充启动类参数到enviroment 对象 listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties."); bindToSpringApplication(environment); //绑定主类 if (!this.isCustomEnvironment) { //转换environment的类型,但这里应该类型和deduce的相同不用转换 environment = convertEnvironment(environment); } ConfigurationPropertySources.attach(environment); return environment; }
创建springApplicationContext 上下文

Closeable提供了关闭时资源释放的接口,Lifecycle是提供对生命周期控制的接口(start\stop)以及查询当前运行状态的接口,ApplicationContext则是配置上下文的中心配置接口
上下文初始化
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context); applyInitializers(context); //调用初始化的切面 listeners.contextPrepared(context); //发布ApplicationContextInitializedEvent事件 bootstrapContext.close(context); 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); //发布ApplicationPreparedEvent事件 }
刷新上下文
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //记录启动时间、状态,web容器初始化其property,复制listener prepareRefresh(); //这里返回的是context的BeanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //beanFactory注入一些标准组件,例如ApplicationContextAwareProcessor,ClassLoader等 prepareBeanFactory(beanFactory); try { //给实现类留的一个钩子,例如注入BeanPostProcessors,这里是个空方法 postProcessBeanFactory(beanFactory); // 调用切面方法 invokeBeanFactoryPostProcessors(beanFactory); // 注册切面bean registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // bean工厂注册一个key为applicationEventMulticaster的广播器 initApplicationEventMulticaster(); // 给实现类留的一钩子,可以执行其他refresh的工作,这里是个空方法 onRefresh(); // 将listener注册到广播器中 registerListeners(); // 实例化未实例化的bean finishBeanFactoryInitialization(beanFactory); // 清理缓存,注入DefaultLifecycleProcessor,发布ContextRefreshedEvent 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(); } } }
参考:https://juejin.cn/post/7035910505810100255
浙公网安备 33010602011771号