阅读 Spring 源码,BeanFactory 是避不了的存在。而大家常见的使用场景,也是以下形式:

ConfigurableApplicationContext ctx = SpringApplication.run(xxx.class);
BeanFactory beanFactory = (BeanFactory) ctx;
beanFactory.getBean(xxx);

但 BeanFactory 可不是如此枯燥无味的。

前置知识

  1. Spring 的 IOC 特性的核心就是: Bean容器,也叫 Bean工厂 —— 存储 bean 的工厂,负责 bean 的加入、实例化、初始化、监控与删除操作。
  2. 我们知道,使用 Spring 前,我们需要在 XML 或 Annotation 中配置 bean,这样 Spring 在启动时,通过加载指定的配置文件或配置类,就能够往容器中存入相应的 bean 实例。而这些在配置文件/类中的定义,称为 Bean定义,在 Spring 中使用 BeanDefinition 进行封装。
  3. Bean定义所在的配置文件/配置类,我们称为配置源,Spring 支持不同的配置源,有:XML、Annotation、Groovy 甚至 Property。
  4. 读取不同的配置源,有不同的读取器,如:读取 XML 的有 XmlBeanDefinitionReader,读取 Property 的有 PropertiesBeanDefinitionReader,读取 Annotation 的有:AnnotatedBeanDefinitionReader。
  5. Annotation 是在 Java5 之后引入的,所以初期 Spring 以读取指定配置源来收集 Bean定义;在 Spring 支持注解之后,配置源由配置文件转变为 Class。所以,AnnotatedBeanDefinitionReader 与 XmlBeanDefinitionReader 并没有继承自统一父类,但他们属于相同的模块概念。

BeanFactory

在 Spring 中 BeanFactory 接口的定义非常简单,主要有以下方法:

<T> T getBean(Class<T> requiredType) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
// ...其他

只负责获取、判断操作。

然而,仅仅这些方法并不满足多功能 BeanFactory 的需求,所以 BeanFactory 有以下三个不同特性的子类:

ListableBeanFactory
HierarchicalBeanFactory
AutowireCapableBeanFactory
  • ListableBeanFactory:此子接口要求实现者具被枚举/索引/检索功能,从而避免需要通过 beanName 一个个迭代进行查找,我们很快就能想到 Map 结构。同时,此接口定义的方法,要求能够关注到预加载的BeanDefinition(即 Bean 定义)。
String[] getBeanDefinitionNames();
boolean containsBeanDefinition(String beanName);
<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) throws NoSuchBeanDefinitionException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit);
  • HierarchicalBeanFactory:此类见名知意,是个具有层级结构的 BeanFactory,它提供的方法,也只有以下两个:获取父工厂及判断当前工厂是否包含指定 Bean。
BeanFactory getParentBeanFactory();
boolean containsLocalBean(String name);
  • AutowireCapableBeanFactory:此类是 Spring 提供的,用以支持 Bean 自动装配、注入、填充的工厂,也就是说 Bean 的实例化在此工厂中(常见的 Bean 的实例化的过程在此工厂中完成,定义了相关的 API)
<T> T createBean(Class<T> beanClass) throws BeansException;    // 创建
void autowireBean(Object existingBean) throws BeansException; // 自动装配
Object initializeBean(Object existingBean, String beanName) throws BeansException; // 初始化
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) BeansException; // 过程回调
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException; // 过程回调
void destroyBean(Object existingBean); // 销毁

乍一看,发现 BeanFactory 丰富了很多,与 BeanDefinition 也有了关联,可仔细一看,就会发现,这些接口定义的都是获取或判断方法,与 BeanFactory 类似;而且都是与 Bean 有紧密联系。在此之外,Spring 提供了 BeanFactory 的相关控制选项的配置接口

Spring 首先提供了一个 HierarchicalBeanFactory 的子类:ConfigurableBeanFactory。它定义了 BeanFactory 的一些相关配置入口,同时也定义了 HierarchicalBeanFactory#getParentBeanFactory 的parent设置入口,总的来说,它是 BeanFactory 配置的相关类(定义了配置的设置与获取),比如有:Scope 的注册、类型转换器列表的持有,后置处理器的新增等等,

void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;    // 设置父工厂
void setBeanClassLoader(@Nullable ClassLoader beanClassLoader); // 设置 Bean 的 ClassLoader
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor); // 添加 BeanPostProcessor
void registerScope(String scopeName, Scope scope); // 注册 Scope
Scope getRegisteredScope(String scopeName); // 从 BeanFactory 获取配置的 Scope 信息
BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; // 获取合并后的 BeanDefinition

工厂相关的配置有了。Spring 又在此基础上,扩展了一个新的子工厂类型:ConfigurableListableBeanFactory,它的继承关系如下:

