【备战秋招】30道Spring IOC经典面试题(附答案)(1),2024年最新java面试吧

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

  • 5. IoC 和 DI 的区别?

  • 6. IoC 容器的职责?

  • 7. 什么是 Spring IoC 容器?

  • 8. 构造器注入和 Setter 注入

  • 9. BeanFactory 和 ApplicationContext 谁才是 Spring IoC 容器?

  • 10. Spring Bean 的生命周期?

  • 11. BeanDefinition 是什么?

  • 12. Spring 内建的 Bean 作用域有哪些?

  • 13. BeanPostProcessor 与 BeanFactoryPostProcessor 的区别?

  • 14. 依赖注入和依赖查找的来源是否相同?

  • 15. 如何基于 Extensible XML authoring 扩展 Spring XML 元素?

  • 16. Java 泛型擦写发生在编译时还是运行时?

  • 17. 简述 Spring 事件机制原理?

  • 18. @EventListener 的工作原理?

  • 19. Spring 提供的注解有哪些?

  • 20. 简述 Spring Environment ?

  • 21. Environment 完整的生命周期是怎样的?

  • 22. Spring 应用上下文的生命周期?

  • 23. Spring 应用上下文生命周期有哪些阶段?

  • 24. 简述 ObjectFactory?

  • 25. 简述 FactoryBean?

  • 26. ObjectFactory、FactoryBean 和 BeanFactory 的区别?

  • 27. @Bean 的处理流程是怎样的?

  • 28. BeanFactory 是如何处理循环依赖?

  • 29. Spring 中几种初始化方法的执行顺序?

作为阅读福利,我也整理了一些Spring全家桶的学习笔记(包含脑图、手写pdf、面试真题等)现在免费分享给阅读到本篇文章的Java程序员朋友们,需要的可点击此处获取

1. 什么是 Spring Framework ?

官方文档:

Spring makes it easy to create Java enterprise applications. It provides everything you need to embrace the Java language in an enterprise environment, with support for Groovy and Kotlin as alternative languages on the JVM, and with the flexibility to create many kinds of architectures depending on an application’s needs.

这个问题很难回答,在 Spring 官方文档中的描述也很抽象,答案在于你对 Spring 是如何理解的,想必每个人都有自己的回答方式,以下是我个人对于 Spring 的理解:

整个 Spring 生态在涉及到 Java 的项目中被广泛应用,它提供了非常多的组件,能够让你在开发 Java 应用的过程变得更加容易,弹性地支持其他软件框架,可以比作一个“排插座”,其他软件框架简单地“插上”即可结合 Spring 一起使用,给开发人员带来了非常多的便利。Spring 底层 IoC 容器的设计实现也是非常完美的,在整个 Spring 应用上下文的生命周期和 Spring Bean 的生命周期的许多阶段提供了相应的扩展点,供开发者自行扩展,使得框架非常的灵活。

2. Spring Framework 的优势和不足?

优势:Spring 面向模块进行开发,根据不同的功能进行划分,根据需求引入对应的模块即可,对于开发人员非常友好。例如 Spring IoC 容器,将我们的 Java 对象作为 Spring Bean 进行管理,管理着 Bean 的整个生命周期;Spring MVC 提供“模型-视图-控制器”(Model-View-Controller)架构和随时可用的组件,用于开发灵活且松散耦合的 Web 应用程序;Spring AOP 提供面向切面编程的接口,可以很方便的使用;还有许多其他的功能模块,就不一一讲述了。

不足:整个 Spring 体系比较复杂,对于开发人员需要一定的学习成本,遇到相关问题时需要对底层实现有充分的了解,这也就需要开发人员投入更多的时间和精力去学习。当然,如今 Spring 体系整合了 Java 生态非常多的东西,为开发人员带来的便利远大于这些不足,我觉得是有必要对 Spring 进行充分的学习,去了解 Spring 的贡献者们的设计思路,对自身也会有很大的提升,从中可以学习到许多的东西。

3. 你对 IoC 的理解?

