一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 10 天,点击查看活动详情。
月落乌啼霜满天,江枫渔火对愁眠。
1 前言
前文已经讲述了 BeanFactory 和 FactoryBean 的区别,在本文中将继续讲述 BeanFactory 和 ApplicationContext 的区别,这个知识点在面试和工作中已经经常遇到的问题。下图是在 Spring 源码中的 ApplicationContext 的注释。
2 BeanFactory 和 ApplicationContext
BeanFactory 在 Spring 中是最底层的接口,提供了获取 Bean 的方法以及 Bean 生命周期的规范。而 ApplicationContext 则是应用上下文的概念,不仅仅是继承了 BeanFactory 的接口,而且还继承了其它接口,丰富了其实现的功能,是 Spring 中的高级容器。
2.1 装载的区别
BeanFactory 在启动时不会去实例化,只有真正去获取 Bean 对象时才会加载实例化。ApplicationContext 在启动时已经把所有非懒加载的 Bean 全部实例化了。这里说一下延迟实例化和非延迟实例化的区别:
- 1 延迟加载的 Bean 在启动阶段消耗的资源少,缩短项目启动的时间,在使用时再进行实例化,一般应用于对资源要求较高、初始化时间较长的操作。
- 2 非延迟加载所有的 Bean 在启动时都已经进行了加载,系统运行速度加快。在 web 应用中,由于所有的 Bean 都已经加载,在系统启动的时候,能尽早发现系统中的配置。
2.2 ApplicationContext 的功能
ApplicationContext 重要的功能如下所示:
- 1 BeanFactory 接口,这里默认使用的是
DefaultListableBeanFactory
, 用来处理 Bean 的后置处理。 - 2 EventPublish 事件相关的设置,用于发送消息和事件响应。事件机制是发布订阅和观察者模式,容器事件 ApplicationEvent 由 ApplicationContext 发布,并且由 ApplicationListener 进行监听事件进行处理,这里需要说的是事件处理是属于同步操作。
- 3 Environment 接口,用于初始化配置使用,在使用 Nacos、Apollo 等配置中心会起作用。
- 4 MessageSource 国际化相关设置,这项配置一般情况下用不上。
- 5 Resource,获取访问资源,比如在 classpath 路径下的项目配置文件,前端 css js html 等文件。
这里再借助 AnnotationConfigApplicationContext
简单回顾一下 Spring 中容器的知识:
- 1 创建
AnnotationConfigApplicationContext
是会先获取一个工厂DefaultListableBeanFactory
,这里调用的是obtainFreshBeanFactory
方法 。 - 2 获取到工厂后,解析扫描类上的注解并将 Bean 封装成 BeanDefinition 对象,BeanDefinition 封装了 Spring 所有 Bean 的相关定义描述信息
- 3 对 Spring 配置的所有 Bean 进行实例化,根据 BeanDefinition 对象的信息,底层采用反射的手段进行 Bean 的实例化和初始化,如果是代理对象,则需要增强处理。
- 4 将实例化的 Bean 放入 map 中,后续应用程序从该 Map 对象中获取 Bean 对象,该 Map 就称之为 IOC 容器。
3 总结
本文主要讲述了 BeanFactory
和 ApplicationContext
的区别,后者实现了前者的功能,是一个容器的体现,前者只是一个操作 Bean 的接口。虽然两者都是接口,但是后者继承了前者的功能,并组合了其它接口的功能,实现的功能更加丰富。