此接口继承了所有 BeanFactory 相关的主要接口类型,具备了上述提及的工厂的所有功能,现在这个类型是“有闲有钱”,我们来看看它定义了哪些新方法:

void ignoreDependencyInterface(Class<?> ifc);    // 忽略依赖接口,如:Aware 类接口
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; // 获取Bean定义(只获取当前Bean内的定义,不考虑层级)
boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException; // 是否支持自动注入
void freezeConfiguration(); // 冻结配置,Bean定义不再支持修改(修改意味着要重新生成Bean实例)
void preInstantiateSingletons() throws BeansException; // 与实例化所有单例

因为继承了自动配置工厂(AutowireCapableBeanFactory),因此具备自动装配Bean能力。同时自己在此基础上,定义了一层外部控制,如:isAutowireCandidate、freezeConfiguration,更重要的是:preInstantiateSingletons。

毕竟它现在掌握了资源:具备检索Bean定义、具备自动装配控制、具备Bean工厂配置,因此它有能力作为实例化单例的入口。

除了继承主要的 Bean工厂类型,此接口还继承了 SingletonBeanRegistry。此接口与其他接口没有任何关联,却与 Spring IOC 特性息息相关。

我们知道,Spring 容器中的 Bean 具备多种 Scope 范围,我们常见的是 Singleton、Prototype。但通过以上工厂定义,我们看到的只有 getBean 操作,而没有 getSingleton。也就是说:Spring 的顶层 BeanFactory 关注的的确只有 IOC(即控制反转),而不关注容器内是单例还是原型。要想通过 BeanFactory 来获知实例范围信息,只能通过其方法:isSingletonisPrototype。没错,就是这么纯粹。

因为单例模型在Spring中也是举足轻重,所以 Spring 划分了单独的概念:SingletonBeanRegistry

它的方法有:

void registerSingleton(String beanName, Object singletonObject);    // 注册单例(不一定要通过Bean定义构建)
Object getSingleton(String beanName); // 获取单例
boolean containsSingleton(String beanName); // 判断是否包含单例
String[] getSingletonNames(); // 获取所有单例名称
int getSingletonCount(); // 获取单例数

具备了单例的注册与获取。

当然,除非明确指定 bean 非单例,否则,在 Spring 中默认解析 Bean定义后注册到容器中,都是使用:registerSingleton,即默认注册单例类型。

以上结果,构建了一个功能丰富且完善的 Bean工厂,具有

  • Bean工厂 配置
  • BeanDefinition 索引获取
  • 触发实例化 Bean
  • Bean实例化与填充、初始化
  • Bean构建时回调
  • Bean实例索引获取
  • Bean销毁
  • 上溯获取父工厂

每个 Bean工厂都有相应的 Abstract实现,最终由子类:DefaultListableBeanFactory 完成统一大业,并被 ApplicationContext 使用

Bean 的构建基于 Bean定义,它从何而来?

Spring 为 BeanDefinition 定义了抽象 BeanDefinitionRegistry,具有以下方法:

void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
boolean containsBeanDefinition(String beanName);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
boolean isBeanNameInUse(String beanName);

具备 Bean定义的注册、移除、获取、判断等,并由 DefaultListableBeanFactory 进行实现。所以 DefaultListableBeanFactory 作为 Spring 的核心类 ApplicationContext 的内定工厂,实现如下:

总结:

  1. 了解了 BeanFactory 的继承体系之后,你能够很快地回忆起相关的知识点,比如:

    • Bean的实例化过程,那一定是在 AutowireCapableBeanFactory 中,而且默认实现就是抽象类:AbstractAutowireCapableBeanFactory
    • Bean工厂具有层级概念,当前 Bean工厂获取不到相应信息时(Bean实例、Bean定义等),可上溯父工厂获取;
  2. 如何较好地记忆 BeanFactory 相关知识点,可通过功能、命名等方面入手,如:

  3. 回顾源码,你会看到如下代码

只有相应的接口实现,才具备对应的 API 进行设置与获取。

以上是 Bean工厂的相关学习与总结,如果错漏,欢迎指正。