Inversion of Control(IoC)是面向对象中的一种编程思想或原则。可以先回到传统方式,当我依赖一个对象,我需要主动去创建它并进行属性赋值,然后我才能去使用这个对象。对于 IoC 这种方式来说,它使得对象或者组件的创建更为透明,你不需要过多地关注细节,如创建对象、属性赋值,这些工作交都由 IoC 容器来完成,已达到解耦的目的。

IoC 控制反转,简单来理解其实就是把获取依赖对象的方式,交由 IoC 容器来实现,由“主动拉取”变为“被动获取”。

4. 为什么需要 IoC ?

实际上,IoC 是为了屏蔽构造细节。例如 new 出来的对象的生命周期中的所有细节对于使用端都是知道的,如果在没有 IoC 容器的前提下,IoC 是没有存在的必要,不过在复杂的系统中,我们的应用更应该关注的是对象的运用,而非它的构造和初始化等细节。

5. IoC 和 DI 的区别?

DI 依赖注入不完全等同于 IoC,更应该说 DI 依赖注入是 IoC 的一种实现方式或策略。

依赖查找依赖注入都是 IoC 的实现策略。依赖查找就是在应用程序里面主动调用 IoC 容器提供的接口去获取对应的 Bean 对象,而依赖注入是在 IoC 容器启动或者初始化的时候,通过构造器、字段、setter 方法或者接口等方式注入依赖。依赖查找相比于依赖注入对于开发者而言更加繁琐,具有一定的代码入侵性,需要借助 IoC 容器提供的接口,所以我们总是强调后者。依赖注入在 IoC 容器中的实现也是调用相关的接口获取 Bean 对象,只不过这些工作都是在 IoC 容器启动时由容器帮你实现了,在应用程序中我们通常很少主动去调用接口获取 Bean 对象。

6. IoC 容器的职责?

主要有以下职责:

  • 依赖处理,通过依赖查找或者依赖注入

  • 管理托管的资源(Java Bean 或其他资源)的生命周期

  • 管理配置(容器配置、外部化配置、托管的资源的配置)

IoC 容器有非常多,例如 JDK 的 Java Beans,Java EE 的 EJB,Apache Avalon,Google guice,Spring,其中 Spring 是最成功的的一个,目前被广泛应用。

其中 Spring 借鉴了 JDK 的 Java Beans 设计思想,也使用到其中相关类(例如 java.beans.PropertyEditor 属性编辑器),开发过 IDE 的 GUI 界面的伙伴应该对 Java Beans 比较熟悉。

7. 什么是 Spring IoC 容器?

Spring 框架是一个 IoC 容器的实现,DI 依赖注入是它的实现的一个原则,提供依赖查找和依赖注入两种依赖处理,管理着 Bean 的生命周期。Spring 还提供了 AOP 抽象、事件抽象、事件监听机制、SPI 机制、强大的第三方整合、易测试性等其他特性。

8. 构造器注入和 Setter 注入

构造器注入:通过构造器的参数注入相关依赖对象

Setter 注入:通过 Setter 方法注入依赖对象,也可以理解为字段注入

对于两种注入方式的看法:

  • 构造器注入可以避免一些尴尬的问题,比如说状态不确定性地被修改,在初始化该对象时才会注入依赖对象,一定程度上保证了 Bean 初始化后就是不变的对象,这样对于我们的程序和维护性都会带来更多的便利;

  • 构造器注入不允许出现循环依赖,因为它要求被注入的对象都是成熟态,保证能够实例化,而 Setter 注入或字段注入没有这样的要求;

  • 构造器注入可以保证依赖的对象能够有序的被注入,而 Setter 注入或字段注入底层是通过反射机制进行注入,无法完全保证注入的顺序;

  • 如果构造器注入出现比较多的依赖导致代码不够优雅,我们应该考虑自身代码的设计是否存在问题,是否需要重构代码结构。

除了上面的注入方式外,Spring 还提供了接口回调注入,通过实现 Aware 接口(例如 BeanNameAware、ApplicationContextAware)可以注入相关对象,Spring 在初始化这类 Bean 时会调用其 setXxx 方法注入对象,例如注入 beanName、ApplicationContext

9. BeanFactory 和 ApplicationContext 谁才是 Spring IoC 容器?

