博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot 启动流程解析大全
阅读量:3932 次
发布时间:2019-05-23

本文共 20099 字,大约阅读时间需要 66 分钟。

前言

了解 SpirngBoot 的加载流程,可以让我们更好地自定义 SpringBoot 加载流程,并且对自己开发相关架构有一定的借鉴意义。本文旨在从 SpringBoot 的启动类出发,了解 SpringBoot 是怎样完成加载环境、设置上下文、注入 bean 等步骤。

由于本人水平有限,分析过程中可能有遗漏和错误,希望大家可以直接指出来,一起学习,一起进步。

run

不管自己怎么定制 SpringBoot 的启动流程,最后总是通过 run() 方法开始运行的。示例如下:

public static void main(String[] args) throws NotSuchUserIdException {
SpringApplication springApplication = new SpringApplication(ApiApplication.class); springApplication.addListeners(new ApplicationStartup()); springApplication.run(ApiApplication.class, args);}

很显然,在 run 方法里 SpringBoot 完成了环境配置,上下文创建等相关任务。我们就进入这个方法看看。在第二次跳转后,我们来到了这个方法:

public static ConfigurableApplicationContext run(Class
[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);}

这个方法完成了两个步骤,一个是创建了 SpringApplication,一个是执行了 SpringApplication.run(args)方法。

我们先来看看 SpringApplication 的构造方法里做了什么:

public SpringApplication(ResourceLoader resourceLoader, Class
... primarySources) {
// 这里传过来的是一个 null this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); /** * 确认 Web 的应用类型,一共有三种: * 1. reactive * 2. servlet * 3. none * 实际是通过 SpringBoot 自己的 forName 方法判断对应 Web 的类是否存在, * 比如 reactive 相关的 jar 包存在就是 reactive web 类型。 */ this.webApplicationType = WebApplicationType.deduceFromClasspath(); /** * setInitializers 就是将一些变量赋值,完成初始化操作。 * 下面两个方法是这个方法的分析。 */ setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 跟 getSpringFactoriesInstances 方法执行逻辑和 getSpringFactoriesInstances 差不多 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 获取当前启动类的类对象 this.mainApplicationClass = deduceMainApplicationClass();}private
Collection
getSpringFactoriesInstances(Class
type) {
return getSpringFactoriesInstances(type, new Class
[] {
});}private
Collection
getSpringFactoriesInstances(Class
type, Class
[] parameterTypes, Object... args) { // 根据当前线程获取到其类的加载器 ClassLoader classLoader = getClassLoader(); /** * 这个方法会从 META-INF/spring.factories 配置文件中以 type * (就是ApplicationContextInitializer的全路径: * org.springframework.context.ApplicationContextInitializer) * 作为 key 获取所有的值 */ Set
names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); /** * 在 createSpringFactoriesInstances() 方法中, * 通过反射的方式创建出各个 ApplicationContextInitializer * 所有实现类的实例,然后添加到 List 中返回。 */ List
instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances;}

然后我们把注意力放在 run 方法上:

public ConfigurableApplicationContext run(String... args) {
// 启动计时器,用来计算应用启动花费的时长 StopWatch stopWatch = new StopWatch(); // 开始计时 stopWatch.start(); // 环境上下文变量 ConfigurableApplicationContext context = null; // 错误报告,当启动错误时会将错误上报给报告 Collection
exceptionReporters = new ArrayList<>(); // 设置 java.awt.headless 属性 // 这是用于在操作系统处于 HeadLess 模式时使用的 // 可以查看博客:http://jimolonely.github.io/2019/03/26/java/039-java-headless/ configureHeadlessProperty(); // 用于获取运行时监听器,在这里我把它们称为监听器组 SpringApplicationRunListeners listeners = getRunListeners(args); // 开启监听器组 listeners.starting(); // 创建 ApplicationArguments 对象,此时 applicationArguments 变量里面只有 args 值 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 准备上下文刷新的环境属性 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 设置环境变量中的 spring.beaninfo.ignore 为 true/false configureIgnoreBeanInfo(environment); // 打印 printBanner Banner printedBanner = printBanner(environment); // 根据 web 类型创建不同的上下文对象 context = createApplicationContext(); 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); // 调用 ApplicationRunner 和 CommandLineRunner callRunners(context, applicationArguments); // 开始 running 事件传播 listeners.running(context); return context;}

可以看出 SpringBoot 做了很多处理,我们一步步对重要的方法进行分析。

创建监听器

SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();private SpringApplicationRunListeners getRunListeners(String[] args) {
Class
[] types = new Class
[] {
SpringApplication.class, String[].class }; /** * new SpringApplicationRunListeners 创建一个监听器组。 * getSpringFactoriesInstances 方法在前面分析过了,在这里 * 的作用是找到在 META-INF/spring.factories 里 key 为 * org.springframework.boot.SpringApplicationRunListener * 的类 */ return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));}

