面试官问Spring的容器是什么?你这么回答他

创作内容丰富的干货文章很费心力,感谢点过此文章的读者,点一个关注鼓励一下作者,激励他分享更多的精彩好文,谢谢大家!


BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。


依赖关系

BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。
ApplicationContext接口作为BeanFactory的派生类,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:

  • 继承MessageSource,因此支持国际化。
  • 统一的资源文件访问方式。
  • 提供在监听器中注册bean的事件。
  • 同时加载多个配置文件。
  • 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
加载方式


BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次调用getBean方法才会抛出异常。
ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。


创建方式


BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用
ContextLoader。


注册方式


BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。

Spring 如何设计容器的,BeanFactory和ApplicationContext的关系详解


Spring 作者 Rod Johnson 设计了两个接口用以表示容器。

  • BeanFactory
  • ApplicationContext

BeanFactory 简单粗暴,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”。
ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具备了更多的功能。例如资源的获取,支持多种消息(例如 JSP tag 的支持),对
BeanFactory 多了工具级别的支持等待。所以你看他的名字,已经不是 BeanFactory 之类的工厂了,而是 “应用上下文”, 代表着整个大容器的所有功能。该接口定义了一个 refresh 方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的bean。
当然,除了这两个大接口,还有其他的辅助接口,这里就不介绍他们了。

BeanFactory和ApplicationContext的关系

为了更直观的展示 “低级容器” 和 “高级容器” 的关系,这里通过常用的
ClassPathXmlApplicationContext 类来展示整个容器的层级 UML 关系。

有点复杂? 先不要慌,我来解释一下。
最上面的是 BeanFactory,下面的 3 个绿色的,都是功能扩展接口,这里就不展开讲。
看下面的隶属 ApplicationContext 粉红色的 “高级容器”,依赖着 “低级容器”,这里说的是依赖,不是继承哦。他依赖着 “低级容器” 的 getBean 功能。而高级容器有更多的功能:支持不同的信息源头,可以访问文件资源,支持应用事件(Observer 模式)。
通常用户看到的就是 “高级容器”。 但 BeanFactory 也非常够用啦!
左边灰色区域的是 “低级容器”, 只负载加载 Bean,获取 Bean。容器其他的高级功能是没有的。例如上图画的 refresh 刷新 Bean 工厂所有配置,生命周期事件回调等。


小结

说了这么多,不知道你有没有理解Spring IoC? 这里小结一下:IoC 在 Spring 里,只需要低级容器就可以实现,2 个步骤:

  1. 加载配置文件,解析成 BeanDefinition 放在 Map 里。
  2. 调用 getBean 的时候,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,如果有依赖关系,将递归调用 getBean 方法,完成依赖注入。

上面就是 Spring 低级容器(BeanFactory)的 IoC。至于高级容器 ApplicationContext,他包含了低级容器的功能,当他执行 refresh 模板方法的时候,将刷新整个容器的 Bean。同时其作为高级容器,包含了太多的功能。一句话,他不仅仅是 IoC。他支持不同信息源头,支持 BeanFactory 工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等。

### 回答1: Spring通过依赖注入的方式来解决循环依赖题,在创建bean的同时进行属性的注入,从而避免了循环依赖的情况。当Spring在创建bean的过程中出现循环依赖时,它会将尚未创建完成的bean对象提前暴露给Spring容器Spring容器在完成对所有bean的创建后,会利用这些提前暴露的bean对象来完成循环依赖的注入。 ### 回答2: 在面试过程中,当面试官到如何解决Spring中的循环依赖题,有效的回答应该包括以下几点。 首先,要明确循环依赖是指两个或多个Bean之间互相依赖,形成一个循环链,无法确定依赖关系的题。Spring为了解决这个题,采用了三级缓存(bean map)的方式。 其次,可以提到Spring的处理循环依赖是通过"提前暴露半成品实例"的方式来实现的。Spring容器在初始化装配Bean的过程中,首先创建Bean的实例,但不进行属性填充,在这个过程中,Spring会将刚刚创建的Bean实例进行缓存。然后,Spring继续对其他Bean进行创建,当创建到有对其他Bean的依赖注入时,Spring会检测到循环依赖的情况,然后从缓存中提取半成品实例,即已经存在的Bean实例,完成对依赖的注入,最终完成装配。 再次,可以提及Spring在解决循环依赖时使用了"构造器注入"和"属性注入"的方式。在存在循环依赖的情况下,采用构造器注入可以在Bean创建时就解决循环依赖题,而属性注入则需要在Bean的创建之后再进行依赖注入。 最后,需要指出Spring的循环依赖处理能力是有限的,并不适用于所有情况。如果循环依赖的链过长或存在复杂的依赖关系,容易导致死锁或循环等待的题。因此,在设计应用程序时,尽量避免循环依赖的产生,减少耦合度,提高系统的可维护性和扩展性。 综上所述,当面试官Spring如何解决循环依赖题时,回答者可以通过解释Spring采用的三级缓存和"提前暴露半成品实例"的方式、使用构造器注入和属性注入的方式以及指出其局限性来回答这个题。 ### 回答3: 面试的过程中,如果面试官Spring如何解决循环依赖的题,我可以这样回答: 首先,循环依赖是指两个或多个Bean之间相互依赖,形成了一个环状的依赖关系。例如,Bean A依赖于Bean B,而Bean B又依赖于Bean A。 在Spring中,解决循环依赖通常有两种方式。 首先是通过构造器注入来解决循环依赖。构造器注入是指在Bean实例化时通过构造器完成依赖注入。在这种情况下,Spring会检测到循环依赖并抛出一个异常,阻止Bean的创建。但是,如果我想要解决这个题,可以使用@Lazy注解来延迟Bean的实例化。通过延迟实例化,Spring能够在构建对象时避免产生循环依赖。 另一种方式是使用Setter方法注入来解决循环依赖。Setter方法注入是指在Bean实例化后,通过Setter方法完成依赖注入。在这种情况下,Spring允许先创建一个空的Bean对象,再通过使用Setter方法设置依赖关系。这种方式下,Spring能够在构建对象的时候完成所有的依赖注入。 总结来说,Spring通过使用构造器注入和Setter方法注入的方式来解决循环依赖的题。无论是采用哪种方式,我们都需要注意避免出现过多复杂的循环依赖关系,因为这可能会导致代码难以维护和理解。同时,需要确保Bean的依赖关系在整个应用程序中是清晰可见的,以便更好地管理和调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏日彩虹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值