BeanFactory 是 Spring 底层 IoC 容器,ApplicationContext 是 BeanFactory 的子接口,是 BeanFactory 的一个超集,提供 IoC 容器以外更多的功能。ApplicationContext 除了扮演 IoC 容器角色,还提供了这些企业特性:面向切面(AOP)、配置元信息、资源管理、事件机制、国际化、注解、Environment 抽象等。我们一般称 ApplicationContext 是 Spring 应用上下文,BeanFactory 为 Spring 底层 IoC 容器。

10. Spring Bean 的生命周期?

生命周期:

  1. Spring Bean 元信息配置阶段,可以通过面向资源(XML 或 Properties)、面向注解、面向 API 进行配置

  2. Spring Bean 元信息解析阶段,对上一步的配置元信息进行解析,解析成 BeanDefinition 对象,该对象包含定义 Bean 的所有信息,用于实例化一个 Spring Bean

  3. Spring Bean 元信息注册阶段,将 BeanDefinition 配置元信息 保存至 BeanDefinitionRegistry 的 ConcurrentHashMap 集合中

  4. Spring BeanDefinition 合并阶段,定义的 Bean 可能存在层次性关系,则需要将它们进行合并,存在相同配置则覆盖父属性,最终生成一个 RootBeanDefinition 对象

  5. Spring Bean 的实例化阶段,首先的通过类加载器加载出一个 Class 对象,通过这个 Class 对象的构造器创建一个实例对象,构造器注入在此处会完成。在实例化阶段 Spring 提供了实例化前后两个扩展点(InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation、postProcessAfterInstantiation 方法)

  6. Spring Bean 属性赋值阶段,在 Spring 实例化后,需要对其相关属性进行赋值,注入依赖的对象。首先获取该对象所有属性与属性值的映射,可能已定义,也可能需要注入,在这里都会进行赋值(反射机制)。提示一下,依赖注入的实现通过 CommonAnnotationBeanPostProcessor(@Resource、@PostConstruct、@PreDestroy)和 AutowiredAnnotationBeanPostProcessor(@Autowired、@Value)两个处理器实现的。

  7. Aware 接口回调阶段,如果 Spring Bean 是 Spring 提供的 Aware 接口类型(例如 BeanNameAware、ApplicationContextAware),这里会进行接口的回调,注入相关对象(例如 beanName、ApplicationContext)

  8. Spring Bean 初始化阶段,这里会调用 Spring Bean 配置的初始化方法,执行顺序:@PostConstruct 标注方法、实现 InitializingBean 接口的 afterPropertiesSet() 方法、自定义初始化方法。在初始化阶段 Spring 提供了初始化前后两个扩展点(BeanPostProcessor 的 postProcessBeforeInitialization、postProcessAfterInitialization 方法)

  9. Spring Bean 初始化完成阶段,在所有的 Bean(不是抽象、单例模式、不是懒加载方式)初始化后,Spring 会再次遍历所有初始化好的单例 Bean 对象,如果是 SmartInitializingSingleton 类型则调用其 afterSingletonsInstantiated() 方法,这里也属于 Spring 提供的一个扩展点

  10. Spring Bean 销毁阶段,当 Spring 应用上下文关闭或者你主动销毁某个 Bean 时则进入 Spring Bean 的销毁阶段,执行顺序:@PreDestroy 注解的销毁动作、实现了 DisposableBean 接口的 Bean 的回调、destroy-method 自定义的销毁方法。这里也有一个销毁前阶段,也属于 Spring 提供的一个扩展点,@PreDestroy 就是基于这个实现的

  11. Spring 垃圾收集(GC)

总结:

  1. 上面 123 属于 BeanDefinition 配置元信息阶段,算是 Spring Bean 的前身,想要生成一个 Bean 对象,需要将这个 Bean 的所有信息都定义好;

  2. 其中 45 属于实例化阶段,想要生成一个 Java Bean 对象,那么肯定需要根据 Bean 的元信息先实例化一个对象;

  3. 接下来的 6 属于属性赋值阶段,实例化后的对象还是一个空对象,我们需要根据 Bean 的元信息对该对象的所有属性进行赋值;

  4. 后面的 78 、9 属于初始化阶段,在 Java Bean 对象生成后,可能需要对这个对象进行相关初始化工作才予以使用;

  5. 最后面的 1011 属于销毁阶段,当 Spring 应用上下文关闭或者主动销毁某个 Bean 时,可能需要对这个对象进行相关销毁工作,最后等待 JVM 进行回收。