进行环境的加载配置

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,        ApplicationArguments applicationArguments) {
// 这里获取之前创建的 DefaultApplicationArguments ConfigurableEnvironment environment = getOrCreateEnvironment(); // getSourceArgs 返回 run 方法中传入的 args configureEnvironment(environment, applicationArguments.getSourceArgs()); /** * 该监听器组会通过 ApplicationEnvironmentPreparedEvent * 这一事件拿到对应的监听器,并执行监听方法。这个对应的监听器为 * ConfigFileApplicationListener,它会配置文扩展名以及默认配置文件名 application, * 在 classpath:/、classpath:/config/、file:./、file:./config/ 下面寻找配置文件。 * 默认的配置文件后缀有 properties、yaml、yml、xml。 */ listeners.environmentPrepared(environment); // 将环境绑定到应用中 bindToSpringApplication(environment); // this.isCustomEnvironment 为 false if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } /** * 属性源中获取是否存在 configurationProperties 的属性源, * 不存在则通过 ConfigurationPropertySourcesPropertySource 包装
, * 然后添加到 MutablePropertySources 中的集合第一个位置上。 */ ConfigurationPropertySources.attach(environment); return environment;}protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
// this.addConversionService 为 true // 这里通过单例模式获取一个 ConversionService // 并设置到环境中 if (this.addConversionService) {
ConversionService conversionService = ApplicationConversionService.getSharedInstance(); environment.setConversionService((ConfigurableConversionService) conversionService); } // 查看有没有指定新的配置源(通过命令行指定) configurePropertySources(environment, args); // 通过配置中的 spring.profiles.active 获取 activeProfile configureProfiles(environment, args);}

创建应用上下文

/** * 这个没什么好说的,就是根据 this.webApplicationType * 类型创建不同的默认 Web 上下文。 */context = createApplicationContext();

创建 bean 对象

// 容器刷新前的进行上下文配置prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 这个是知识点的重灾区,后面会详细进行分析refreshContext(context);// 这是一个空方法afterRefresh(context, applicationArguments);private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,        SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 把之前的环境加载到上下文中 context.setEnvironment(environment); // 注册上下文的后置处理, postProcessApplicationContext(context); // 执行 ApplicationContextInitializer // 可以通过继承 ApplicationContextInitializer 类 // 重写 initialize 方法,然后将该子类通过 application.addInitializers // 注册到 SpringApplication。 applyInitializers(context); // 发布上下文已预加载完成事件 listeners.contextPrepared(context); if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 注册 ApplicationArguments 类 beanFactory.registerSingleton("springApplicationArguments", applicationArguments); // 注册 Banner 类 if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner); } // SpringApplication 提供 setAllowBeanDefinitionOverriding 方法 // 来设置 BeanDefinition 是否可以被覆盖 if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } Set sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[0])); // 发布上下文已加载完成的事件 listeners.contextLoaded(context);}

refresh

