Spring⾯试题-IOC总结
1. SpringFramework的基本知识
1.1 SpringFramework概述
SpringFramework 是⼀个开源的、松耦合的、分层的、可配置的⼀站式企业级 Java 开发框架,它的核⼼是 IOC 与 AOP ,它可以更容易的构建出企业级 Java 应⽤,并且它可以根据应⽤开发的组件需要,整合对应的技术。
1.2 为什么使⽤SpringFramework
IOC:组件之间的解耦(由强依赖降为弱依赖)
AOP:切⾯编程可以将应⽤业务做统⼀或特定的功能增强,能实现应⽤业务与增强逻辑的解耦
容器与事件:管理应⽤中使⽤的组件 Bean、托管 Bean 的⽣命周期、事件与的驱动机制
Web、事务控制、测试、与其他技术的整合
1.3 SpringFramework的模块划分
beans、core、context、expression 【核⼼包、容器】
aop 【切⾯编程】
jdbc 【整合 jdbc 】
orm 【整合 ORM 框架】
tx 【事务控制】
web 【 Web 层技术】
test 【整合测试】
......
2. IOC相关
2.1 如何理解IOC
IOC 控制反转是⼀种思想,它的核⼼是将控制权转交出去。利⽤ IOC 思想,可以实现组件之间的解耦。IOC 的实现⽅式通常有依赖注⼊和依赖查。
2.2 为什么使⽤IOC
解耦
解决对象间的依赖关系
托管对象的⼤部分⽣命周期过程,应⽤程序仅关⼼使⽤过程
2.3 IOC的实现⽅式及对⽐
IOC 仅仅是⼀种思想,依赖查 DL 和依赖注⼊ DI 才是 IOC 的落地实现。具体对⽐如下:
作⽤⽬标不同
依赖注⼊的作⽤⽬标通常是类成员(当然也可以是⽅法参数)
依赖查的作⽤⽬标可以是⽅法体内,也可以是⽅法体外
实现⽅式不同
依赖注⼊通常借助⼀个上下⽂被动的接收(标注 @Autowired 注解 / <property> 标签配置)
依赖查通常主动使⽤上下⽂搜索(拿到 BeanFactory / ApplicationContext 之后主动调⽤ getBean ⽅法)
2.4 IOC在Spring中的实现⽅式
依赖查
getBean :根据 name 获取 / 根据 Class 获取指定的 bean
ofType :根据 Class 获取容器中所有指定类型的 bean
withAnnotation :获取标注了指定注解的 bean
getBeanDefinitionNames :获取容器中的所有 bean 的 name
getBeanProvider :延迟查,先获取 ObjectProvider 后获取实际的对象,如果不存在可使⽤缺省值代替
依赖注⼊
xml 配置⽂件
借助 <property> 标签给带有 setter ⽅法的属性赋值 / 注⼊依赖对象
借助 <constructor-arg> 标签使⽤ bean 的构造器注⼊依赖对象 / 属性赋值
注解驱动⽅式
使⽤ @Value 给普通属性赋值
使⽤ @Autowired / @Resource / @Inject 注解给组件依赖注⼊
借助 ObjectProvider 可以实现组件延迟注⼊
借助 Aware 系列接⼝实现回调注⼊
2.5 使⽤依赖注⼊的优点
⾸先,依赖注⼊作为 IOC 的实现⽅式之⼀,⽬的就是解耦,我们不再需要直接去 new 那些依赖的类对象(直接依赖会导致对象的创建机制、初始化过程难以统⼀控制);⽽且,如果组件存在多级依赖,依赖注⼊可以将这些依赖的关系简化,开发者只需要定义好谁依赖谁即可。
除此之外,依赖注⼊的另⼀个特点是依赖对象的可配置:通过 xml 或者注解声明,可以指定和调整组
件注⼊的对象,借助 Java 的多态特性,可以不需要⼤批量的修改就完成依赖注⼊的对象替换(⾯向接⼝编程与依赖注⼊配合近乎完美)。
再有⼀个,依赖注⼊可以不需要依赖框架的 API (仅依赖 JSR 规范也可以实现依赖注⼊),⽽依赖查必须要拿到框架的容器 API ,从这⼀点也能看出来依赖注⼊的⼀个优点是与框架 API 的低耦合。
这⾥⼩册加了⼀段话,这是依赖注⼊对⽐于依赖查的⼀个还算⽐较明显的区别了,由于依赖注⼊只需要配置 / 标注注⼊的注解,所以不需要拿到框架的 API ,这就相当于降低了应⽤代码与框架底层的耦合。
2.6 依赖注⼊的注⼊⽅式对⽐
注⼊⽅式被注⼊成员是否可变是否依赖IOC框架的API使⽤场景
构造器注⼊不可变否(xml、编程式注⼊不依赖)不可变的固定注⼊
参数注⼊不可变否(⾼版本中注解配置类中的 @Bean ⽅法参数注⼊可不标注注解)注解配置类中 @Bean ⽅法注册 bean
属性注⼊不可变是(只能通过标注注解来侵⼊式注⼊)通常⽤于不可变的固定注⼊
setter注⼊可变否(xml、编程式注⼊不依赖)可选属性的注⼊
2.7 ⾃动注⼊的注解对⽐
注解注⼊⽅式⽀持@Primary来源Bean不存在时处理
@Autowired根据类型注⼊⽀持SpringFramework 原⽣注解可指定 required=false 来避免注⼊失败
@Resource根据名称注⼊⽀持JSR 250 规范容器中不存在指定 Bean 会抛出异常
@Inject根据类型注⼊⽀持JSR 330 规范 ( 需要导jar包 )容器中不存在指定 Bean 会抛出异常
@Qualifier :如果被标注的成员 / ⽅法在根据类型注⼊时发现有多个相同类型的 Bean ,则会根据该注解声明的 name 寻特定的 bean 。
@Primary :如果有多个相同类型的 Bean 同时注册到 IOC 容器中,使⽤ “根据类型注⼊” 的注解时会注⼊标注 @Primary 注解的 bean 。
2.8 使⽤setter注⼊还是构造器注⼊
SpringFramework 4.0.2 及之前是推荐 setter 注⼊,理由是⼀个 Bean 有多个依赖时,构造器的参数列
表会很长;⽽且如果 Bean 中依赖的属性不都是必需的话,注⼊会变得更⿇烦;
4.0.3 及以后官⽅推荐构造器注⼊,理由是构造器注⼊的依赖是不可变的、完全初始化好的,且可以保证不为 null ;
当然 4.0.3 及以后的官⽅⽂档中也说了,如果真的出现构造器参数列表过长的情况,可能是这个 Bean 承担的责任太多,应该考虑组件的责任拆解。
官⽅⽂档的截图可回到第 10 章查看,图⽚太⼤了这⾥就不贴了
这个问题,最好的保险回答是引⽤官⽅⽂档,⽽官⽅⽂档在不同的版本推荐的注⼊⽅式也不同,这⾥更推荐⼩伙伴们采⽤ “官⽅⽂档+ ⾃⼰的理解” 的⽅式回答,这样更稳。
2.9 Spring中的⾃动注⼊模式
byType :根据类型注⼊
byName :根据组件的 name 注⼊
byConstructor :根据构造器注⼊
autodetect :通过类的内省机制决定使⽤哪种⽅式注⼊
顺序:byConstructor → byType
no :不⾃动注⼊(默认)
这个问题之前可能问的⽐较多,由于现在⾃动注⼊模式的使⽤越来越少了,所以这个问题相对的也就没多少关注度了,不过⼩伙伴们还是知道⼀下为好。
3. IOC容器相关
3.1 如何对⽐BeanFactory与ApplicationContext
BeanFactory 接⼝提供了⼀个抽象的配置和对象的管理机制,ApplicationContext 是 BeanFactory 的⼦接⼝,它简化了与 AOP 的整合、消息机制、事件机制,以及对 Web 环境的扩展( WebApplicationContext 等),BeanFactory 是没有这些扩展的。
ApplicationContext 主要扩展了以下功能:
AOP 的⽀持( AnnotationAwareAspectJAutoProxyCreator 作⽤于 bean 的初始化之后 )
配置元信息( BeanDefinition 、Environment 、注解等 )
资源管理( Resource 抽象 )
事件驱动机制( ApplicationEvent 、ApplicationListener )
消息与国际化( LocaleResolver )
Environment 抽象( SpringFramework 3.1 以后)
Feature BeanFactory ApplicationContext Bean instantiation/wiring —— Bean 的实例化和属性注⼊Yes Yes
Integrated lifecycle management —— ⽣命周期管理No Yes
Feature BeanFactory ApplicationContext Automatic BeanPostProcessor registration —— Bean后置处理器的⽀持No Yes
Automatic BeanFactoryPostProcessor registration —— BeanFactory 的后置处理器的⽀持No Yes
Convenient MessageSource access (for internalization) —— 消息转换服务(国际化)No Yes
Built-in ApplicationEvent publication mechanism —— 事件发布机制(事件驱动)No Yes
如果⾯试中被问到这个问题,注意在回答时表达清楚 ApplicationContext 是基于 BeanFactory 的扩展⽽不是继承!因为底层我们也看到了,⽆论是 AbstractRefreshableApplicationContext 还是 GenericApplicationContext ,底层都是组合了⼀
个 DefaultListableBeanFactory 。
除此之外,可以适当的引⽤官⽅⽂档的内容(可参照第 6 章 2.1 节)加以阐述,增加论述的可靠性。
3.2 ApplicationContext的类型
从⽀持的配置源的⾓度来看,ApplicationContext 分为两种:基于 xml 配置⽂件的 ApplicationContext ,和基于注解驱动配置类
的 ApplicationContext 。其中基于 xml 配置⽂件的 ApplicationContext ⼜
有 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext 两种,它们的区别是加载 xml 配置⽂件的基准路径不同;基于注解驱动配置类的 ApplicationContext 只有 AnnotationConfigApplicationContext ,它可以基于配置类驱动,也可以基于包扫描路径驱动。
注意,这个问题只是区分了最基本的 ApplicationContext 的落地实现,如果有细问到更深⼊的内容,可以参照第 15
章 ApplicationContext 全解析的内容辅以理解。
3.3 对⽐BeanFactory与FactoryBean
BeanFactory :SpringFramework 中实现 IOC 的最底层容器(此处的回答可以从两种⾓度出发:从类的继承结构上看,它是最顶级的接⼝,也就是最顶层的容器实现;从类的组合结构上看,它则是最深层次的容器,ApplicationContext 在最底层组合了 BeanFactory )。FactoryBean :创建对象的⼯⼚ Bean ,可以使⽤它来直接创建⼀些初始化流程⽐较复杂的对象。
3.4 BeanFactory的设计
【接⼝的设计⾓度】从 BeanFactory 的顶层接⼝开始,最基础的 BeanFactory 只具备依赖查的能⼒,下⾯的扩展接⼝分别增加
了 BeanFactory 的层次性、可列举、可配置的特性。
【实现的设计⾓度】BeanFactory 的实现类中,⼤多采⽤ “⽗类控制流程 + ⼦类实现细节” 的⽅式完成
底层的功能逻辑,在⽗类中使⽤⼤量模板⽅法来控制整体的逻辑流程,由⼦类实现这些模板⽅法,完成功能的真正实现。
【特性】BeanFactory 本⾝具备以下基本功能特性:
基础的容器( DL 、DI )
定义了作⽤域的概念( scope )
集成环境配置( Environment )
⽀持多种类型的配置源( Resource 、PropertySource )
层次性的设计( Hierarchical )
完整的⽣命周期控制机制( createBean 定义在 BeanFactory 中⽽不是 ApplicationContext)
⼩伙伴们在理解 BeanFactory 的时候,⼀定要从多⽅位的⾓度出发理解,结合第 14 章的内容理清 BeanFactory 中实现的功能、特性,以及在应⽤中发挥的作⽤。
3.5 ApplicationContext的设计
【接⼝的设计⾓度】ApplicationContext 继承了 BeanFactory 接⼝,它具备 BeanFactory 本⾝的特性;除此之外,ApplicationContext 还继承了多个接⼝,扩展了资源加载解析、消息国际化、事件发布等特性。
【实现的设计⾓度】ApplicationContext 分为 xml 配置⽂件和注解驱动两种不同的驱动实现,它们的实现⽅式与 BeanFactory 相似,也是采⽤ “⽗类控制流程 + ⼦类实现细节” 的⽅式设计。
【扩展特性】ApplicationContext 提供了以下的特性:
⽤于访问应⽤程序组件的 Bean ⼯⼚⽅法,它继承⾃ ListableBeanFactory 。
以通⽤⽅式加载⽂件资源的能⼒,它继承⾃ ResourceLoader 。
能够将事件发布给注册的,它继承⾃ ApplicationEventPublisher 。
解析消息的能⼒,⽀持国际化,它继承⾃ MessageSource 。
从⽗上下⽂继承,在⼦容器中的定义将始终优先。( ApplicationContext 也具有层次性)
同样的,⼩伙伴们理解 ApplicationContext 的时候,不要⼀味地想着 ApplicationContext 就是 BeanFactory 的⼦类扩展,它
与 BeanFactory 的关系是组合,包括继承了其它接⼝后,底层也都是组合这些接⼝对应功能的核⼼ API 。理解了这个设计,在回答 ApplicationContext 的设计和理解时,就容易得多了。
3.6 Environment的设计
Environment 是 SpringFramework 3.1 引⼊的抽象的概念,它包含 profiles 和 properties 的信息,可以实现统⼀的配置存储和注⼊、配置属性的解析等。其中 profiles 实现了⼀种基于模式的环境配置,properties 则应⽤于外部化配置。
理解 Environment ,要先理解 ApplicationContext 、Environment 、BeanFactory 、beans 之间的关系,把这个关系理清楚之后,再按照⾃⼰的理解,解释 Environment 的时候也会更加的容易。
3.7 如何理解BeanDefinitionRegistry
BeanDefinitionRegistry 是维护 BeanDefinition 的注册中⼼,它内部存放了 IOC 容器中 bean 的定义信息,同时 BeanDefinitionRegistry 也是⽀撑其它组件和动态注册 Bean 的重要组件。在 SpringFramework 中,BeanDefinitionRegistry 的实现
是 DefaultListableBeanFactory 。spring ioc注解
重点理解 BeanDefinitionRegistry 针对的⽬标是 BeanDefinition ⽽不是 bean 对象哦!
3.8 对⽐BeanFactory与BeanDefinitionRegistry
BeanFactory :SpringFramework 中实现 IOC 的最底层容器,内部存放了应⽤中注册的 bean 实例。
BeanDefinitionRegistry :BeanDefinition 的注册表,它的维护对象是 BeanDefinition ⽽不是 bean 实例,
在这个问题上,⼩伙伴们⼀定要辩证的去看:虽然最终 DefaultListableBeanFactory 同时实现
了 BeanFactory 与 BeanDefinitionRegistry 两个接⼝,但这不代表 BeanFactory 与 BeanDefinitionRegistry 可以混为⼀谈,它们两个的分⼯是⾮常明确且⾼度分离的。
3.9 BeanFactoryPostProcessor
3.9.1 BeanFactoryPostProcessor的设计
BeanFactoryPostProcessor 是容器的扩展点,它⽤于 IOC 容器的⽣命周期中,所有 BeanDefinition 都注册到 BeanFactory 后回调触发,⽤于访问 / 修改已经存在的 BeanDefinition 。与 BeanPostProcessor 相同,它们都是容器隔离的,不同容器中
的 BeanFactoryPostProcessor 不会相互起作⽤。
关键点:改变原有 bean 的定义信息
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论