11. BeanDefinition 是什么?

BeanDefinition 是 Spring Bean 的“前身”,其内部包含了初始化一个 Bean 的所有元信息,在 Spring 初始化一个 Bean 的过程中需要根据该对象生成一个 Bean 对象并进行一系列的初始化工作。

12. Spring 内建的 Bean 作用域有哪些?

| 来源 | 说明 |

| — | — |

| singleton | 默认 Spring Bean 作用域,一个 BeanFactory 有且仅有一个实例 |

| prototype | 原型作用域,每次依赖查找和依赖注入生成新 Bean 对象 |

| request | 将 Spring Bean 存储在 ServletRequest 上下文中 |

| session | 将 Spring Bean 存储在 HttpSession 中 |

| application | 将 Spring Bean 存储在 ServletContext 中 |

13. BeanPostProcessor 与 BeanFactoryPostProcessor 的区别?

BeanPostProcessor 提供 Spring Bean 初始化前和初始化后的生命周期回调,允许对关心的 Bean 进行扩展,甚至是替换,其相关子类也提供 Spring Bean 生命周期中其他阶段的回调。

BeanFactoryPostProcessor 提供 Spring BeanFactory(底层 IoC 容器)的生命周期的回调,用于扩展 BeanFactory(实际为 ConfigurableListableBeanFactory),BeanFactoryPostProcessor 必须由 Spring ApplicationContext 执行,BeanFactory 无法与其直接交互。

14. 依赖注入和依赖查找的来源是否相同?

否,依赖查找的来源仅限于 Spring BeanDefinition 以及单例对象,而依赖注入的来源还包括 Resolvable Dependency(Spring 应用上下文定义的可已处理的注入对象,例如注入 BeanFactory 注入的是 ApplicationContext 对象)以及 @Value 所标注的外部化配置

15. 如何基于 Extensible XML authoring 扩展 Spring XML 元素?

Spring XML 扩展

  1. 编写 XML Schema 文件(XSD 文件):定义 XML 结构

  2. 自定义 NamespaceHandler 实现:定义命名空间的处理器

  3. 自定义 BeanDefinitionParser 实现:绑定命名空间下不同的 XML 元素与其对应的解析器

  4. 注册 XML 扩展(META-INF/spring.handlers 文件):命名空间与命名空间处理器的映射

  5. 编写 Spring Schema 资源映射文件(META-INF/spring.schemas 文件):XML Schema 文件通常定义为网络的形式,在无网的情况下无法访问,所以一般在本地的也有一个 XSD 文件,可通过编写 spring.schemas 文件,将网络形式的 XSD 文件与本地的 XSD 文件进行映射,这样会优先从本地获取对应的 XSD 文件

Mybatis 对 Spring 的集成项目中的 <mybatis:scan /> 标签就是这样实现的,可以参考:NamespaceHandlerMapperScannerBeanDefinitionParserXSD 等文件

具体实现逻辑参考后续**《解析自定义标签(XML 文件)》**一文

16. Java 泛型擦写发生在编译时还是运行时?

运行时。编译时,泛型参数类型还是存在的,运行时会忽略。

17. 简述 Spring 事件机制原理?

主要有以下几个角色:

  • Spring 事件 - org.springframework.context.ApplicationEvent,实现了 java.util.EventListener 接口

  • Spring 事件监听器 - org.springframework.context.ApplicationListener,实现了 java.util.EventObject 类

  • Spring 事件发布器 - org.springframework.context.ApplicationEventPublisher

  • Spring 事件广播器 - org.springframework.context.event.ApplicationEventMulticaster

Spring 内建的事件:

  • ContextRefreshedEvent:Spring 应用上下文就绪事件

  • ContextStartedEvent:Spring 应用上下文启动事件

  • ContextStoppedEvent:Spring 应用上下文停止事件

  • ContextClosedEvent:Spring 应用上下文关闭事件

