SpringloC容器的依赖注入源码解析(3)—— doGe

doGetBean源码:

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
java复制代码protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

// 先将方法传入的name转换成容器真实的beanName
// 之前可以通过三种形式获取beanName
// 一个是原始的beanName,一个是加了&的,一个是别名
final String beanName = transformedBeanName(name);
Object bean;

// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
// 加果先前已经创建过单例Bean的实例,并且调用的getBean方法传入的参数为空,则执行理面的逻辑
// args之所以要求为空是因为如果有args,则需要做进一步赋值,因此无法直接返回
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
// 如果Bean还在创建中,则说明是循环引用
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 如果是普通bean,直接返回,如果是FactoryBean,则返回他的getObject
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}

// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}

if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}

try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}

// Create bean instance.
// 如果BeanDefinition为单例
if (mbd.isSingleton()) {
// 这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}

// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}

之前讨论了doGetBean里面从缓存获取bean的代码,doGetBean方法接下来的else处理Bean的scope为prototype或者单例模式但是缓存中还不存在bean的情况:
请添加图片描述
Spring同样为scope为prototype的Bean设计了一个缓存列表

1
2
3
java复制代码if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
1
2
3
4
5
java复制代码protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}

相比单例的set,这里是ThreadLocal,只记录当前线程创建出来的scope为prototype的Bean,上面的if如果是true的话证明有循环依赖。

通过了循环依赖校验之后看容器是否存在父容器,如果存在且当前容器里没有包含此bean的BeanDefinition实例,尝试去从父类容器递归查询

请添加图片描述
为了防止之前的beanName已经被转换的不成样子,将&重新加上,再调用父类的doGetBean或者getBean方法,如果父类是AbstractBeanFactory,则调用doGetBean

如果当前容器里包含了此bean的BeanDefinition实例则继续执行

1
2
3
4
5
java复制代码// typeCheckOnly 是用来判断调用 getBean() 是否仅仅是为了类型检查获取 bean,而不是为了创建Bean
if (!typeCheckOnly) {
// 如果不是仅仅做类型检查则是创建bean
markBeanAsCreated(beanName);
}

进入markBeanAsCreated方法里,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码protected void markBeanAsCreated(String beanName) {
// 双重检查锁机制
if (!this.alreadyCreated.contains(beanName)) {
synchronized (this.mergedBeanDefinitions) {
if (!this.alreadyCreated.contains(beanName)) {
// Let the bean definition get re-merged now that we're actually creating
// the bean... just in case some of its metadata changed in the meantime.
// 将原先合并之后的RootBeanDefinition的需要重新合并的状态设置为true
// 表示需要重新合并一遍,以防原数据的改动
clearMergedBeanDefinition(beanName);
// 将已经创建好的或者正在创建的Bean的名称加到alreadyCreated这个缓存中
this.alreadyCreated.add(beanName);
}
}
}
}

有一个双重锁检查机制,创建的Bean的名称加到alreadyCreated(类型Set)这个缓存中,在加入缓存之前需要将原先的MergedBeanDefinition设置上一个需要清除的标识符,目的是让后续从容器中获取BeanDefinition时重新合并子类和父类的BeanDefinition,这样就可以防止元数据被改动后,BeanDefinition还是按照原来的数据去创建

1
2
3
4
5
6
java复制代码protected void clearMergedBeanDefinition(String beanName) {
RootBeanDefinition bd = this.mergedBeanDefinitions.get(beanName);
if (bd != null) {
bd.stale = true;
}
}

clearMergedBeanDefinition回去容器中获取RootBeanDefinition实例,然后把该实例需要重新合并的状态设为true(之前提到过,只要指定了parent属性,则两个BeanDefinition就合并成一个来使用)


回到doGetBean,接下来会调用getMergedLocalBeanDefinition方法来合并子类和父类的BeanDefinition,进入到该方法里:

1
2
3
4
5
6
7
8
java复制代码protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

先从mergedBeanDefinitions缓存里获取之前已经合并好的RootBeanDefinition实例,如果stale为true的话就会合并一遍BeanDefinition,随后返回。


回到doGetBean,获取到了BeanDefinition之后,就去对相关实例做合法性校验

1
java复制代码checkMergedBeanDefinition(mbd, beanName, args);

进入到checkMergedBeanDefinition方法里:

1
2
3
4
5
6
7
java复制代码protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args)
throws BeanDefinitionStoreException {

if (mbd.isAbstract()) {
throw new BeanIsAbstractException(beanName);
}
}

看一下RootBeanDefinition是否是抽象的。


回到doGetBean,尝试从BeanDefinition里获取显式的依赖关系,如果有depends-on的话就检查是否有循环依赖关系
请添加图片描述
如果没有循环依赖的话则会将相关的依赖关系注册上