在前面讲到创建 bean 对象时,我们看到 refreshContext 方法是用于刷新容器的。当我们点进方法后,发现它实际上是调用了 AbstractApplicationContext.refresh 方法,再次进去就看到了容器刷新的核心执行逻辑部分。SpringBoot 采用了模板方法,我们来看看它的执行逻辑:

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 预刷新处理 prepareRefresh(); // 获取 beanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 对 beanFactory 进行预处理 prepareBeanFactory(beanFactory); try {
// 对 beanFactory 进行后置处理 postProcessBeanFactory(beanFactory); // 调用 beanFactory 的后置处理器,这里是针对 BeanDefinition 进行处理 invokeBeanFactoryPostProcessors(beanFactory); // 注册 bean 后置处理器 registerBeanPostProcessors(beanFactory); // 国际化处理 initMessageSource(); // 初始化应用事件广播器 initApplicationEventMulticaster(); // 初始化特殊的 bean,这个方法是空实现 onRefresh(); // 注册监听器 registerListeners(); // 实例化剩余的 bean,IOC、DI、AOP 都是发生在这里的 finishBeanFactoryInitialization(beanFactory); // 完成刷新,发布事件 finishRefresh(); } catch (BeansException ex) {
// 销毁创建的 bean destroyBeans(); // 取消 active 标记 cancelRefresh(ex); throw ex; } finally {
// 重置 Spring 内核中的常用自检缓存,清空单例 bean 内缓存 resetCommonCaches(); } }}

接下来我们会它的各处理逻辑的实现进行解析。

预刷新上下文

protected void prepareRefresh() {
// 获取上下文启动时间点 this.startupDate = System.currentTimeMillis(); // 设置上下文为活跃状态 this.closed.set(false); this.active.set(true); // 初始化上下配置信息,这是一个空方法 initPropertySources(); // 检验环境中是否存在必须字段 getEnvironment().validateRequiredProperties(); // earlyApplicationListeners 绑定监听器 if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); } else {
this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } this.earlyApplicationEvents = new LinkedHashSet<>();}

获取 beanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory(); return getBeanFactory();}protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans(); closeBeanFactory(); } try {
// 创建默认 beanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); // 设置两个属性: // 1. allowBeanDefinitionOverriding // 2. allowCircularReferences customizeBeanFactory(beanFactory); // 记载所有的 bean 到 beanFactory 中 // 主要有两种实现: // 1. XmlWebApplicationContext // 2. AnnotationConfigWebApplicationContext loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory; } } catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); }}

可以看到在 obtainFreshBeanFactory 方法中完成了三件事:

  1. 创建 beanFactory
  2. 完成了 BeanDefinition 的加载和注册工作。

后面就是 beanFactory 的二次配置,没什么好说的。

postProcessBeanFactory 用于对 beanFactory 的 BeanDefinition 数据进行修改,所以在这里,我们可以自己去注册或修改一些 BeanDefinition。invokeBeanFactoryPostProcessors 方法就是调用 beanFactory 的后置处理器。代码如下:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
/** * getBeanFactoryPostProcessors:拿到上下文的 beanFactoryProcessors * invokeBeanFactoryPostProcessors:实例化并调用已注册的 beanFactoryProcessor */ PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); /** * 判断是否定义了名为 loadTimeWeaver 的 bean,如果定义了则添加 loadTimeWeaver 功能的 * beanPostProcessor 扩展,并且创建一个临时的 classLoader 来让其处理真正的bean */ if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}

registerBeanPostProcessors 用于注册 bean 的后置处理器。

registerBeanPostProcessors 的执行流程如下,省略了部分代码,但是逻辑是不变的:

public static void registerBeanPostProcessors(            ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 获取 BeanPostProcessor 实现类的 beanName String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // 注册 PriorityOrdered 实现类 sortPostProcessors(priorityOrderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // 注册 Ordered 实现类. List
orderedPostProcessors = new ArrayList<>(); for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp); } } sortPostProcessors(orderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, orderedPostProcessors); // 注册其它 bean 后置处理器 List
nonOrderedPostProcessors = new ArrayList<>(); for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp); } } registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // 注册所有内部处理器 sortPostProcessors(internalPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, internalPostProcessors); // 重新注册 ApplicationListenerDetector beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); }

