IoC又叫依赖注入(DI)。它描述了对象的定义和依赖的一个过程,也就是说,依赖的对象通过构造参数、工厂方法参数或者属性注入,当对象实例化后依赖的对象才被创建,当创建bean后容器注入这些依赖对象。这个过程基本上是反向的,因此命名为控制反转(IoC),它通过直接使用构造类来控制实例化,或者定义它们之间的依赖关系,或者类似于服务定位模式的一种机制。
org.springframework.beans 和 org.springframework.context 是Spring框架中IoC容器的基础, BeanFactory 接口提供一种高级的配置机制能够管理任何类型的对象。 ApplicationContext 是 BeanFactory 的子接口。它能更容易集成Spring的AOP功能、消息资源处理(比如在国际化中使用)、事件发布和特定的上下文应用层比如在网站应用中的 WebApplicationContext。
总之, BeanFactory 提供了配置框架和基本方法, ApplicationContext 添加更多的企业特定的功能。 ApplicationContext 是 BeanFactory 的一个子接口,通过解析BeanFactory的源码是了解Spring的IoC容器的一个最佳选择
在Spring中,由Spring IoC容器管理的对象叫做beans。 bean就是由Spring IoC容器实例化、组装和以其他方式管理的对象。此外bean只是你应用中许多对象中的一个。Beans以及他们之间的依赖关系是通过容器配置元数据反映出来。
1.容器概述
org.springframework.context.ApplicationContext 接口代表了Spring Ioc容器,它负责实例化、配置、组装之前的beans。容器通过读取配置元数据获取对象的实例化、配置和组装的描述信息。它配置的0元数据用xml、Java注解或Java代码表示。它允许你表示组成你应用的对象以及这些对象之间丰富的内部依赖关系。
Spring提供几个开箱即用的 ApplicationContext 接口的实现类。在独立应用程序中通常创建一个 ClassPathXmlApplicationContext 或 FileSystemXmlApplicationContext实例对象。虽然XML是用于定义配置元数据的传统格式,你也可以指示容器使用Java注解或代码作为元数据格式,但要通过提供少量XML配置来声明启用对这些附加元数据格式的支持。
在大多数应用场景中,显示用户代码不需要实例化一个或多个Spring IoC容器的实例。比如在web应用场景中,在web.xml中简单的8行(或多点)样板式的xml配置文件就可以搞定(参见第3.15.4节“Web应用程序的便利的ApplicationContext实例
化”)。如果你正在使用Eclipse开发环境中的Spring Tool Suite插件,你只需要鼠标点点或者键盘敲敲就能轻松搞定这几行配置。
下图是Spring如何工作的高级展示。你应用中所有的类都由元数据组装到一起所以当 ApplicationContext 创建和实例化后,你就有了一个完全可配置和可执行的系统或应用。
这里写图片描述
2. BeanFactory
BeanFactory为Spring的IoC功能提供了底层的基础,但是它仅仅被用于和第三方框架的集成,现在对于大部分的Spring用户来说都是历史了。BeanFactory及其相关的接口,例如:BeanFactoryAware,InitializingBean,DisposableBean,在Spring
中仍然有所保留,目的就是为了让大量的第三方框架和Spring集成时保持向后兼容。通常第三方组件不会更加现代的等价物,例如:@PostConstruct 或@PreDestroy,以便可以与JDK1.4兼容,或避免依赖JSR-250。这部分提供了BeanFactory 和 ApplicationContext之间的背景差异以及用户怎样通过查找单例的模式来访问IoC容器。
3.ApplicationContext
正如本章开头所讨论的那样,org.springframework.beans.factory包提供基本的功能来管理和操作bean,包括以编程的方式。The org.springframework.context包增加了ApplicationContext接口,它继承了BeanFactory接口,除了以面向应用框架的风
格扩展接口来提供一些额外的功能。很多人以完全声明的方式使用ApplicationContext,甚至没有以编程的方式去创建它,而是依赖诸如ContextLoader等支持类来自动的实例化ApplicationContext,作为Java EE web应用程序正常启动的一部分。
为了增强BeanFactory在面向框架风格的功能,上下文的包还提供了以下的功能:
- 通过MessageSource接口访问i18n风格的消息
- 通过ResourceLoader接口访问类似URL和文件资源
- 通过ApplicationEventPublisher接口,即bean实现ApplicationListener接口来进行事件发布
- 通过HierarchicalBeanFactory接口实现加载多个(分层)上下文,允许每个上下文只关注特定的层,例如应用中的web层
4.BeanFactory or ApplicationContext?
尽量使用ApplicationContext除非你有更好的理由不用它。因为ApplicationContext包括了BeanFactory的所有功能,通常也优于BeanFactory,除非一些少数的场景,例如:在受资源约束的嵌入式设备上运行一个嵌入式应用,它的内存消耗可能至关重要,并且可能会产生字节。然而,对于大多数典型的企业级应用和系统来说,ApplicationContext才是你想使用的。Spring大量使用了BeanPostProcessor扩展点(以便使用代理等)。如果你仅仅只使用简单的BeanFactory,很多的支持功能将不会有效,例如:事务和AOP,但至少不会有额外的步骤。这可能会比较迷惑,毕竟配置又没有错。
下表列了BeanFactory 和 ApplicationContext接口和实现的一些特性:
功能 / 特点 | BeanFactory | ApplicationContext |
Bean实例化/装配 | 是 | 是 |
BeanPostProcessor自动注册 | 否 | 是 |
BeanFactoryPostProcessor自动注册 | 否 | 是 |
MessageSource便捷访问(针对i18n) | 否 | 是 |
ApplicationEvent 发布 | 否 | 是 |
用BeanFactory的实现来明确的注册一个bean的后置处理器,你需要写和下面类似的代码:
DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); // populate the factory with bean definitions // now register any needed BeanPostProcessor instances MyBeanPostProcessor postProcessor = new MyBeanPostProcessor(); factory.addBeanPostProcessor(postProcessor); // now start using the factory
当使用一个BeanFactory的实现来明确的注册一个BeanFactoryPostProcessor时,你写的代码必须和下面类似:
DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(new FileSystemResource("beans.xml")); // bring in some property values from a Properties file PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); cfg.setLocation(new FileSystemResource("jdbc.properties")); // now actually do the replacement cfg.postProcessBeanFactory(factory);
在这两种情况下,明确的注册步不是很方便,这也就是为什么在大多数支持Spring的应用中,ApplicationContext的各种实现都优于BeanFactory实现的原因之一,特别是当使用BeanFactoryPostProcessors和BeanPostProcessors的时候。这些机制
实现了一些很重要的功能,例如:属性的占位替换和AOP。
5.总结
上面简单介绍了下IoC容器,BeanFactory和ApplicationContext,其中BeanFactory是IoC容器的基础,ApplicationContext是对BeanFactory的扩展,所以接下来我们以BeanFactory为入口,进行SpringIoC的分析...
附: Spring5的官方文档