SpringBoot启动原理分析

SpringBoot启动原理分析,第1张

自动配置核心类SpringFactoriesLoader

上面在说@EnableAutoConfiguration的时候有说META-INF下的springfactories文件,那么这个文件是怎么被spring加载到的呢,其实就是SpringFactoriesLoader类。

SpringFactoriesLoader是一个供Spring内部使用的通用工厂装载器,SpringFactoriesLoader里有两个方法

在这个SpringBoot应用启动过程中,SpringFactoriesLoader做了以下几件事:

加载所有META-INF/springfactories中的Initializer

加载所有META-INF/springfactories中的Listener

加载EnvironmentPostProcessor(允许在Spring应用构建之前定制环境配置)

接下来加载Properties和YAML的PropertySourceLoader(针对SpringBoot的两种配置文件的加载器)

各种异常情况的FailureAnalyzer(异常解释器)

加载SpringBoot内部实现的各种AutoConfiguration

模板引擎TemplateAvailabilityProvider(如Freemarker、Thymeleaf、Jsp、Velocity等)

总得来说,SpringFactoriesLoader和@EnableAutoConfiguration配合起来,整体功能就是查找springfactories文件,加载自动配置类。

整体启动流程

在我们执行入口类的main方法之后,运行SpringApplicationrun,后面new了一个SpringApplication对象,然后执行它的run方法。

初始化SpringApplication类

创建一个SpringApplication对象时,会调用它自己的initialize方法

执行核心run方法

初始化initialize方法执行完之后,会调用run方法,开始启动SpringBoot。

首先遍历执行所有通过SpringFactoriesLoader,在当前classpath下的META-INF/springfactories中查找所有可用的SpringApplicationRunListeners并实例化。调用它们的starting()方法,通知这些监听器SpringBoot应用启动。

创建并配置当前SpringBoot应用将要使用的Environment,包括当前有效的PropertySource以及Profile。

遍历调用所有的SpringApplicationRunListeners的environmentPrepared()的方法,通知这些监听器SpringBoot应用的Environment已经完成初始化。

打印SpringBoot应用的banner,SpringApplication的showBanner属性为true时,如果classpath下存在bannertxt文件,则打印其内容,否则打印默认banner。

根据启动时设置的applicationContextClass和在initialize方法设置的webEnvironment,创建对应的applicationContext。

创建异常解析器,用在启动中发生异常的时候进行异常处理(包括记录日志、释放资源等)。

设置SpringBoot的Environment,注册Spring Bean名称的序列化器BeanNameGenerator,并设置资源加载器ResourceLoader,通过SpringFactoriesLoader加载ApplicationContextInitializer初始化器,调用initialize方法,对创建的ApplicationContext进一步初始化。

调用所有的SpringApplicationRunListeners的contextPrepared方法,通知这些Listener当前ApplicationContext已经创建完毕。

最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。

调用所有的SpringApplicationRunListener的contextLoaded方法,加载准备完毕的ApplicationContext。

调用refreshContext,注册一个关闭Spring容器的钩子ShutdownHook,当程序在停止的时候释放资源(包括:销毁Bean,关闭SpringBean的创建工厂等)

注: 钩子可以在以下几种场景中被调用:

1)程序正常退出

2)使用Systemexit()

3)终端使用Ctrl+C触发的中断

4)系统关闭

5)使用Kill pid命令杀死进程

获取当前所有ApplicationRunner和CommandLineRunner接口的实现类,执行其run方法

遍历所有的SpringApplicationRunListener的finished()方法,完成SpringBoot的启动。

SpringApplicationrun方法中,实例化一个SpringApplication对象,并调用该对象的run方法。

在SpringApplication构造函数中,主要完成了这样两件事:

在run()中主要完成如下几项工作:

在refreshContext方法中实现Ioc容器的初始化和Ioc的依赖注入。其中,在invokeBeanFactoryPostProcessors()方法中完成了IoC容器初始化过程的三个步骤。

第一步:Resource定位

在SpringBoot中,我们都知道他的包扫描是从主类所在的包开始扫描的,prepareContext()方法中,会先将主类解析成BeanDefinition,然后在refresh()方法的invokeBeanFactoryPostProcessors()方法中解析主类的BeanDefinition获取basePackage的路径。这样就完成了定位的过程。其次SpringBoot的各种starter是通过SPI扩展机制实现的自动装配,SpringBoot的自动装配同样也是在invokeBeanFactoryPostProcessors()方法中实现的。还有一种情况,在SpringBoot中有很多的@EnableXXX注解,细心点进去看的应该就知道其底层是@Import注解,在invokeBeanFactoryPostProcessors()方法中也实现了对该注解指定的配置类的定位加载。