国际化处理

protected void initMessageSource() {
// 获取 beanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); /** * 判断是否有名称为 messageSource 的 bean * 处理逻辑为: * 1. 如果存在 MessageSource 的实现类,则对 MessageSource进行初始化并赋值给其成员变量messageSource * 2. 如果不存在 MessageSource 实现类,则赋值一个 DelegatingMessageSource,保证正常进行 getMessage * 方法调用。 */ if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource; if (hms.getParentMessageSource() == null) {
hms.setParentMessageSource(getInternalParentMessageSource()); } } } else {
DelegatingMessageSource dms = new DelegatingMessageSource(); dms.setParentMessageSource(getInternalParentMessageSource()); this.messageSource = dms; beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); }}

初始化事件监听多路广播器

protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory(); /** * 判断容器中是否存在名称为 applicationEventMulticaster * 的 ApplicationEventMulticaster 的实现类。如果没有,则采用 * 默认的 SimpleApplicationEventMulticaster。 */ if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); } else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); }}

初始化特殊的 bean,该方法是一个空方法,用于让 AbstractApplicationContext 的子类重写。

初始化监听器

protected void registerListeners() {
// getApplicationListeners 获取用户添加的监听器 for (ApplicationListener
listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener); } // 从容器中获取所有 ApplicationListener 的实现类 String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // 发布早期的监听器,默认为空 Set
earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent); } }}

实例化 bean

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 为上下文初始化 conversionService if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // 检查上下文是否有类型转换器 valueResolver if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } // 初始化 LoadTimeWeaverAware bean String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName); } // 禁止使用临时类加载器进行类型匹配 beanFactory.setTempClassLoader(null); // 允许缓存所有 bean 的定义数据 beanFactory.freezeConfiguration(); // 准备实例化 bean // 遍历 beanName list 中的每一个 beanName, // 然后实例化当前 beanName 相应的bean beanFactory.preInstantiateSingletons();}

容器刷新完成的处理工作

protected void finishRefresh() {
// 处理资源缓存 clearResourceCaches(); // 为上下文初始化生命周期处理器 initLifecycleProcessor(); // 将刷新关闭事件传播到生命周期处理器 getLifecycleProcessor().onRefresh(); // 推送上下文刷新完毕事件到对应的监听器 publishEvent(new ContextRefreshedEvent(this)); // 将上下文注册到 MBean 中,MBean 是 Java 的一种技术 // 参考博客:https://juejin.im/post/6856949531003748365 LiveBeansView.registerApplicationContext(this);}

总结

到此 SpringBoot 启动的主要流程就分析完了。我们可以看出它的结构十分严谨,对并发也进行了相关的处理,并且提供了很多接口供我们实现,以此来定制自己的处理逻辑,其中主要使用的设计模式为工厂模式和模板模式。这些为我们以后设计自己的网站架构有很大的启发。

转载地址:http://ijqgn.baihongyu.com/

你可能感兴趣的文章
如何算三角形的cotangent
查看>>
houdini 做选点效果
查看>>
compute_vertex_ring
查看>>
read tetgen file
查看>>
sub figure without letter numbering
查看>>
my plot mesh
查看>>
文章索引加1
查看>>
Laplacian surface editing
查看>>
求cluster的质心坐标
查看>>
Deformable 3D shape registration based on local similarity transforms
查看>>
intersectLineMesh3d
查看>>
how change files in matlab2 , cell 函数的运用
查看>>
sort_nat
查看>>
how to fix the frame size?
查看>>
write frames to a video
查看>>
export frames as pictures
查看>>
AE的一些基本知识
查看>>
perform_farthest_point_sampling_mesh
查看>>
perform_faces_reorientation
查看>>
compute_voronoi_triangulation_mesh
查看>>