【Spring浅析】一、 BeanFactory 有啥可说的?的更多相关文章

  1. 转:Spring系列之beanFactory与ApplicationContext

    原文地址:Spring系列之beanFactory与ApplicationContext 一.BeanFactoryBeanFactory 是 Spring 的“心脏”.它就是 Spring IoC ...

  2. spring 简单实现BeanFactory(转)

    原文地址: http://blog.csdn.net/mlc1218559742/article/details/52776160 有没有发现上面的代码与利用反射实现工厂模式的代码很相似.对,你没有看 ...

  3. 44、[源码]-Spring容器创建-BeanFactory预准备

    44.[源码]-Spring容器创建-BeanFactory预准备 @Override public void refresh() throws BeansException, IllegalStat ...

  4. Spring中的BeanFactory与FactoryBean看这一篇就够了

    前言 理解FactoryBean是非常非常有必要的,因为在Spring中FactoryBean最为典型的一个应用就是用来创建AOP的代理对象,不仅如此,而且对理解Mybatis核心源码也非常有帮助!如 ...

  5. Spring系列之beanFactory与ApplicationContext

    一.BeanFactoryBeanFactory 是 Spring 的“心脏”.它就是 Spring IoC 容器的真面目.Spring 使用 BeanFactory 来实例化.配置和管理 Bean. ...

  6. [原创]java WEB学习笔记98:Spring学习---Spring Bean配置及相关细节:如何在配置bean,Spring容器(BeanFactory,ApplicationContext),如何获取bean,属性赋值(属性注入,构造器注入),配置bean细节(字面值,包含特殊字符,引用bean,null值,集合属性list map propert),util 和p 命名空间

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  7. 深入剖析 Spring 框架的 BeanFactory

    说到Spring框架,人们往往大谈特谈一些似乎高逼格的东西,比如依赖注入,控制反转,面向切面等等.但是却忘记了最基本的一点,Spring的本质是一个bean工厂(beanFactory)或者说bean ...

  8. spring中的BeanFactory与ApplicationContext的作用和区别?

    BeanFactory类关系继承图 1. BeanFactory类结构体系: BeanFactory接口及其子类定义了Spring IoC容器体系结构,由于BeanFactory体系非常的庞大和复杂, ...

  9. Spring学习笔记——Spring中的BeanFactory与FactoryBean

    BeanFactory BeanFactory是Spring的org.springframework.beans.factory下的一个接口,是Spring IOC所遵守的基本编程规范.他的实现类有D ...

随机推荐

  1. 前端生成分享海报兼容H5和小程序

    ### 移动端分享海报生成 最近做项目需求是生成商品分享海报,并且保存到手机中要兼容H5和小程序<br> 与后端同学沟通后,海报在前端生成最省性能和有较好的交互体验,先看做好的效果

  2. J. Cole 的 InnoDB 系列 - 1. 学习 InnoDB - 深入探索核心原理之旅

    原文地址:https://blog.jcole.us/2013/01/02/on-learning-innodb-a-journey-to-the-core/,本系列翻译会在其基础上扩展一些 MySQ ...

  3. 在ASP.NET Core中用HttpClient(四)——提高性能和优化内存

    到目前为止,我们一直在使用字符串创建请求体,并读取响应的内容.但是我们可以通过使用流提高性能和优化内存.因此,在本文中,我们将学习如何在请求和响应中使用HttpClient流. 什么是流 流是以文件. ...

  4. sqli-labs系列——第五关

    less5 更改id后无果,不能用union联合查询 此处用报错注入 报错注入的概念:(1). 通过floor报错 and (select 1 from (select count(*),concat ...

  5. SSH&SSM

    SSH和SSM的区别 SSH是Spring+Struts+Hibernate的缩写,是一种Web应用程序开源框架.框架系统分为四层:表选层.业务逻辑层.数据持久层和模块层.SSM是Spring+Spr ...

  6. electron踩坑系列之一

    前言 以electron作为基础框架,已经开发两个项目了.第一个项目,我主要负责用react写页面,第二项目既负责electron部分+UI部分. 做项目,就是踩坑, 一路做项目,一路踩坑,坑多不可怕 ...

  7. 第24 章 : Kubernetes API 编程利器:Operator 和 Operator Framework

    Kubernetes API 编程利器:Operator 和 Operator Framework 本节课程主要分享以下三方面的内容: operator 概述 operator framework 实 ...

  8. Java利用线程工厂监控线程池

    目录 ThreadFactory 监控线程池 扩展线程池 扩展线程池示例 优化线程池大小 线程池死锁 线程池异常信息捕获 ThreadFactory 线程池中的线程从哪里来呢?就是ThreadFoct ...

  9. 201871010130-周学铭 实验二 个人项目—D{0-1}问题项目报告

    项目 内容 课程班级博客链接 18级卓越班 这个作业要求链接 实验二 软件工程个人项目 我的课程学习目标 掌握软件项目个人开发流程.掌握Github发布软件项目的操作方法. 这个作业在哪些方面帮助我实 ...

  10. Windows Server 2016不小心卸载了.NET Framwork4.6后服务器管理器等功能都不能用的解决方案

    之前卸载IIS的时候手贱把.NET FrameWork 4.6给卸载了,下面有一个比较简单的恢复方法. 可以尝试一下通过cmd命令DISM启用.NET 4.6:1. 首先运行如下命令查看当前的功能安装 ...