设计模式(二十九)----综合应用-自定义Spring框架-Spring IOC相关接口分析
1 BeanFactory解析
Spring中Bean的创建是典型的工厂模式,这一系列的Bean工厂,即IoC容器,为开发者管理对象之间的依赖关系提供了很多便利和基础服务,在Spring中有许多IoC容器的实现供用户选择,其相互关系如下图所示。

其中,BeanFactory作为最顶层的一个接口,定义了IoC容器的基本功能规范,BeanFactory有三个重要的子接口:ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory。但是从类图中我们可以发现最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口。
那么为何要定义这么多层次的接口呢?
每个接口都有它的使用场合,主要是为了区分在Spring内部操作过程中对象的传递和转化,对对象的数据访问所做的限制。例如,
- ListableBeanFactory接口表示这些Bean可列表化。 
- HierarchicalBeanFactory表示这些Bean 是有继承关系的,也就是每个 Bean 可能有父 Bean 
- AutowireCapableBeanFactory 接口定义Bean的自动装配规则。 
这三个接口共同定义了Bean的集合、Bean之间的关系及Bean行为。最基本的IoC容器接口是BeanFactory,来看一下它的源码:
public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";
    //根据bean的名称获取IOC容器中的的bean对象
    Object getBean(String name) throws BeansException;
    //根据bean的名称获取IOC容器中的的bean对象,并指定获取到的bean对象的类型,这样我们使用时就不需要进行类型强转了
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
    //判断容器中是否包含指定名称的bean对象
    boolean containsBean(String name);
    //根据bean的名称判断是否是单例
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    String[] getAliases(String name);
}在BeanFactory里只对IoC容器的基本行为做了定义,根本不关心你的Bean是如何定义及怎样加载的。正如我们只关心能从工厂里得到什么产品,不关心工厂是怎么生产这些产品的。
BeanFactory有一个很重要的子接口,就是ApplicationContext接口,该接口主要来规范容器中的bean对象是非延时加载,即在创建容器对象的时候就对象bean进行初始化,并存储到一个容器中。

要知道工厂是如何产生对象的,我们需要看具体的IoC容器实现,Spring提供了许多IoC容器实现,比如:
- ClasspathXmlApplicationContext : 根据类路径加载xml配置文件,并创建IOC容器对象。 
- FileSystemXmlApplicationContext :根据系统路径加载xml配置文件,并创建IOC容器对象。 
- AnnotationConfigApplicationContext :加载注解类配置,并创建IOC容器。 
2 BeanDefinition解析
Spring IoC容器管理我们定义的各种Bean对象及其相互关系,而Bean对象在Spring实现中是以BeanDefinition来描述的,如下面配置文件
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
bean标签还有很多属性:
    scope、init-method、destory-method等。其继承体系如下图所示。

3 BeanDefinitionReader解析
Bean的解析过程非常复杂,功能被分得很细,因为这里需要被扩展的地方很多,必须保证足够的灵活性,以应对可能的变化。Bean的解析主要就是对Spring配置文件的解析。这个解析过程主要通过BeanDefinitionReader来完成,看看Spring中BeanDefinitionReader的类结构图,如下图所示。

看看BeanDefinitionReader接口定义的功能来理解它具体的作用:
public interface BeanDefinitionReader {
    //获取BeanDefinitionRegistry注册器对象
    BeanDefinitionRegistry getRegistry();
    @Nullable
    ResourceLoader getResourceLoader();
    @Nullable
    ClassLoader getBeanClassLoader();
    BeanNameGenerator getBeanNameGenerator();
    /*
        下面的loadBeanDefinitions都是加载bean定义,从指定的资源中
    */
    int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
    int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
    int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
    int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}4 BeanDefinitionRegistry解析
BeanDefinitionReader用来解析bean定义,并封装BeanDefinition对象,而我们定义的配置文件中定义了很多bean标签,所以就有一个问题,解析的BeanDefinition对象存储到哪儿?答案就是BeanDefinition的注册中心,而该注册中心顶层接口就是BeanDefinitionRegistry。
public interface BeanDefinitionRegistry extends AliasRegistry {
    //往注册表中注册bean
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;
    //从注册表中删除指定名称的bean
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    //获取注册表中指定名称的bean
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    
    //判断注册表中是否已经注册了指定名称的bean
    boolean containsBeanDefinition(String beanName);
    
    //获取注册表中所有的bean的名称
    String[] getBeanDefinitionNames();
    
    int getBeanDefinitionCount();
    boolean isBeanNameInUse(String beanName);
}继承结构图如下:

