Spring源码解析 - AbstractBeanFactory 实现接口与父类分析
我们先来看类图吧:
除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegistry和SingletonBeanRegistry接口.
这边主要提供了这样的三个功能: 别名管理,单例创建与注册,工厂方法FactoryBean支持.
我们来看看这些接口,类的主要职责吧:
BeanFactory Spring IOC容器的根接口
-- HierachicalBeanFactory 实现容器的继承,就是可以有父 BeanFactory
-- -- ConfigureabelBeanFactory 提供factory的配置功能
AliasRegistry 定义bean name的别名管理
-- SimpleAliasRegistry 在实现别名管理接口基础上,添加一个canonicalName查找类真是名称api
SingletonBeanRegistry 提供单例注册,查询服务
-- DefaultSingletonBeanRegistry 实现单例与DisposableBean的生命周期管理(创建,维护,销毁)
-- -- FactoryBeanRegistrySupport 添加工厂方式创建类FactoryBean的支持
-- -- -- AbstractBeanFactory BeanFactory的抽象实现.
也就是说这边可以分为这样几类职责:
a, 类别名管理
b, 单例生命周期管理
c, 工厂方法初始化类对应的FactoryBean
d, BeanFactory容器
BeanFactory容器的职责(BeanFactory,HierachicalBeanFactory,ConfigureableBeanFactory)在上一篇文章<Spring源码解析 - BeanFactory接口体系解读>里已经分析过,有兴趣可以看下.
我们今天主要分析其他的三个职责,如下的接口与类(顺便做目录):
1. AliasRegistry 定义bean name的别名管理
2. SimpleAliasRegistry 实现别名管理接口
3. SingletonBeanRegistry 提供单例注册,查询服务
4. DefaultSingletonBeanRegistry 实现单例与DisposableBean的生命周期管理(创建,维护,销毁)
5. FactoryBeanRegistrySupport 添加工厂方式创建类FactoryBean的支持
1. AliasRegistry 定义bean name的别名管理
提供别名的注册,查找,删除,判断定义.
看个类图就行,不用展开.
2. SimpleAliasRegistry 实现别名管理接口
这边除了实现接口定义的api,还添加了两个公共api:
批量校验别名public void resolveAliases(StringValueResolver valueResolver)和查找别名对应的原始类名public String canonicalName(String name)
这边以别名为key缓存数据.
/** Map from alias to canonical name */
private final Map<String, String> aliasMap = new ConcurrentHashMap<String, String>(16);
分析下api实现逻辑吧:
2.1 别名注册 registerAlias(String name, String alias)
2.2 删除别名public void removeAlias(String alias)
校验下,如果别名不存在报错:throw new IllegalStateException("No alias '" + alias + "' registered");
2.3 判断别名是否存在
直接使用ConcurrentHashMap的containsKey
2.4 获取别名public String[] getAliases(String name)
主要逻辑是加了个锁,然后是递归调用retrieveAliases,查找多层次的别名(就是查找别名的别名这些下去)
2.5 使用StringValueResolver解析类名,别名后,进行循环依赖的校验
这边使用的是StringValueResolver的接口,具体实现需要靠注入
3. SingletonBeanRegistry 提供单例注册,查询服务
这边定义的单例注册,有点门道,主要就是相对BeanFactory的api而言有点low,没有做附加的处理.
注册的时候不管注入afterPropertiesSet的初始化回调.
查找的时候不管还没初始化的单例不说,还不管别名问题,不管FactoryBean如何区分是获取FactoryBean本身还是getObject初始化的实例.
咱们一个个api分析吧.
3.1 注册单例 void registerSingleton(String beanName, Object singletonObject);
这边的实现不会再调用 初始化回调函数,如InitializingBean 的afterPropertiesSet,所以这边应该接收的是完成初始化的实例
同理也不会调用销毁的回调,如DisposableBean的destroy
这跟标准的BeanFactory中注册单例是明显不同的,因为那边是会调用各种回调.
3.2 查找单例 Object getSingleton(String beanName);
String[] getSingletonNames();
int getSingletonCount();
设计于访问手动注册的单例.
这边只会查找已经初始化完毕 的单例,有bean definition但没有实例化的这边查找不到.
这边也不会处理FactoryBean的情况(就是具体获取getObject还是factoryBean本身的区分,&),别名也需要预先转化好了来查.
3.3 判断是否保护单例 boolean containsSingleton(String beanName);
只有单例已经实例化才会返回true,剩下的看3.2 查找单例的说明吧,一样的.
4. DefaultSingletonBeanRegistry 实现单例与DisposableBean的生命周期管理(创建,维护,销毁)
在SingletonBeanRegistry注册的基础上,添加单例的共享.
也支持容器关闭时,DisposableBean实例的销毁
4.1 这边注册时,通过下面四个变量来维护:
Map<String, Object> singletonObjects 缓存以bean name为key的单例实例
Map<String, ObjectFactory> singletonFactories 缓存以bean name 为key的ObjectFactory
Map<String, Object> earlySingletonObjects 用于解决单例时的循环依赖,这边缓存以bean name为key的预初始化单例
Set<String> registeredSingletons 已经注册好的单例bean name
这边singletonObjects和registeredSingletons的数据应该是同步的,只是适用于不同的场景,但他们俩跟singletonFactories 和earlySingletonObjects分别互斥,就是singletonObjects里有了,这两个肯定没有.
同时这边也有inCreationCheckExclusions和singletonsCurrentlyInCreation进行锁控制的概念.
singletonsCurrentlyInCreation缓存bean正在被初始化,这样就不能再发起初始化;
inCreationCheckExclusions 直接缓存当前不能加载的bean
这部分看个例子就,清晰了,初始化前需要先使用beforeSingletonCreation判断
这边inCreationCheckExclusions不包含beanName才会去判断singletonsCurrentlyInCreation
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.containsKey(beanName) &&
this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
4.2 管理bean的依赖问题
使用如下三个属性进行管理:
Map<String, Set<String>> containedBeanMap 依赖的bean name为key , 就是依赖类 -> 查找 被依赖的类
Map<String, Set<String>> dependentBeanMap 依赖的原始bean name为key
Map<String, Set<String>> dependenciesForBeanMap 被依赖的bean name为key
4.3 bean 销毁
这不过跟初始化类似,自行看代码比较简单.
5. FactoryBeanRegistrySupport 添加工厂方式创建类FactoryBean的支持
添加对FactoryBean的支持,就是使用工厂方法初始化类.
这里主要涉及3个新概念:FactoryBean,BeanPostProcessor和AccessController.这三个概念懂了,源码也就分析完了.
5.1 FactoryBean,通过T getObject() api提供简单工厂方法,可用用于创建单例,原型模式的实例.主要用于创建过程复杂,xml配置不方便的情况.
其实这个就是使用spring的接口对简单工厂设计模式做了一个规范,方便大家在spring中配置使用.
具体直接看<Spring配置bean的方法(工厂方法和Factorybean)>
5.2 BeanPostProcessor用于bean 初始化时进行功能增强,类似web开发中的filter.
这边有两个api:
postProcessBeforeInitialization 在类初始化前调用,比InitializaingBean 的 setPropertiesSet 和 xml文件中自定义的init-method方法执行都早
postProcessAfterInitialization 类初始话后调用,在InitializaingBean 的 setPropertiesSet 和 xml文件中自定义的init-method方法之后执行
5.3 AccessController jdk的安全控制,跟spring关联不大,还是度娘吧,不多写了.
在 Java 中将执行程序分成本地和远程两种,本地代码默认视为可信任的,而远程代码则被看作是不受信的。对于授信的本地代码,可以访问一切本地资源。
在应用开发中还有一些关于安全的复杂用法,其中最常用到的 API 就是 doPrivileged。doPrivileged 方法能够使一段受信任代码获得更大的权限,甚至比调用它的应用程序还要多,可做到临时访问更多的资源。
所以就出现了spring中的典型代码
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}else {
object = factory.getObject();
}
Spring源码解析 - AbstractBeanFactory 实现接口与父类分析的更多相关文章
- Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...
- spring 源码解析
1. [文件] spring源码.txt ~ 15B 下载(167) ? 1 springн┤┬вио╬Ш: 2. [文件] spring源码分析之AOP.txt ~ 15KB 下载( ...
- Spring源码解析-ioc容器的设计
Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...
- Spring源码解析之BeanFactoryPostProcessor(三)
在上一章中笔者介绍了refresh()的<1>处是如何获取beanFactory对象,下面我们要来学习refresh()方法的<2>处是如何调用invokeBeanFactor ...
- Spring源码解析之ConfigurationClassPostProcessor(二)
上一个章节,笔者向大家介绍了spring是如何来过滤配置类的,下面我们来看看在过滤出配置类后,spring是如何来解析配置类的.首先过滤出来的配置类会存放在configCandidates列表, 在代 ...
- Spring源码解析——循环依赖的解决方案
一.前言 承接<Spring源码解析--创建bean>.<Spring源码解析--创建bean的实例>,我们今天接着聊聊,循环依赖的解决方案,即创建bean的ObjectFac ...
- Spring源码解析系列汇总
相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...
- Spring源码解析之PropertyPlaceholderHelper(占位符解析器)
Spring源码解析之PropertyPlaceholderHelper(占位符解析器) https://blog.csdn.net/weixin_39471249/article/details/7 ...
- identityserver4源码解析_2_元数据接口
目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4 ...
随机推荐
- margin和padding的四种写法
我们经常会看到CSS样式属性中外边距margin和内边距padding的各种用法,这里做一个小结,但只简单介绍margin,因为它们的用法大同小异. 方法一. margin:10px; //4个外边距 ...
- JDK和Tomcat部署时,版本不同的问题解决
问题: 在以Tomcat作为Web容器,启动java Web工程时,遇到下面问题:org.eclipse.jdt.internal.compiler.classfmt.ClassFormatExcep ...
- Python 3 学习笔记(1)
Python 3.6 运算符 + - * / 四则运算 % 求余 **乘方 // 用于整除 字符串 字符串用单引号或双引号括起来. 三引号(单引号或双引号均可)表示多行字符串,行末加反斜杠表示换行不算 ...
- Python修改文件的两种方法
目录: 一.以占用内存的方式修改文件 二.以占用硬盘的方式修改文件 引言 文件修改的方法从操作方式上大致可以分为两类,一种是以占用电脑内存的方式,将文件读取到内存中修改再存回硬盘:第二种方法是分别打开 ...
- DBA 招聘
数据库管理员(资深) 眼控科技 10-19万 72小时反馈 上海 6小时前 大专及以上 2年以上经验 普通话 25-35岁 绩效奖金 带薪年假 午餐补助 定期体检 年底双薪 五险一金 职位描述: 工作 ...
- oracle ITL(事务槽)的理解
一.ITL描述: ITL(Interested Transaction List)是Oracle数 据块内部的一个组成部分,位于数据块头(block header),itl由xid,uba,flag, ...
- MySQL8 重置改root密码及开放远程访问
1. 修改配置文件 先修改配置文件:vim /etc/my.conf 在 [mysqld] 下加上下面这行 skip-grant-tables 重启 mysql 服务: service mysqld ...
- javaWeb后端学习记录
java后端学习重点: 1.java语言特性: 基础知识,集合,多线程,并发,JVM,NIO,网络编程,设计模式. (★★★★★) jdk源码中有大量的数据结构与java语言细节.jdk源码着重看c ...
- 第十章 泛型程序设计与C++标准模板库 泛型程序设计及STL的结构
- vs2010使用中遇到的一些问题[xyytIT]
1. 代码编辑器行号显示: 设置方法:点击菜单栏的"工具"-->"选项",弹出选项窗体-->标上选项窗体左下方的"显示所有设置" ...