可以把 Spring IoC 容器比作一间餐馆,当你来到餐馆,通常会直接招呼服务员:点菜!至于菜的原料是什么?如何用原料把菜做出来?可能你根本就不关心。IoC 容器也是一样,你只需要告诉它需要某个bean,它就把对应的实例(instance)扔给你,至于这个bean是否依赖其他组件,怎样完成它的初始化,根本就不需要你关心。
作为餐馆,想要做出菜肴,得知道菜的原料和菜谱,同样地,IoC 容器想要管理各个业务对象以及它们之间的依赖关系,需要通过某种途径来记录和管理这些信息。BeanDefinition
对象就承担了这个责任:容器中的每一个 bean 都会有一个对应的 BeanDefinition 实例,该实例负责保存bean对象的所有必要信息,包括 bean 对象的 class 类型、是否是抽象类、构造方法和参数、其它属性等等。当客户端向容器请求相应对象时,容器就会通过这些信息为客户端返回一个完整可用的 bean 实例。微信搜索 web_resource 关注后获取更多干货!
原材料已经准备好(把 BeanDefinition 看着原料),开始做菜吧,等等,你还需要一份菜谱,BeanDefinitionRegistry
和BeanFactory
就是这份菜谱,BeanDefinitionRegistry 抽象出 bean 的注册逻辑,而 BeanFactory 则抽象出了 bean 的管理逻辑,而各个 BeanFactory 的实现类就具体承担了 bean 的注册以及管理工作。它们之间的关系就如下图:
DefaultListableBeanFactory
作为一个比较通用的 BeanFactory 实现,它同时也实现了 BeanDefinitionRegistry 接口,因此它就承担了 Bean 的注册管理工作。从图中也可以看出,BeanFactory 接口中主要包含 getBean、containBean、getType、getAliases 等管理 bean 的方法,而 BeanDefinitionRegistry 接口则包含 registerBeanDefinition、removeBeanDefinition、getBeanDefinition 等注册管理 BeanDefinition 的方法。
下面通过一段简单的代码来模拟 BeanFactory 底层是如何工作的:
// 默认容器实现 DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory(); // 根据业务对象构造相应的BeanDefinition AbstractBeanDefinition definition = new RootBeanDefinition(Business.class,true); // 将bean定义注册到容器中 beanRegistry.registerBeanDefinition("beanName",definition); // 如果有多个bean,还可以指定各个bean之间的依赖关系 // ........ // 然后可以从容器中获取这个bean的实例 // 注意:这里的beanRegistry其实实现了BeanFactory接口,所以可以强转, // 单纯的BeanDefinitionRegistry是无法强制转换到BeanFactory类型的 BeanFactory container = (BeanFactory)beanRegistry; Business business = (Business)container.getBean("beanName");
这段代码仅为了说明 BeanFactory 底层的大致工作流程,实际情况会更加复杂,比如 bean 之间的依赖关系可能定义在外部配置文件(XML/Properties)中、也可能是注解方式。Spring IoC 容器的整个工作流程大致可以分为两个阶段