从上面类图可以看到BeanDefinitionRegistry接口的子实现类主要有以下几个:
- DefaultListableBeanFactory - 在该类中定义了如下代码,就是用来注册bean - private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
- SimpleBeanDefinitionRegistry - 在该类中定义了如下代码,就是用来注册bean - private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);
5 创建容器
ClassPathXmlApplicationContext对Bean配置资源的载入是从refresh()方法开始的。refresh()方法是一个模板方法,规定了 IoC 容器的启动流程,有些逻辑要交给其子类实现。它对 Bean 配置资源进行载入,ClassPathXmlApplicationContext通过调用其父类AbstractApplicationContext的refresh()方法启动整个IoC容器对Bean定义的载入过程。
设计模式(二十九)----综合应用-自定义Spring框架-Spring IOC相关接口分析的更多相关文章
- 解释器模式 Interpreter 行为型 设计模式(十九)
		解释器模式(Interpreter) 考虑上图中计算器的例子 设计可以用于计算加减运算(简单起见,省略乘除),你会怎么做? 你可能会定义一个工具类,工具类中有N多静态方法 比如定义了两个 ... 
- 【黑金原创教程】【FPGA那些事儿-驱动篇I 】原创教程连载导读【连载完成,共二十九章】
		前言: 无数昼夜的来回轮替以后,这本<驱动篇I>终于编辑完毕了,笔者真的感动到连鼻涕也流下来.所谓驱动就是认识硬件,还有前期建模.虽然<驱动篇I>的硬件都是我们熟悉的老友记,例 ... 
- FreeSql (二十九)Lambda 表达式
		FreeSql 支持功能丰富的表达式函数解析,方便程序员在不了解数据库函数的情况下编写代码.这是 FreeSql 非常特色的功能之一,深入细化函数解析尽量做到满意,所支持的类型基本都可以使用对应的表达 ... 
- 使用Typescript重构axios(二十九)——添加baseURL
		0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ... 
- Bootstrap <基础二十九>面板(Panels)
		Bootstrap 面板(Panels).面板组件用于把 DOM 组件插入到一个盒子中.创建一个基本的面板,只需要向 <div> 元素添加 class .panel 和 class .pa ... 
- Web 开发人员和设计师必读文章推荐【系列二十九】
		<Web 前端开发精华文章推荐>2014年第8期(总第29期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ... 
- 设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)
		设计模式 ( 二十 ) 访问者模式Visitor(对象行为型) 1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象, ... 
- WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载]
		原文:WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载] 我们有两种典型的WCF调用方式:通过SvcUtil.exe(或者添加Web引用)导入发布的服务元数据生成服务代理相关的代码 ... 
- VMwarevSphere 服务器虚拟化之二十九 桌面虚拟化之安装View副本服务器
		VMwarevSphere 服务器虚拟化之二十九 桌面虚拟化之安装View副本服务器 VMware View中高可用性可是一个必须要考虑的问题.在整个虚拟桌面环境中View Connection S ... 
- Bootstrap入门(二十九)JS插件6:弹出框
		Bootstrap入门(二十九)JS插件6:弹出框 加入小覆盖的内容,像在iPad上,用于存放非主要信息 弹出框是依赖于工具提示插件的,那它也和工具提示是一样的,是需要初始化才能够使用的 首先我们引入 ... 
随机推荐
- 导航条透明,ios11系统,会出现偏移64的问题
			在当前页面加入下面方法 - (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self.navigation ... 
- javase我的笔记
			学习java编程 |--需要遵循其语法规范 |--在其开发环境下编程 准备开发java环境 |--安装jdk |--配置jdk jdk:含义是java提供的一套开发工具,包含jre\编译器等 |--编 ... 
- 【LeetCode】——分割回文串II
			继续与动态规划斗智斗勇... 132. 分割回文串 II - 力扣(LeetCode) (leetcode-cn.com) 分析:记f[i]表示将字符串s[0:i]分割的最小次数.我们需要将列举出在[ ... 
- #Python #OpenCV 使用Python为你的圣诞节增添更多乐趣
			 目录 1.前言 2.目标与效果展示 3.下载OpenCV图形识别库 4.下载python支持的v2模块 5.图片素材 6.代码 1.前言  编辑 Merry Christmas!今天是2022 ... 
- vue、react配置gzip打包后,删除源文件deleteOriginalAssets: true,nginx需要的配置
			1.删除源文件后,配置了gzip,当配置gzip删除源文件后,解决前端history问题,就会出现所有的都返回html,请求js.css也会返回html,页面会报错,如下配置即可 location / ... 
- 2022竞赛新方法学习1--学习Proceedings of SAT Competition 2022 : Solver and Benchmark Descriptions
			Proceedings of SAT Competition 2022 : Solver and Benchmark Descriptions https://helda.helsinki.fi/ha ... 
- nodejs路由
			Router与route: Route是一条路由: 如:/users - - > 调用 getAllUsers()函数 /users/count/ - - > 调用 getUsersCou ... 
- qtconsole和jupyter-notebook的对应启动命令行配置
			jupyter-notebook: set conda_path=D:\use\program\Miniconda3 pushd %conda_path% call Scripts\activate. ... 
- 针对“RuntimeError: each element in list of batch should be of equal size” 问题解决
			第一次运行代码出现了这个问题: 这个问题的出现主要来源于DataLoader类中的collate.py文件造成的问题,由于每个batch里的长度不一致,因此导致出现了该问题. 通过百度方法和查看源码去 ... 
- setter注入--简单类型
			UserDaoImpl中的代码,实现对name和age的注入 private String name; private int age; public void setName(String name ... 