1
java复制代码registerDependentBean(dep, beanName);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
java复制代码public void registerDependentBean(String beanName, String dependentBeanName) {
String canonicalName = canonicalName(beanName);

synchronized (this.dependentBeanMap) {
// computeIfAbsent:若key对应的value为空,会将第二个参数的返回值存入并返回
// dependentBeanMap中存放着当前Bean被引用的Bean的集合
// 比如当前需要实例化的是Bean的名字是userInfo,userInfo中有个Human类型的属性human
// 那么就有human被userInfo引用的关系 human=[userInfo]
Set<String> dependentBeans =
this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
if (!dependentBeans.add(dependentBeanName)) {
return;
}
}

synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean =
this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
dependenciesForBean.add(canonicalName);
}
}

先获取name,之后就进入两重注册,第一重注册往dependentBeanMap中写入键值对,key是被依赖的Bean名字,value是依赖他的Bean名字列表

第二重注册往dependenciesForBeanMap中写入键值对,键值对和上面正好是相反的


回到doGetBean,执行完显式依赖关系注册之后就会递归调用getBean(dep)来将依赖的bean创建出来,往后就是根据不同的scope进行不同的创建bean的操作了,分为Singleton、Prototype和其他。

除了Prototype是直接调用createBean(beanName, mbd, args)去创建Bean实例之外,scope=其他的将createBean封装到了一个匿名参数里
请添加图片描述
进入scope.get()方法

1
java复制代码Object get(String name, ObjectFactory<?> objectFactory);

可见后面的匿名函数实现的是ObjectFactory的getObject方法,调用createBean方法去创建适配scope的实例。

下面主要分析scope = singleton的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码if (mbd.isSingleton()) {
// 这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
// 显式从单例缓存中删除 bean实例
// 因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

进入getSingleton方法:
请添加图片描述
也是接收一个ObjectFactory对象然后实现其getObject方法。

进入createBean:

1
2
java复制代码protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException;

这是个抽象方法需要子类去实现。

再回到上面的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
java复制代码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) {
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 {
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.
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) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}

先将一级缓存singletonObjects上锁,获取到锁之后再次尝试从一级缓存里去获取实例,以防别的线程创建好了,如果获取不到实例就开始做真正的创建了:

先看一下目前容器是否正在销毁所有的单例:
请添加图片描述
singletonsCurrentlyInDestruction是个flag。

通过验证之后会来到beforeSingletonCreation(beanName),进入:

1
2
3
4
5
6
7
java复制代码protected void beforeSingletonCreation(String beanName) {
//inCreationCheckExclusions 直接缓存当前不能加载的bean,
//主要用在web容器的拦截器里,所以这里可以忽略,因为肯定是不存在的
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}

if 的第一个条件可以忽略,第二个条件是尝试将beanName放入正在创建的单例名字列表里,添加失败则会抛异常,因为bean的正常创建流程按理是进入不到这里的,如果beanName出现在正在创建的名字列表中则表明在本次操作之前对于同一个bean的创建已经在进行了,doGetBean的时候第一步从三级缓存中获取Bean实例的时候就应该已经获取到了。

在并发场景下,两个线程在三级缓存里都没获取到单例,就会来到这里。

再回到上面的getSingleton方法,接下来就可以去创建并获取bean实例了:
请添加图片描述
newSingleton设置为true方便后续调用addSingleton来添加一级缓存。

异常处理跳过,看一下finally:
请添加图片描述
进入afterSingletonCreation:

1
2
3
4
5
java复制代码protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}

由于bean实例已经创建完毕了,所以会从正在创建的bean名字列表singletonsCurrentlyInCreation中移除beanName

回到外面,接下来就会去判断是否是新创建的单例,之前标志位已经是true了,进入addSingleton

1
2
3
4
5
6
7
8
9
java复制代码protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// Bean实例完成创建之后,只保留一级缓存以及注册beanName的顺序,其余的清除
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}

执行完addSingleton之后就会返回完整的bean实例了


回到doGetBean的创建单例的逻辑中,返回完整的bean实例之后就会执行

1
2
java复制代码// 如果是普通bean,直接返回,是FactoryBean,返回他的getObject
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

再看下scope为Prototype的创建:
请添加图片描述
进入beforePrototypeCreation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet<>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
}
else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}

向类型为ThreadLocal的prototypesCurrentlyInCreation(当前线程正在创建的Prototype的bean名字列表)去添加该bean的记录,防止循环依赖,表示这个bean正在创建中。

回到doGetBean,之后也调用了prototypeInstance = createBean(beanName, mbd, args),创建完之后将先前注册的正在创建中的Bean信息给抹除掉

1
java复制代码afterPrototypeCreation(beanName);
1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码protected void afterPrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal instanceof String) {
this.prototypesCurrentlyInCreation.remove();
}
else if (curVal instanceof Set) {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.remove(beanName);
if (beanNameSet.isEmpty()) {
this.prototypesCurrentlyInCreation.remove();
}
}
}

回到doGetBean,之后也会调用

1
java复制代码bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);

获取bean实例或者beanFactory创建的bean实例


最后在看其他的情况,
请添加图片描述
根据生命周期范围选择实例化bean的合适方法来创建bean实例,比如request就是确保每个请求生成一个实例。


doGetBean最后会做一个类型检查,校验通过后返回实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java复制代码if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%