Spring 应用上下文就是一个 ApplicationEventPublisher 事件发布器,其内部有一个 ApplicationEventMulticaster 事件广播器(被观察者),里面保存了所有的 ApplicationListener 事件监听器(观察者)。Spring 应用上下文发布一个事件后会通过 ApplicationEventMulticaster 事件广播器进行广播,能够处理该事件类型的 ApplicationListener 事件监听器则进行处理。

18. @EventListener 的工作原理?

@EventListener 用于标注在方法上面,该方法则可以用来处理 Spring 的相关事件。

Spring 内部有一个处理器 EventListenerMethodProcessor,它实现了 SmartInitializingSingleton 接口,在所有的 Bean(不是抽象、单例模式、不是懒加载方式)初始化后,Spring 会再次遍历所有初始化好的单例 Bean 对象时会执行该处理器对该 Bean 进行处理。在 EventListenerMethodProcessor 中会对标注了 @EventListener 注解的方法进行解析,如果符合条件则生成一个 ApplicationListener 事件监听器并注册。

19. Spring 提供的注解有哪些?

核心注解有以下:

  • Spring 模式注解

| Spring 注解 | 场景说明 | 起始版本 |

| — | — | — |

| @Repository | 数据仓储模式注解 | 2.0 |

| @Component | 通用组件模式注解 | 2.5 |

| @Service | 服务模式注解 | 2.5 |

| @Controller | Web 控制器模式注解 | 2.5 |

| @Configuration | 配置类模式注解 | 3.0 |

Spring 模式注解都是 @Component 的派生注解,Spring 为什么会提供这么多派生注解?

@Component 注解是一个通用组件注解,标注这个注解后表明你需要将其作为一个 Spring Bean 进行使用,而其他注解都有各自的作用,例如 @Controller 及其派生注解用于 Web 场景下处理 HTTP 请求,@Configuration 注解通常会将这个 Spring Bean 作为一个配置类,也会被 CGLIB 提供,帮助实现 AOP 特性。这也是领域驱动设计中的一种思想。

领域驱动设计:Domain-Driven Design,简称 DDD。过去系统分析和系统设计都是分离的,这样割裂的结果导致需求分析的结果无法直接进行设计编程,而能够进行编程运行的代码却扭曲需求,导致客户运行软件后才发现很多功能不是自己想要的,而且软件不能快速跟随需求变化。DDD 则打破了这种隔阂,提出了领域模型概念,统一了分析和设计编程,使得软件能够更灵活快速跟随需求变化。

  • 装配注解

| Spring 注解 | 场景说明 | 起始版本 |

| — | — | — |

| @ImportResource | 替换 XML 元素 <import> | 2.5 |

| @Import | 导入 Configuration 类 | 2.5 |

| @ComponentScan | 扫描指定 package 下标注 Spring 模式注解的类 | 3.1 |

  • 依赖注入注解

| Spring 注解 | 场景说明 | 起始版本 |

| — | — | — |

| @Autowired | Bean 依赖注入,支持多中依赖查找方式 | 2.5 |

| @Qualifier | 细粒度的 @Autowired 依赖查找 | 2.5 |

  • @Enable 模块驱动

| Spring 注解 | 场景说明 | 起始版本 |

最后

做任何事情都要用心,要非常关注细节。看起来不起眼的、繁琐的工作做透了会有意想不到的价值。
当然要想成为一个技术大牛也需要一定的思想格局,思想决定未来你要往哪个方向去走, 建议多看一些人生规划方面的书籍,多学习名人的思想格局,未来你的路会走的更远。

更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
书籍,多学习名人的思想格局,未来你的路会走的更远。

更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务

[外链图片转存中…(img-IBidlsdB-1713439175928)]

[外链图片转存中…(img-lAFBMrFw-1713439175928)]

[外链图片转存中…(img-eGbqozxN-1713439175929)]

[外链图片转存中…(img-LwhBQ2ZM-1713439175929)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-Z3LI64d2-1713439175929)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值