spring
spring核心类分析
要想读懂spring源码就需要知道spring核心类的脉络,及核心类的作用。先有核心类的脉络体系知识后,带着脉络看源码调用流程事半功倍
ApplicationContext
ApplicationContext
接口代表了Spring Ioc容器,它负责实例化、配置、组装bean。容器通过读取配置元数据获取对象的实例化、配置和组装的描述信息 Spring提供几个开箱即用的
ApplicationContext
接口的实现类
ClassPathXmlApplicationContext
从classpath的XML配置文件中读取上下文
ApplicationContext context = new ClassPathXmlApplicationContext(“bean.xml”);
FileSystemXmlApplicationContext
- 由文件系统中的XML配置文件读取上下文
- ApplicationContext context = new FileSystemXmlApplicationContext(“bean.xml”);
XmlWebApplicationContext
- 由Web应用的XML文件读取上下文
AnnotationConfigApplicationContext
- spring boot使用的基于注解的上下文
BeanFactory 和 ApplicationContext
尽量使用ApplicationContext除非你有更好的理由不用它
因为ApplicationContext包括了BeanFactory的所有功能,通常也优于BeanFactory,除非一些少数的场景,例如:在受资源约束的嵌入式设备上运行一个嵌入式应用,它的内存消耗可能至关重要,并且可能会产生字节。然而,对于大多数典型的企业级应用和系统来说,ApplicationContext才是你想使用的。Spring大量使用了BeanPostProcessor扩展点(以便使用代理等)。如果你仅仅只使用简单的BeanFactory,很多的支持功能将不会有效,例如:事务和AOP,但至少不会有额外的步骤。这可能会比较迷惑,毕竟配置又没有错。
Feature BeanFactory ApplicationContext Bean实例化/装配 是 是 BeanPostProcessor自动注册 否 是 BeanFactoryPostProcessor自动注册 否 是 MessageSource便捷访问(针对i18n) 否 是 ApplicationEvent 发布 否 是 区别:
BeanFactory提供了ioc容器的基本功能,主要负责bean的实例化和装配,ApplicationContext代表了spring ioc容器,ApplicationContext继承于BeanFactory包含BeanFactory的所有功能,并且还提供了BeanPostProcessor,ApplicationEvent等功能,比BeanFaction功能更加强大
AnnotationConfigApplicationContext
AnnotationConfigApplicationContext,在 Spring 3.0 中 是 新加入的,从此spring进入注解配置时代,支持注解配置
@Configuration
@Bean
@Component
@Autowired
…
从类图结构中看出,
AbstractApplicationContext
是所有开箱即用的ApplicationContext
接口的实现类的中枢,图中出现另一个重要spring顶级接口体系AliasRegistry (别名注册表)
及它的子接口BeanDefinitionRegistry (Bean 定义注册表)
注册表体系
注册表体系主要提供了bean别名注册,单例bean注册,bean循环依赖三级缓存
AliasRegistry
bean别名注册表,作为bean定义的最顶层接口,这个接口定义了管理别名的一些方法,主要作用是将名字-别名映射存到内存中。提供查找和校验的接口
- registerAlias 注册一个bean的别名
- removeAlias 删除注册的别名
- isAlias 确定一个名字是否是别名
- getAliases 返回一个名字注册的别名列表。当传入bean的名称带有
&
前缀时,转换为别名后也会返回带&
前缀的别名,这种特殊处理参考BeanFactory#FACTORY_BEAN_PREFIX
BeanDefinition
在了解
BeanDefinitionRegistry (Bean 定义注册表)
之前必须知道BeanDefinition
是什么在 Spring 容器中,我们广泛使用的是一个一个的 Bean,BeanDefinition(接口) 从名字上就可以看出是关于 Bean 的定义
事实上就是这样,我们在 XML 文件中,java配置类中配置的 Bean 的各种属性,这些属性不仅仅是和对象相关,Spring 容器还要解决 Bean 的生命周期、销毁、初始化等等各种操作,我们定义的关于 Bean 的生命周期、销毁、初始化等操作总得有一个对象来承载,那么这个对象就是 BeanDefinition的实现类。文章后续会讲到spring如何将bean的配置转成
BeanDefinition
,又是如何使用BeanDefinitionRegistryPostProcessor
后置处理器使用BeanDefinition
对bean进行注册流程
- 首先一开始定义了两个变量用来描述 Bean 是不是单例的,后面的 setScope/getScope 方法可以用来修改/获取 scope 属性。
- ROLE_xxx 用来描述一个 Bean 的角色,ROLE_APPLICATION 表示这个 Bean 是用户自己定义的 Bean;ROLE_SUPPORT 表示这个 Bean 是某些复杂配置的支撑部分;ROLE_INFRASTRUCTURE 表示这是一个 Spring 内部的 Bean,通过 setRole/getRole 可以修改。
- setParentName/getParentName 用来配置 parent 的名称,这块可能有的小伙伴使用较少,这个对应着 XML 中的
<bean parent="">
配置。- setBeanClassName/getBeanClassName 这个就是配置 Bean 的 Class 全路径,对应 XML 中的
<bean class="">
配置。- setLazyInit/isLazyInit 配置/获取 Bean 是否懒加载,这个对应了 XML 中的
<bean lazy-init="">
配置。- setDependsOn/getDependsOn 配置/获取 Bean 的依赖对象,这个对应了 XML 中的
<bean depends-on="">
配置。- setAutowireCandidate/isAutowireCandidate 配置/获取 Bean 是否是自动装配,对应了 XML 中的
<bean autowire-candidate="">
配置。- setPrimary/isPrimary 配置/获取当前 Bean 是否为首选的 Bean,对应了 XML 中的
<bean primary="">
配置。- setFactoryBeanName/getFactoryBeanName 配置/获取 FactoryBean 的名字,对应了 XML 中的
<bean factory-bean="">
配置,factory-bean 松哥在之前的入门视频中讲过,小伙伴们可以参考这里:https://www.bilibili.com/video/BV1Wv41167TU。- setFactoryMethodName/getFactoryMethodName 和上一条成对出现的,对应了 XML 中的
<bean factory-method="">
配置,不再赘述。- getConstructorArgumentValues 返回该 Bean 构造方法的参数值。
- hasConstructorArgumentValues 判断上一条是否是空对象。
- getPropertyValues 这个是获取普通属性的集合。
- hasPropertyValues 判断上一条是否为空对象。
- setInitMethodName/setDestroyMethodName 配置 Bean 的初始化方法、销毁方法。
- setDescription/getDescription 配置/返回 Bean 的描述。
- isSingleton Bean 是否为单例。
- isPrototype Bean 是否为原型。
- isAbstract Bean 是否抽象。
- getResourceDescription 返回定义 Bean 的资源描述。
- getOriginatingBeanDefinition 如果当前 BeanDefinition 是一个代理对象,那么该方法可以用来返回原始的 BeanDefinition
BeanDefinition实现类
BeanDefinitionRegistry
BeanDefinitionRegistry类图
我们定义bean时不管是通过java config方式,还是xml配置文件的方式,最终都会解析成BeanDefinition,而这些BeanDefinition都需要注册到容器中,这个注册的过程是通过接口org.springframework.beans.factory.support.BeanDefinitionRegistry来定义的,也就是说BeanDefinitionRegistry子类具备注册bean的定义到ioc容器的能力
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
>org.springframework.beans.factory.support.BeanDefinitionRegistry
>// 定义bean定义的注册相关方法的接口
public interface BeanDefinitionRegistry extends AliasRegistry {
// 在注册中心注册一个bean定义,必须支持RootBeanDefinition和ChildBeanDefinition
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
// 移除对应bean名称的bean定义
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 返回给定bean名称对应的bean定义
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 检查注册中心是否包含指定名称的bean定义
boolean containsBeanDefinition(String beanName);
// 返回注册中心中所有的bean定义的名称的数组
String[] getBeanDefinitionNames();
// 返回注册中心中bean定义的个数
int getBeanDefinitionCount();
// 返回beanName是否被占用,即已经在注册中心中注册了bean定义
boolean isBeanNameInUse(String beanName);
}
bean注册的流程
sequenceDiagram 后置处理器 ->> 扫描配置 : xml、java config 扫描配置 ->> BeanDefinition : 解析生成bean定义对象 BeanDefinition ->> DefaultListableBeanFactory : BeanDefinition注册 DefaultListableBeanFactory ->> DefaultSingletonBeanRegistry : 单例bean实例化注册到ioc容器
SingletonBeanRegistry
单例bean注册表接口,这个是单例bean注册的顶级接口,主要是用于管理单例的注册、获取
1 |
|
*DefaultSingletonBeanRegistry
DefaultSingletonBeanRegistry是整个ioc容器比较核心的类,因为它负责存储、提供单例的bean实例、维护bean之间关系以及维护已经注册的bean的名称
- 解决循环依赖的三级缓存,存储单例bean
- 注册单例bean
- 添加单例bean到ioc容器
- 获取单例bean
重要属性说明
1 |
|
重要方法说明
registerSingleton
这个是对 SingletonBeanRegistry (此注册方法不会提供任何用以初始化的回调函数) 接口方法的实现,调用这个方法注册bean的一般都是框架自身的bean,比如spring准备上下文需要的bean
StandardServletEnvironment
1 |
|
addSingleton
单例bean加入到缓存
1
2
3
4
5
6
7
8
9
10
11
12
13protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 加入单例对象的缓存(一级缓存)
this.singletonObjects.put(beanName, singletonObject);
// 既然加入了单例对象的缓存,那singletonFactories和earlySingletonObjects就不再持有
// 删除三级级缓存
this.singletonFactories.remove(beanName);
// 删除二级缓存
this.earlySingletonObjects.remove(beanName);
// 加入已注册的bean
this.registeredSingletons.add(beanName);
}
}addSingletonFactory
添加三级缓存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//增加单例工程的单例,取单例的时候调用getObject方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}getSingleton
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92public Object getSingleton(String beanName) {
// 允许早期依赖
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//如果一级缓存有直接返回
Object singletonObject = this.singletonObjects.get(beanName);
//缓存没有的情况但正在创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//如果早期缓存中有,说明正在加载,则不处理直接返回
//一级缓存拿不到尝试去二级缓存拿
singletonObject = this.earlySingletonObjects.get(beanName);
//allowEarlyReference允许是否从singletonFactories读取
if (singletonObject == null && allowEarlyReference) {
// 某些方法提前初始化的时候会调用addSingletonFactory,把ObjectFactory缓存在singletonFactories中
// 二级缓存拿不到到三级缓存拿
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//如果singletonFactories有,调用getObject方法返回
singletonObject = singletonFactory.getObject();
// singletonFactories产生的对象放入earlySingletonObjects中
this.earlySingletonObjects.put(beanName, singletonObject);
// 已经产生过一次对象了,所以就不能再用了,后面直接用earlySingletonObjects获取
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 已经创建过了,直接返回
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 当前在销毁bean,不能创建
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 创建前检查,记录正在加载状态
beforeSingletonCreation(beanName);
boolean newSingleton = false;
// 如果当前没有异常,初始化异常集合
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 通过ObjectFactory的getObject创建bean,实际是回调createBean方法
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
// 有可能是其他方式创建的bean
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 创建后检查,移除加载状态
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 是新创建的bean,就加入到缓存中并移除其他缓存,如果是其他方式创建的bean,说明已经加入过缓存了,这边不再加入
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}removeSingleton
移除单例bean
1
2
3
4
5
6
7
8
9
10
11
12protected void removeSingleton(String beanName) {
synchronized (this.singletonObjects) {
// 移除一级缓存
this.singletonObjects.remove(beanName);
// 移除三级缓存
this.singletonFactories.remove(beanName);
// 移除二级缓存
this.earlySingletonObjects.remove(beanName);
// 移除已注册的beanName名单
this.registeredSingletons.remove(beanName);
}
}beforeSingletonCreation
创建单例bean之前的检查
1
2
3
4
5
6protected void beforeSingletonCreation(String beanName) {
// 如果这个beanName要检查,看看add的时候返回什么,如果返回false,说明已经在创建了,抛异常
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}afterSingletonCreation
创建单例bean之后的检查
1
2
3
4
5
6protected void afterSingletonCreation(String beanName) {
// 如果这个beanName要检查,看看remove返回什么,如果返回false,说明已经创建完了。
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}registerDisposableBean
注册具有销毁业务的bean,
1
2
3
4
5
6
7
8
9public void registerDisposableBean(String beanName, DisposableBean bean) {
synchronized (this.disposableBeans) {
this.disposableBeans.put(beanName, bean);
}
}
public interface DisposableBean {
void destroy() throws Exception;
}
BeanFactory体系
BeanFactory
BeanFactory为Spring的IoC功能提供了底层的基础,但是它仅仅被用于和第三方框架的集成,现在对于大部分的Spring用户来说都是历史了。BeanFactory及其相关的接口,例如:BeanFactoryAware,InitializingBean,DisposableBean,在Spring中仍然有所保留,目的就是为了让大量的第三方框架和Spring集成时保持向后兼容
BeanFactory和类加载器一样,也是有父BeanFactory的,具体体现在HierarchicalBeanFactory接口
1 |
|
FACTORY_BEAN_PREFIX`
String FACTORY_BEAN_PREFIX = "&";
- 根据beanName从spring容器获取实例,如果该实例不是FactoryBean类型,则直接返回该实例,这也是我们平时用的最多的、最普通的情况;如果该实例是FactoryBean类型,而name又是以&开头,也直接返回该实例,说明我们想要的就是FactoryBean实例;如果name不是以&开头,而该实例又是FactoryBean类型,则会调用该实例的getObject()来创建我们需要的目标实例
1 |
|
*AutowireCapableBeanFactory
定义BeanFactory自动装配接口
- 对于想拥有自动装配能力,并且想要把这种能力暴露给外部应用的beanfactory需要实现该接口
- 正常情况下,不要实现该接口,应该实现BeanFactory或者ListableBeanFactory接口
- 需要注意的是ApplicationContext并没实现该接口。如果需要用到自动装配功能的话,可以调用ApplicationContext.getAutowireCapableBeanFactory()方法,来获取此接口实例
- 如果一个接口实现了该接口,很大程度上,还要实现BeanFactoryWare接口,这样子就能在上下文中返回BeanFactory
1 |
|
ListableBeanFactory
提供一次性获取当前BeanFactory 所有bean信息能力
ListableBeanFactory实现了BeanFactory接口, Listable意思是可列表的,ListableBeanFactory可以枚举它们的所有bean信息,而不用一个个通过bean的名称或类型一个个查找 (比如通过bean类型获取所有的bean) 。如果容器是有层级的,比如实现了HierarchicalBeanFactory接口,返回值不考虑层级的信息,只读取当前容器定义的信息
1 |
|
HierarchicalBeanFactory
HierarchicalBeanFactory继承BeanFactory并扩展使其支持层级结构 (对BeanFactory提供分层)
1 |
|
ConfigurableBeanFactory
ConfigurableBeanFactory继承了HierarchicalBeanFactory, SingletonBeanRegistry两个接口。定义了一些对BeanFactory的配置功能,比如通过addBeanPostProcessor配置Bean后置处理器,setParentBeanFactory设置双亲Ioc容器
1 |
|
ConfigurableListableBeanFactory
ConfigurableListableBeanFactory继承了ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory。在ConfigurableBeanFactory的基础上,并扩展了忽略依赖,自动装配判断,冻结bean的定义,枚举所有bean名称的功能
1 |
|
AbstractBeanFactory
AbstractAutowireCapableBeanFactory
*DefaultListableBeanFactory
*Bean初始化的全过程
常见问题
Spring中有哪些方式可以把Bean注入到IOC容器
- 使用xml文件的方式来定义bean,在spring启动的时候会解析这个xml,把bean装载到IOC容器
- 使用@ComponentScan注解来扫描声明了 @Controller、@Service、@Component注解的类
- 使用@Configuration注解声明配置类,并使用@Bean实现bean的定义
- 使用@Import注解导入配置类或普通的Bean
- 使用FactoryBean这一个工厂Bean来构建一个Bean的实例
- 实现ImportBeanDefinitionRegistrat这个接口,可以动态注入bean实例
- 实现ImportSelector接口。动态批量注入Bean对象
Spring为什么要用三级缓存来解决循环依赖
名称 | 描述 |
---|---|
singletonObjects | 一级缓存,存放完整的 Bean |
earlySingletonObjects | 二级缓存,存放提前暴露的Bean,Bean 是不完整的,未完成属性注入和执行 init 方法 |
singletonFactories | 三级缓存,存放的是 Bean 工厂,主要是生产 Bean,存放到二级缓存中 |
什么是依赖注入(DI)?什么是控制反转(IOC)? 在 Spring 中,有几种依赖注入方式?
依赖注入:对象的创建过程由框架管理;对象外部资源的获取由对象本身反转到Ioc容器
控制反转:
spring的依赖注入有哪些方式
- 变量注入: @Autowired
- 构造器注入
- set方法注入
Spring自动装配的方式
- byName
- byType
- constructor
- autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式
spring是如何创建一个Bean对象的
bean -> 推断构造函数 -> 反射生成对象 -> 依赖注入(属性填充)-> 初始化前(@PostConstruct) -> Aware接口 -> 初始化(InitializingBean)-> 初始化后(AOP)-> 代理对象 -> 放入一级缓存
Spring事务传播行为
传播属性 | 描述 |
---|---|
REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中(默认) |
REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起 |
SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行 |
NOT_SUPPORTED | 不支持事务,如果当前存在事务就将事务挂起 |
MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常 |
NEVER | 不支持事务,如果当前存在事务,则抛出异常 |
NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作 |
嵌套事务:(部分事务提交)内层事务的回滚不影响外层事务的提交
什么是单例池?作用是什么?
DefaultSingletonBeanRegistry#singletonObjects 这个 ConcurrentHashMap就是单例池
作用就是缓存单例bean对象
Bean对象和普通对象之间的区别是什么
区别:对象的创建流程不同,spring的bean创建包含了依赖注入,初始化前操作,初始化,初始化后操作(AOP)
推断构造方法是什么意思
spring 需要通过构造函数反射创建对象,这个时候就面临构造函数选择(如果有多个),默认使用无参构造函数
- 如果没有无参构造函数并且有多个有参构造函数,则抛出异常(不知如何选择),除非给其中一个构造函数加@Autowired注解(暗示spring使用它)
- 如果没有无参构造函数,并且只有一个有参构造函数,则使用它(没得选择)
单例Bean和单例模式之间有什么关系
单例bean:通过相同的依赖注入条件能获取到同一个对象,ioc容器能注册多个类型相同的单例bean.单例bean是相对依赖注入条件而言的
单例模式:整个JVM虚拟机中只允许存在这个类型的一个实例
什么是先bytype再byname
在构造函数注入中:假设在ioc容器中注册了多个类型相同的单例bean,根据类型能够获取多个单例bean,那么就再按照变量名称匹配
1 |
|