设计模式(二十九)----综合应用-自定义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上,用于存放非主要信息 弹出框是依赖于工具提示插件的,那它也和工具提示是一样的,是需要初始化才能够使用的 首先我们引入 ...
随机推荐
- VirtualBox_Ubuntu22.10_Terminal无法打开
https://blog.csdn.net/weixin_43959807/article/details/128872860
- vim多行缩进
1.首先设置vim缩进空格 vim /etc/vim/vimrc 或者vim /etc/vimrc,添加一下文字 set smartindent set shiftwidth=4 # 缩进四个空格 # ...
- [jmeter的使用]jmeter上传文件接口的写法
1.类型和参数名称,依据接口/抓的包决定 2.必须选择java否则报错 3.http header也要写
- C++运算符重载引用传参与返回引用的小小心得
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 //平面向量类,提供完成向量运算和比较的API 6 //除递增运算符和左移运 ...
- Shell 更多结构化命令(流程控制)
更多的结构化命令 上一章里,你看到了如何通过检查命令的输出和变量的值来改变 shell 脚本程序的流程.本章会继续介绍能够控制 shell 脚本流程的结构化命令.你会了解如何重复一些过程和命令,也就是 ...
- Linux 配置nginx 代理tomcat,配置ssl
我就直接干活不废话: 配置文件nginx, nginx.conf #user nobody;worker_processes 1; #error_log logs/error.log;#error_l ...
- java15配置环境后java_version无反应(不显示“不是内部或外部命令”)
重新装了jdk15来使用eclipse 配置完环境变量之后打开cmd输入 java -version 好家伙,居然一点反映都没有, 然后傻乎乎的跑回去重新配置JAVA_HOME和path 还是没用,细 ...
- golang sync.WaitGroup错误使用导致死锁以及noCopy结构体介绍
背景 项目中遇到死锁,使用搜索引擎搜索goroutine堆栈中出现的"sync.runtime_Semacquire deadlock"时,搜到一篇说sync.WaitGroup死 ...
- apt-get install 出现could not open lock file /var/lib/dpkg/lock错误问题
apt-get install 经常出现 could not open lock file /var/lib/dpkg/lock -open 错误问题 一种解决办法 1.切换到root用户 su ~ ...
- density plot
FIN=read.table("/Users/zhongyuantian/macshare/workSpace2021/1.TFY/1.3.TFY20201215/1.3.1.TFY1C_T ...