SpringBoot启动流程

点击查看回答

总:SpringBoot启动,其本质就是加载各种配置信息
分:在其启动的过程会做这么几个事情
首先,当我们在启动类执行SpringApplication.run这行代码的时候,在它的方法内部其实会做两个事情

  1. 创建SpringApplication对象
  2. 执行run方法

其次,在创建SpringApplication对象的时候,在他的构造方法内部主要做3件事情。

  1. 确认web应用类型,一般情况是Servlet类型,这种类型的应用,将来会自动启动一个tomcat
  2. spring.factories配置文件中,加载默认的ApplicationContextInitializerApplicationListener
  3. 记录当前应用的主启动类,将来做包扫描使用

最后,对象创建好了以后,再调用该对象的run方法,在run方法的内部主要做4个事情

  1. 准备Environment对象,它里面会封装一些当前应用运行环境的参数,比如环境变量等等
  2. 实例化容器,这里仅仅是创建ApplicationContext对象
  3. 容器创建好了以后,会为容器做一些准备工作,比如为容器设置Environment、BeanFactoryPostProcessor后置处理器,并且加载主类对应的Definition
  4. 刷新容器,就是我们常说的referesh,在这里会真正的创建Bean实例

总:总结一下,其实SpringBoot启动的时候核心就两步,创建SpringApplication对象以及run方法的调用,在run方法中会真正实例化容器,并创建容器中需要的bean实例,最终返回

IOC容器初始化流程

点击查看回答

总:IOC容器的初始化,核心工作是在AbstractApplicationContext.refresh方法中完成的
分:在refresh方法中主要做了这么几件事

  1. 准备BeanFactory,在这一块需要给BeanFactory设置很多属性,比如类加载器,Environment等
  2. 执行BeanFactory后置处理器,这一阶段会扫描要放入到容器中的Bean信息,得到对应的BeanDefinition(注意:这里只扫描,不创建)
  3. 是注册BeanPostProcesor,我们自定义的BeanPostProcesor就是在这一阶段被加载的,将来Bean对象实例化好后需要用到
  4. 启动tomcat
  5. 实例化容器中实例化非懒加载的单例Bean,这里需要说的是,多例Bean和懒加载的Bean不会在这个阶段实例化,将来用到的时候再创建
  6. 当容器初始化完毕后,再做一些扫尾工作,比如清除缓存等

总:简单总结一下,在IOC容器初始化的过程中,首先得准备并执行BeanFactory后置处理器,其次得注册Bean后置处理器,并启动tomcat,最后需要借助于BeanFactory完成Bean的实例化

Spring中Bean的生命周期

点击查看回答

总: Bean的生命周期总的来说有4个阶段,分别有创建对象,初始化对象,使用对象以及销毁对象,而且这些工作大部分是交给Bean工厂的doCreateBean方法完成的
分:
首先,在创建对象阶段,先调用构造方法实例化对象,对象有了后会填充该对象的内容,其实就是处理依赖注入
其次,对象创建完毕后,需要做一些初始化的操作,在这里涉及到几个扩展点。

  1. 执行Aware感知接口的回调方法
  2. 执行Bean后置处理器的postProcessBeforelnitialization方法
  3. 执行InitializingBean接口的回调,在这一步如果Bean中有标注了@PostConstruct注解的方法,会先执行它
  4. 执行Bean后置处理器的postProcessAfterInitialization

把这些扩展点都执行完,Bean的初始化就完成了
接下来,在使用阶段就是程序员从容器中获取该Bean使用即可
最后,在容器销毁之前,会先销毁对象,此时会执行DisposableBean接口的回调,这一步如果Bean中有标注了@PreDestroy接口的函数,会先执行它

总:简单总结一下,Bean的生命周期共包含四个阶段,其中初始化对象和销毁对象我们程序员可以通过一些扩展点执行自己的代码

Spring中Bean的循环依赖

点击查看回答

总:Bean的循环依赖指的是A依赖B,B又依赖A这样的依赖闭环问题,在Spring中,通过三个对象缓存区来解决循环依赖问题,这三个缓存区被定义到了DefaultSingletonBeanRegistry中,分别是singletonObjects用来存储创建完毕的Bean,earlySingletonObjecs用来存储未完成依赖注入的Bean,还有SingletonFactories用来存储创建Bean的ObjectFactory。假如说现在A依赖B,B依赖A,整个Bean的创建过程是这样的
分:

首先,调用A的构造方法实例化A,当前的A还没有处理依赖注入,暂且把它称为半成品,此时会把半成品A封装到一个ObjectFactory中,并存储到springFactories缓存区</P>

接下来,要处理A的依赖注入了,由于此时还没有B,所以得先实例化一个B,同样的,半成品B也会被封装到ObiectFactory中并存储到springFactory缓存区

紧接着,要处理B的依赖注入了,此时会找到springFactories中A对应的ObjecFactory, 调用它的getObject方法得到刚才实例化的半成品A(如果需要代理对象,则会自动创建代理对象、将来得到的就是代理对象),把得到的半成品A注入给B,并同时会把半成品A存入到earlvSingletonObjects中,将来如果还有其他的类循环依赖了A,就可以直接从earlvSingletonObjects中找到它了,那么此时springFactories中创建A的ObjectFactory也可以删除了

至此,B的依赖注入处理完了后,B就创建完毕了,就可以把B的对象存入到singletonObjects中了,并同时删除掉springFactories中创建B的ObjectFactory

B创建完毕后,就可以继续处理A的依赖注入了,把B注入给A,此时A也创建完毕了,就可以把A的对象存储到singletonObjects中,并同时删除掉earlySingletonObjects中的半成品A

截此为止,A和B对象全部创建完毕,并存储到了singletonObjects中,将来通过容器获取对象,都是从singletonObeicts中获取


总:总结起来还是一句话,借助于DefaultSingletonBeanRegistry的三个缓存区可以解决循环依赖问题

SpringMvc执行流程

点击查看回答

总:使用了SpringMvc后,所有的请求都需要经过DispatcherServlet前端控制器,该类中提供了一个doDispatch方法,有关请求处理和结果响应的所有流程都在该方法中完成
分:

首先,借助于HandlerMapping处理器映射器得到处理器执行链,里面封装了HandlerMethod代表目标Controller的方法,同时还通过一个集合记录了要执行的拦截器

接下来,会根据HandlerMethod获取对应的HandlerAdapter处理器适配器,里面封装了参数解析器以及结果处理器

然后,执行拦截器的preHandle方法

接下来是核心,通过HandlerAdapter处理器适配器执行目标Controller的方法,在这个过程中会通过参数解析器和结果处理器分别解析浏览器提交的数据以及处理Controller方法返回的结果

然后,执行拦截器的postHandle方法,

最后处理响应,在这个过程中如果有异常抛出,会执行异常的逻辑,这里还会执行全局异常处理器的逻辑,并通过视图解析器ViewResolver解析视图,再渲染视图,最后再执行拦截器的afterCompletion