谈一谈SpringBoot的启动流程

一、 启动类中的SpringApplication.run(),里面会对ApplicationContext容器创建进行一些必要的设置

  例如SpringApplicaton类的构造函数设置监听器和初始化器作为容器准备的参数
  例如SpringApplicaton类的run方法中的ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);封装命令行参数对象作为容器准备的参数
  例如SpringApplicaton类的run方法中的ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);配置应用程序环境作为容器准备的参数

二、上面都是SpringApplicaton类为我们的ApplicationContext容器初始化进行必要的设置,接下来就是ApplicationContext容器利用这些配置,还是在SpringApplicaton类的run方法中:

  context = this.createApplicationContext();创建ApplicationContext容器
  this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);根据SpringApplicaton类提供的配置准备容器
  this.refreshContext(context);刷新容器
  this.afterRefresh(context, applicationArguments);会查找所有实现了 ApplicationRunner 或 CommandLineRunner 接口的 bean,并调用它们的 run 方法。这些接口允许你在应用程序启动后立即执行一些代码,例如发送启动通知、执行初始化任务或启动后台任务

三、 现在说一下刷新容器的的逻辑(此时beanDefinationMap里一般会有6个初始的键值对)

  其中会遍历BeanDefinitionNames,按照BeanDefinitionNames中Bean定义的注册顺序找到beanDefinationMap中这6个初始的键值对,主要是找到启动类的BeanDefination定义信息,主要是解析启动类(配置类)的注解,将注解的配置路径加载为bean定义注册到容器的beanDefinationMap中,然后根据beanDefinationMap的bean定义进行该bean的实例化、属性填充、初始化,生成的bean实例注册到singletonObjects中。这是大体的逻辑,现在细致的说一说。

四、在SpringApplicaton类的run方法中,会调用this.refreshContext()方法,实际调用的是AbstractApplicationContext中的refresh方法,

  1、里面会调用this.invokeBeanFactoryPostProcessor()方法,主要是从beanDefinationMap中找到internalConfigurationAnnotationProcess(BeanFactoryPostProcessor的一个实现类)BeanDefination定义信息,然后生成它的实例,将该实例注册到singletonObjects中。通过调用invokeBeanDefinationRegistryPostProcessor()方法调用该实例的postProcessBeanDifinationRegistry()方法,方法里面还是从beanDefinationMap找到启动类(配置类)的BeanDefination定义信息,解析其@Configuration注解,@Component注解,@Controller注解等等,确保所有的配置路径文件都以BeanDefination定义信息的形式被注册到Spring容器的beanDefinationMap中并存放BeanDefination注册顺序到beanDefinationNames中。后续会根据注册顺序遍历beanDefinationMap,找到里面的Bean定义创建Bean实例。
  2、里面接下来就会调用this.registryBeanPostProcessors()方法,从beanDefinationMap中获取BeanPostProcessor.class有关的Bean定义,并创建其实例注册到singletonObjects和BeanPostProcessors中,为了给后续遍历beanDefinationMap,根据里面的Bean定义创建Bean实例时,初始化的前后阶段对Bean进行额外的处理。
  3、里面接下来就是调用this.onRefresh()方法,里面调用了this.createWebServer()创建和配置嵌入式Web服务器。里面会获取ServletWebServerFactory实例,会应用所有已经注册的自定义WebServerFactoryCustomizer来配置Web服务器,这些Customizer可以用来修改Web服务器的端口、上下文路径、SSL配置等。最终来创建WebServer实例,然后初始化,准备启动服务器。这个WebServer实例会在后续的步骤中被启动,后续调用WebServer实例的start()方法来进行启动服务器,然后Web服务器开始监听请求并处理传入的Http请求。
  4、里面接下来就是调用this.finishbeanFactoryInitialization(),它会遍历BeanDefinitionNames,按照BeanDefinitionNames中Bean定义的注册顺序,找到beanDefinationMap中相应Bean定义信息并完成实例化、属性注入、初始化等。Bean的属性注入时会处理循环依赖,Bean的初始化前后置处理(BeanPostProcessors里的方法)也会在这里开始进行调用。到这里beanDefinationMap中非懒加载的Bean定义信息都会被创建为实例然后存放在singletonObjects中。
  5、里面接下来就是调用this.finishRefresh(),里面会启动之前创建的WebServer实例,此时Web服务器开始接收请求,剩下的就是SpringMVC逻辑。

五、SpringMVC逻辑

  嵌入式Web服务器开始监听指定端口上的Http请求,接收到请求后,会将请求转发给DispatcherServlet实例,DispatcherServlet实例会根据请求的URL,遍历HandlerMapping中的键值对(创建DispatcherServlet实例时会初始化HandlerMapping键值对,检测所有的singletonObjects中的Bean,找到哪些是控制器类的Bean,检查里面带有注解的方法,并将注解信息封装到MappingInfo对象中,而注解标记的方法会被封装到HandMethod对象中,HandMethod对象中存储了控制器实例和对应的方法Method对象)找到处理器方法,然后HandlerAdapter实例会通过反射调用处理器方法,根据处理器方法返回值的类型来决定返回什么,HandlerAdapter实例可能会返回一个ModelAndView对象或一个视图名称,或一个ResponseEntity对象或其它的响应,不过这些过程在SpringMVC中都是自动的。
  试着想象一下Vue页面使用场景,用户通过浏览器地址发送一个请求,服务器根据地址会返回一个单页面Vue(这个Vue页面在服务器中是以静态文件的身份存放的),然后用户在浏览器中操作这个单页面应用,不断地像服务器请求数据,SpringBoot接收请求然后调用里面早已注册的Bean实例进行方法的调用,或者说是任务的处理,然后将数据返回给客户,剩下的都是前端页面处理这些数据展示了。

六、总结

  总之,从整个客户端-服务端的流程来看,逻辑大致是这样,大家可以试着顺着我的逻辑来理解代码,进行更加深入的了解。尤其是在beanDefinationMap和singletonObjects中寻找数据进行验证。还可以了解,比如是怎么遍历beanDefinationMap中所有Bean定义信息并完成实例化、属性注入、初始化的;循环依赖是怎么解决的;实现这些SpringBoot自带的接口,看看会不会被调用等等。由于代码太多,以上这些是我挑选的一些很主要的一些代码进行的讲解希望这些内容对大家会有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值