常规的在SpringBoot中有三种实现定位,第一个是主类所在包的,第二个是SPI扩展机制实现的自动装配(比如各种starter),第三种就是@Import注解指定的类。

第二步:BeanDefinition的载入

在第一步中说了三种Resource的定位情况,定位后紧接着就是BeanDefinition的分别载入。所谓的载入就是通过上面的定位得到的basePackage,SpringBoot会将该路径拼接成:classpath :org/springframework/boot/demo/ / class这样的形式,然后一个叫做PathMatchingResourcePatternResolver的类会将该路径下所有的class文件都加载进来,然后遍历判断是不是有@Component注解,如果有的话,就是我们要装载的BeanDefinition。大致过程就是这样的了。

TIPS:@Configuration,@Controller,@Service等注解底层都是@Component注解,只不过包装了一层罢了。

第三步:注册BeanDefinition

这个过程通过调用上文提到的BeanDefinitionRegister接口的实现来完成。这个注册过程把载入过程中解析得到的BeanDefinition向IoC容器进行注册。通过上文的分析,我们可以看到,在IoC容器中将BeanDefinition注入到一个ConcurrentHashMap中,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的。比如DefaultListableBeanFactory 中的beanDefinitionMap属性。

invokeBeanFactoryPostProcessors方法中主要通过ConfigurationClassPostProcessor完成IoC容器初始化的过程。

registerBeanPostProcessors方法中注册了AutowiredAnnotationBeanPostProcessor,registerBeanPostProcessors方法中对bean进行初始化时会调用AutowiredAnnotationBeanPostProcessor的接口实现@Autowired,完成Ioc的注入。

参考:

>

Spring Boot连接Redis哨兵集群的原理如下:

1 Spring Boot使用Jedis客户端连接Redis哨兵集群。Jedis是一个Java Redis客户端,它支持连接Redis哨兵集群。

2 Jedis客户端会向Redis哨兵集群发送SENTINEL get-master-addr-by-name命令,获取当前Redis主节点的IP地址和端口号。

3 Jedis客户端会使用获取到的IP地址和端口号连接Redis主节点,并发送PING命令测试连接是否正常。

4 如果连接正常,Jedis客户端会将连接信息保存在连接池中,以便后续使用。

5 如果连接失败,Jedis客户端会向Redis哨兵集群发送SENTINEL get-master-addr-by-name命令,获取新的Redis主节点的IP地址和端口号,然后重复步骤2-4。

6 如果Redis主节点发生故障,Redis哨兵会自动将从节点升级为主节点,并通知Jedis客户端更新连接信息。

总之,Spring Boot连接Redis哨兵集群的原理是通过Jedis客户端向Redis哨兵集群发送命令获取当前Redis主节点的IP地址和端口号,然后使用获取到的信息连接Redis主节点。如果连接失败,Jedis客户端会重新获取新的Redis主节点的IP地址和端口号,直到连接成功为止。如果Redis主节点发生故障,Redis哨兵会自动将从节点升级为主节点,并通知Jedis客户端更新连接信息。

springboot启动流程如下:

启动流程主要分为三个部分,第一部分进行、SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块。

及核心的创建上下文环境模块,第三部分是自动化配置模块,该模块作为springboot自动配置核心,在后面的分析中会详细讨论。在下面的启动程序中我们会串联起结构中的主要功能。

启动过程主要做了以下几件事情:

配置属性、获取监听器,发布应用开始启动事件初、始化输入参数、配置环境,输出banner、创建上下文、预处理上下文、刷新上下文(加载tomcat容器)、再刷新上下文、发布应用已经启动事件、发布应用启动完成事件。

在SpringBoot中启动tomcat的工作在刷新上下这一步。

而tomcat的启动主要是实例化两个组件:Connector、Container,一个tomcat实例就是一个Server,一个Server包含多个Service,也就是多个应用程序,每个Service包含多个Connector和一个Container,而一个Container下又包含多个子容器。

以上就是关于SpringBoot启动原理分析全部的内容,包括:SpringBoot启动原理分析、SpringBoot启动分析、springboo连接redis哨兵集群原理等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9556299.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-29
下一篇 2023-04-29

发表评论

登录后才能评论

评论列表(0条)

保存