SpringBoot | 面试题

基础知识

ApplicationContextInitializer 如何使用 ?
  1. IOC 容器对象创建完成后执行 , 常用于环境属性注册
  2. 自定义类 , 实现 ApplicationContextInitializer 接口

initialize 方法什么时候执行 ?
  1. 在 META-INF/spring.factories 配置文件中配置自定义的类

 ApplicationListener 如何使用 ?
  1. IOC 容器发布事件之后执行 , 通常用于资源加载 , 定时任务发布等
  2. 自定义类 , 实现 ApplicationListener 接口

onApplicationEvent 方法什么时候执行 ?
  1. 在 META-INF/spring.factories 配置文件中配置自定义的类

BeanFactory 的作用 ?
  1. ApplicationConfigServletServerApplicationContext
  2. DefaultListableBeanFactory

BeanFactory 常见的两个实现 ?
  1. Bean 容器的根接口 , 提供 Bean 对象的创建、配置、依赖注入等功能

面试题

Q:SpringBoot 启动流程

答:SpringBoot 启动,其本质就是加载各种配置信息,然后初始化 IOC 容器并返回。
在其启动的过程中会做这么几个事情
首先,当我们在启动类执行 SpringApplication.run 这行代码的时候,在它的方法内部其实会做两个事情

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

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

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

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

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

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

Q:IOC 容器的初始化流程

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

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

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

Q:Bean 生命周期

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

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

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


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

Q:Bean 循环依赖

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

  • 1.调用 A 的构造方法实例化 A ,当前的 A 还没有处理依赖注入,暂且把它称为半成品,此时会把半成品 A 封装到一个 ObjectFactory 中,并存储到 springFactories 缓存区
  • 2.要处理 A 的依赖注入了,由于此时还没有 B ,所以得先实例化一个 B ,同样的,半成品 B 也会被封装到ObjectFactory 中,并存储到 springFactory 缓存区
  • 3.要处理 B 的依赖注入了,此时会找到 springFactories 中 A 对应的 ObjecFactory, 调用它的 getObject方法得到刚才实例化的半成品 A( 如果需要代理对象 , 则会自动创建代理对象 , 将来得到的就是代理对象 ) ,把得到的半成品 A注入给 B ,并同时会把半成品 A 存入到 earlySingletonObjects 中,将来如果还有其他的类循环依赖了 A ,就可以直接从earlySingletonObjects 中找到它了,那么此时 springFactories 中创建 A ObjectFactory 也可以删除了
  • 4.B 的依赖注入处理完了后, B 就创建完毕了,就可以把 B 的对象存入到 singletonObjects 中了,并同时删除掉 springFactories 中创建 B 的 ObjectFactory
  • 5.B 创建完毕后,就可以继续处理 A 的依赖注入了,把 B 注入给 A ,此时 A 也创建完毕了,就可以把 A 的对象存储到singletonObjects 中,并同时删除掉 earlySingletonObjects 中的半成品 A

截此为止, A 和 B 对象全部创建完毕,并存储到了 singletonObjects 中,将来通过容器获取对象,都是从singletonObejcts 中获取
总:总结起来还是一句话,借助于 DefaultSingletonBeanRegistry 的三个缓存区可以解决循环依赖问题

Q:SpringMvc 执行流程

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

  • 1.借助于 HandlerMapping 处理器映射器得到处理器执行链,里面封装了 HandlerMethod 代表目标Controller 的方法,同时还通过一个集合记录了要执行的拦截器
  • 2.会根据 HandlerMethod 获取对应的 HandlerAdapter 处理器适配器,里面封装了参数解析器以及结果处理器
  • 3.执行拦截器的 preHandle 方法
  • 4.通过 HandlerAdapter 处理器适配器执行目标 Controller 的方法,在这个过程中会通过参数解析器和结果处理器分别解析浏览器提交的数据以及处理 Controller 方法返回的结果
  • 5.执行拦截器的 postHandle 方法
  • 6.处理响应,在这个过程中如果有异常抛出,会执行异常的逻辑,这里还会执行全局异常处理器的逻辑,并通过视图解析器 ViewResolver 解析视图,再渲染视图,最后再执行拦截器的 afterCompletion

  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是建立在现有Spring框架之上的一种方法,它可以帮助我们以最少的工作量更加健壮地使用现有的Spring功能。关于Spring Boot的源码面试题,以下是一些可能的问题: 1. Spring Boot是如何简化Spring应用程序的开发和配置的? 2. 请简要解释一下Spring Boot的核心原理和机制。 3. Spring Boot的自动配置是如何工作的?可以举一个例子来说明吗? 4. Spring Boot中的关键注解是什么?它们分别有什么作用? 5. 如何自定义和扩展Spring Boot的自动配置? 6. Spring Boot的启动过程是怎样的?请描述一下。 7. @SpringBootApplication注解的作用是什么?它与其他Spring注解有什么区别? 8. Spring Boot Actuator的作用是什么?如何将其集成到项目中? 这些问题可以帮助面试者深入了解Spring Boot的原理和机制,以及如何在实际项目中使用和扩展它。当然,在面试中还可能出现其他与Spring Boot源码相关的问题,因此准备时应该全面了解Spring Boot的核心概念和源码结构。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [springBoot常见面试题(2023最新)](https://blog.csdn.net/twotwo22222/article/details/129260502)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Spring面试题汇总3:SpringBoot面试题及答案整理](https://blog.csdn.net/a724888/article/details/116520204)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值