从网上看到一篇博文 徒手撸框架–实现IoC ,写得很棒,作者抛开了 Spring 源码中复杂的校验,拓展等功能,实现了一个极简的 IoC 框架,让 Spring 源码初学者可以清楚的看到 IOC 的实现流程。

本文就借其框架,略加改造,再次介绍一下 Spring 是如何处理循环依赖的。

了解本项目核心代码需要先参考原作者的博文 徒手撸框架–实现IoC

循环依赖

其实很好理解,A 类依赖 B,B 又依赖 A。

说具体点就是 ,我们要 getBean(“a”), A 在实例化时需要为类型为 B 的成员变量赋值,因此去 getBean(“b”),而 getBean(“b”) 的时候又需要为其类型为A 的成员变量赋值,此时又会回过头去实例化 A ,导致无限循环。

用代码展示就是

1
2
3
4
5
6
7
8
public class A {
@AutoWired
private B b;
}
public class B {
@AutoWired
private A a;
}

代码改造

最主要的代码改造在于 BeanFactoryImpl 内, 添加了成员变量

1
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

用于缓存正在创建中的,提前暴露出来的单例 bean。

在获取 bean 时,会在创建之前先从此 Map 中尝试获取,而这就是解决循环依赖的关键。

以上面的例子来说,就是一开始 getBean(“a”) 时,将未完成的 a 放入缓存,getBean(“b”) 时,需要去获取 a ,会从缓存中获取,而不是再去实例化 a。

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
@Override
public Object getBean(String name) throws Exception {
//查找对象是否已经实例化过
Object bean = beanMap.get(name);
if (bean != null) {
return bean;
}
Object earlyBean = earlySingletonObjects.get(name);
if (earlyBean != null) {
System.out.println("循环依赖,提前返回尚未加载完成的bean:" + name);
return earlyBean;
}
//如果没有实例化,那就需要调用createBean来创建对象
BeanDefinition beanDefinition = beanDefineMap.get(name);
bean = createBean(beanDefinition);
if (bean != null) {
earlySingletonObjects.put(name, bean);
//对象创建成功以后,注入对象需要的参数
populatebean(bean, beanDefinition);
//再吧对象存入Map中方便下次使用。
beanMap.put(name, bean);
//从早期单例Map中移除
earlySingletonObjects.remove(name);
}
//结束返回
return bean;
}

Q & A

Q: 构造器循环依赖为什么无法解决?

A: 从上面代码可以看出,需要在 createBean 之后,才能将其放入缓存,而构造过程是在 createBean 之内的,此时尚未构造好一个基本的 bean ,拿什么放入缓存呢?

心得

上面只贴了 getBean 的代码,仅仅修改了原作者不到 10 行代码,其实在修改原框架,实现我们要的功能时不止这么多,包括调整对 json 的解析,对 bean 的填充等。

感受到 Spring 框架真的是很复杂很全面,这复杂程度靠说是说不清楚的,也不是翻一遍书看看源码就能明白的。而且看源码其实还是似懂非懂,中间的细节迷迷糊糊就可能跳过去了。

在追随 Spring 脚步,复现其代码的时候,才更深刻的理解其中很多操作,很多类的作用。比如说 BeanDefinition, BeanWrapper , PropertyDescriptor 这些类在我想要实现一些功能的时候才能体会到 Spring 创造它们的重要性。

评论和共享

前文

源码解析

入参说明

  • includeNonSingletons:是否包括非单例的 bean,比如 prototype scope
  • allowEagerInit:为了这个检查(找出所有匹配类型的 beanName),是否初始化 lazy-init 单例和由 FactoryBeans 创建的对象。此处我们传入的值为 true。
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

public static String[] beanNamesForTypeIncludingAncestors(
ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {

Assert.notNull(lbf, "ListableBeanFactory must not be null");
//方法主干还是在这行 getBeanNamesForType
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
//下面的内容就是从 bf 的 parent 中找,
if (lbf instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
//此处以 parent 再来调此方法,合并结果。
String[] parentResult = beanNamesForTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
List<String> resultList = new ArrayList<String>();
resultList.addAll(Arrays.asList(result));
for (String beanName : parentResult) {
if (!resultList.contains(beanName) && !hbf.containsLocalBean(beanName)) {
resultList.add(beanName);
}
}
result = StringUtils.toStringArray(resultList);
}
}
return result;
}

看来我们还需要继续深入到 getBeanNamesForType中去一探究竟。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
//configurationFrozen:判断所有 bean 的 定义元数据是否可以被缓存
//如果不能缓存 或没type 或不允许急切初始化,则直接查 doGetBeanNamesForType
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
//否则先查缓存,没有缓存的话再查 doGetBeanNamesForType 并塞入缓存
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
//判断是否缓存安全:依据我们目标class 和当前beanFactory的classLoader是否一致
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}

再深入一层到 doGetBeanNamesForType ,其中逻辑外层是遍历所有的 beanName, 对于不是别名的进行处理,处理过程如下(省略了 try-catch ):

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
//首先获取这个beanName对应的mbd,它的相关定义配置信息
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
// 不是抽象的
// 并且 允许急切初始化 或 (此bean不需要急切初始化 且(有beanClass 或 不是lazyInit 或 允许急切的类加载,即使是懒惰的初始化bean))
if (!mbd.isAbstract() && (allowEagerInit ||
((mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading())) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// In case of FactoryBean, match object created by FactoryBean.
//判断是否 FactoryBean
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
//接下来又是一段非常长的逻辑判断,判断是否匹配
boolean matchFound =
(allowEagerInit || !isFactoryBean ||
(dbd != null && !mbd.isLazyInit()) || containsSingleton(beanName)) &&
(includeNonSingletons ||
(dbd != null ? mbd.isSingleton() : isSingleton(beanName))) &&
isTypeMatch(beanName, type);
if (!matchFound && isFactoryBean) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
//如果不匹配,还要试试匹配FactoryBean本身,因为说不好要的就是这个FactoryBean呢
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
}
if (matchFound) {
result.add(beanName);
}
}

//检查一遍手动的单例集合
//对于 FactoryBean ,如果匹配到它的getObject()满足,就不会继续去匹配它本身
for (String beanName : this.manualSingletonNames) {
// In case of FactoryBean, match object created by FactoryBean.
if (isFactoryBean(beanName)) {
if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
result.add(beanName);
// Match found for this bean: do not match FactoryBean itself anymore.
continue;
}
// In case of FactoryBean, try to match FactoryBean itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
}
// Match raw bean instance (might be raw FactoryBean).
if (isTypeMatch(beanName, type)) {
result.add(beanName);
}
}

}

前一段的超长的逻辑判断看得人头疼,但是先看下半段的遍历,突然就找到了最关键判断类型匹配的函数 isTypeMatch,从名字就看出来,这应该就是判断类型匹配的地方啦。

然而点进去一看,居然是长达 100 行的函数。

isTypeMatch

首先从单例中查找,匹配这个单例 bean 的类型和我们目标的类型,其中对 factoryBean 的处理也比较简单,就不再贴代码了。对于注册的 null instance ,也返回 false。

再从父工厂找,递归 isTypeMatch 。

再就是复杂的查找了。

先定义个 typesToMatch ,包括了目标类型和 FactoryBean .

然后我们再继续看代码。

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
// Check decorated bean definition, if any: We assume it'll be easier
// to determine the decorated bean's type than the proxy's type.
// 先检查 bean 的装饰definition。
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
return typeToMatch.isAssignableFrom(targetClass);
}
}
// 注意此处predictBeanType返回了很关键的Class ,我们后面再详细分析此方法。
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
if (beanType == null) {
return false;
}

// Check bean class whether we're dealing with a FactoryBean.
//接下来就是处理 FactoryBean
if (FactoryBean.class.isAssignableFrom(beanType)) {
if (!BeanFactoryUtils.isFactoryDereference(name)) {
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
beanType = getTypeForFactoryBean(beanName, mbd);
if (beanType == null) {
return false;
}
}
}
else if (BeanFactoryUtils.isFactoryDereference(name)) {
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
// type but we nevertheless are being asked to dereference a FactoryBean...
// Let's check the original bean class and proceed with it if it is a FactoryBean.
beanType = predictBeanType(beanName, mbd, FactoryBean.class);
if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
return false;
}
}
//对其 resolvableType 进行处理
ResolvableType resolvableType = mbd.targetType;
if (resolvableType == null) {
resolvableType = mbd.factoryMethodReturnType;
}
if (resolvableType != null && resolvableType.resolve() == beanType) {
return typeToMatch.isAssignableFrom(resolvableType);
}
//如果以上都没有处理掉的话, 则判读typeToMatch和 beanType
return typeToMatch.isAssignableFrom(beanType);

总结:

目前很遗憾 isTypeMatch 往下还有很复杂的逻辑暂时不能看懂,但是从外层的逻辑大致知道寻找所有匹配的beanName 的方法非常的“复杂粗暴”。遍历 beanDefinitionNames 已定义的所有 bean,即使是一个小型的项目也有近200个 bean 需要遍历,并且这数百个 beanName 还要遍历非常多次。

只能说根据 type 寻找 bean 实在是比根据 name 复杂了太多太多,从源码看真是深坑,理解了为什么作者直接忽略了这部分…应该是第二遍或第三遍阅读 Spring 源码时才能理解。

评论和共享

前言

Spring 装配 bean 有两种类型:autowireByNameautowireByType

autowireByName 通过名称查找很直接,就是我们一直在学的 getBean() 。

autowireByType 根据类型查找相比起来就要复杂一些了,《 Spring 源码深度解析 》 中有介绍过的部分我就不再重复贴了,但是书中遗漏了一处重要的部分—— findAutowireCandidates 查找所有合适的 bean,还有一处新版本 Spring 中升级的部分——如果只需要一个但是找出多个 bean 该怎么处理,今天我们先来学习第一部分。

正文

本函数要做什么

1
2
3
4
5
6
@RestController
@RequestMapping("/article")
public class ArticleController {
@Autowired
private ArticleService articleService;
}

在初始化 ArticleController 的过程中,我们要为其装配 ArticleService 。

忽略掉外面代码一层一层的包裹之后,我们走到 DefaultListableBeanFactory.findAutowireCandidates 这个函数中,要寻找合适的候选 bean 。由于可能会找到多个,因此返回结果是候选 bean 的名称和其对应实例构成的 Map 。

源码解析

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
//三个参数的含义依次是 
// 正在解析的 beanName, 本例中即 "articleController"
// 需要装配的 bean 类型, 本例中即 ArticleService.class
// 对当前依赖关系的解析类,记录了 ArticleController 和 ArticleService 的依赖关系
protected Map<String, Object> findAutowireCandidates(String beanName,
Class<?> requiredType,
DependencyDescriptor descriptor) {

//第一步就是查找出所有符合类型的 beanName 。
//似乎第一句就干完全部逻辑了???稍后我们再详细分析这个方法。
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
/**
* resolvableDependencies 记录了 依赖类型--具体装配值 的映射
* 遍历 resolvableDependencies。如果该类型是我们需要的类型(ArticleService),
*
*/
for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = this.resolvableDependencies.get(autowiringType);
//key值是我们需要的类型,但value值未必。
//value可能是ObjectFactory,就得调用它的 getObject() 来获取真正的bean.
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
//如果类型匹配,则塞入result
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
//如果不是自己依赖自己 , 并且符合装配候选,就塞入result。
//何为符合装配候选(isAutowireCandidate)呢?稍后我们再详细分析。
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
// Consider fallback matches if the first pass failed to find anything...
//如果之前一轮都没找到,则考虑回退匹配,什么是回退匹配?稍后再分析。
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) {
//再执行一遍上面的方法。如果不是自己依赖自己,并且符合装配候选,就塞入result。
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
// 如果依然没找到结果,那么满足以下条件的也是我们的目标。
// 1.是自引用
// 2.依赖不是多元素依赖 或者 bean名和候选者名字不相等(这里就避免了自引用导致无限循环)
// 3.候选者符合回退匹配之后的装配候选
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}

看完主干自然还是有点迷糊,我们留下了三个问题要继续研究:

评论和共享

Spring vs MyBatis

Spring 和 MyBatis 中都有 BeanWrapper , Spring 中为接口, 实现类为 BeanWrapperImpl , 为了方便后面区分,本文用 SB 指代 Spring 的 BeanWrapperImpl ,用 MB 指代 MyBatis 中的 BeanWrapper。

功能

BeanWrapper 都属于各自框架的反射工具箱的重要组成部分。都是创建实例并且为其属性赋值的。以 SB 为例,下面的代码应该很容易看明白它的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BeanWrapper company = BeanWrapperImpl(new Company());
// setting the company name..
company.setPropertyValue("name", "Some Company Inc.");

// ... can also be done like this:
PropertyValue value = new PropertyValue("name", "Some Company Inc.");
company.setPropertyValue(value);

// ok, let's create the director and tie it to the company:
BeanWrapper jim = BeanWrapperImpl(new Employee());
jim.setPropertyValue("name", "Jim Stravinsky");
company.setPropertyValue("managingDirector", jim.getWrappedInstance());

// retrieving the salary of the managingDirector through the company
Float salary = (Float) company.getPropertyValue("managingDirector.salary");

共同点

  1. 核心功能功能基本相同
  2. 对要生成的类的要求规范也相同,有 get set 方法。
  3. 它们的底层也没有什么秘密,归根到底都是使用 java.lang.reflect 包下的 Constructor , Method 等等工具。

不同点

可能是我刚开始研究 SB 的原因,感觉 SB 源码更加复杂,结构也没那么清楚,关联了向下层级的工具类,很长很长一段的源码。 这篇博文 分析了其中一部分。

得益于已经学习过结构更为清晰的 MB,尽管 SB 源码复杂,但是读的时候不再会恐惧,因为简略的Debug 一遍就知道它底层还是调 getter/setter 的反射。再复杂的结构也离不开这最终的方法。

已目前对 SB 粗浅的了解来说,感受到最大的区别就是在工具箱中的结构地位不同

MB 属于BaseWrapper 的子类之一,同级别的还有 MapWrapper ,上级还有 CollectionWrapper 。

而 SB 就已经是在创建 Bean 时直接使用到的接口了。

解析嵌套参数名 (比如 user.name / address.city.mailcode),类型转换这些事情,SB 都能处理完。而 MB 都是先要使用其它工具类处理,比如依靠 PropertyTokenizer 。

总而言之,SB 就是对外的一个大接口,包含很多功能,MB 则是MyBatis 反射工具箱内的一个小的工具实现。

评论和共享

此方法交给了 AbstractBeanFactory 的子类 AbstractAutowireCapableBeanFactory 去实现。

并且不管这个bean是单例还是 prototype 还是其它 scope ,最终都是会走到此处,只是前后的一些验证、处理有区别。比如单例的就要先去缓存中获取,prototype 就不需要。

源码阅读到这里,我们已经习惯了一层一层剥。createBean 依然还是没有直接地把 bean 创建出来(当然我所期望的看到创建 bean 就是看到它的反射源码为止)。

createBean 的大致步骤为:

  1. 根据 RootBeanDefinition 来获取要创建 bean 的 class 。这 class 还有可能为 null。
  2. prepareMethodOverrides 。准备 override 方法,对 override 属性进行验证。
  3. 给后处理器一个机会来返回代理,替代真正的 bean.
  4. doCreateBean 创建真正的 bean 实例。

prepareMethodOverrides

首先去温习一遍 lookup-method 和 replace-method 吧。博文

其实就是通过配置把原本 bean 中的某个方法给替代掉。

此处我们先只是确认一遍指定的替代方法存在于要生成的 bean 中。

顺带看一看这个方法有没有重载overload),做个标记。

resolveBeforeInstantiation

经过一波预处理器InstantiationAwareBeanPostProcessor ,如果生产出了 bean,再经过一波后处理器。

一旦生产出 bean,则立即将此 bean 返回。

此处就是留下了一个拓展点,经过此方法之后,bean可能已经不是我们认为的 bean 了,而可能已经变成了一个经过处理的代理 bean 。

循环依赖

构造器循环依赖

如果是 prototype,无法解决,只能抛错。

代码在 AbstractBeanFactory : 256 doGetBean()

当创建 bean 时,首先去“当前创建 bean 池”查找是否当前 bean 正在创建,如果发现存在,则表示循环依赖了。抛出 BeanCurrentlyInCreationExcetion 。

当前创建 bean 池:

1
2
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<Object>("Prototype beans currently in creation");

setter 循环依赖

只能解决单例的情况。

在创建单例 bean 时,提前暴露刚完成构造器但未完成其他步骤(如 setter 注入)的 bean 。

通过提前暴露这个单例工厂方法,从而使其他 bean 能够引用到此 bean。

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
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
//注意这里返回的是 早期引用
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}

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);
}
}
}

简单地记一下这里解决步骤:

testA 先创建,并且暴露一个工厂出去,进行 setter 注入 testB.

testB 创建,并且暴露一个工厂,进行 setter 注入 testA.

在这里想用 testA 时,由于发现提前暴露的工厂,从而在此处走了另一条路,使用此工厂来创建 testA ,在此处解决了循环问题。

再返回回去继续完成 testA 的 setter 注入。

评论和共享

获取单例bean getSingleton

明明之前一篇已经讲过了获取单例,为什么这里又是获取单例bean呢?

两天不看书,果断又忘了.前面学的是从缓存中获取,这里是真正的获取.

DefaultSingletonBeanRegistry 中重载此方法,第二参数为ObjectFactory<?>

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
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
//这里再次看到了这个singletonObjects,上篇文章介绍过,是维护了单例对象
//书中说法是:用于保存BeanName和创建bean实例之间的关系
Map var3 = this.singletonObjects;
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 the singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)");
}

if (this.logger.isDebugEnabled()) {
//打印日志,正在创建单例bean(beanName)的共享的实例
this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
//标志这个beanName正在创建,如果同时重复创建,会报错
this.beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = this.suppressedExceptions == null;
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet();
}

try {
//=============这里应该是最关键的创建bean的步骤===============
singletonObject = singletonFactory.getObject();
//标识新创建出来的单例
newSingleton = true;
} catch (IllegalStateException var16) {
//非法状态错误,应该是创建过程中发现存在其他线程已创建此单例
//所以此处catch里面再次调用了singletonObjects.get(beanName);
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw var16;
}
} catch (BeanCreationException var17) {
//其它创建bean错误
BeanCreationException ex = var17;
if (recordSuppressedExceptions) {
Iterator var8 = this.suppressedExceptions.iterator();
while(var8.hasNext()) {
Exception suppressedException = (Exception)var8.next();
//把其它recordSuppressedExceptions塞入这个ex一并抛出
ex.addRelatedCause(suppressedException);
}
}
throw ex;
} finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
//确认这个beanName在几个set中的状态
this.afterSingletonCreation(beanName);
}
if (newSingleton) {
//如果是新创建的,则加入缓存,移除几个新创建的标识,名字加入registeredSingletons
this.addSingleton(beanName, singletonObject);
}
}
//返回,如果是NULL_OBJECT也作为null返回.
//这个NULL_OBJECT应该是在前面的获取方法中有可能的特殊返回值
return singletonObject != NULL_OBJECT ? singletonObject : null;
}
}

从上可以看出,获取单例还是通过 synchronized(this.singletonObjects) 加锁来实现,先从 singletonObjects 查一遍有没有已存在的,若没有则再进行创建。

而创建的步骤,则是在入参的 ObjectFactory<?> 中完成,调用其 getObject() 依然还是调用我们本身AbstractBeanFactorycreateBean 方法。


我们先不急着往下看,先理一理,首先第一点要知道的是单例加锁都是 synchronized(this.singletonObjects) 。其次获取单例 bean 的大致步骤,无非就是:

  1. 上一文中介绍的,从缓存中拿,并且允许“早期引用” ,即从 earlySingletonObjects 中拿。

  2. 如果缓存中没有,则自己创建,

    2.1 在各种 map 里记录它的 创建、销毁等信息

    2.2 通过createBean 方法去具体创建这个实例。

评论和共享

缓存中获取单例bean getSingleton

DefaultSingletonBeanRegistry 中实现此方法

1
2
3
4
5
6
7
8
//这个map维护了单例对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//当前正在创建中的单例对象
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));
//早期单例对象
private final Map<String, Object> earlySingletonObjects = new HashMap(16);
//单例工厂?
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
//如果根据这个beanName没取到对象,但发现这个对象还在创建中.....
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
Map var4 = this.singletonObjects;
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
//如果早期单例对象中没有此bean,并且允许早期依赖
if (singletonObject == null && allowEarlyReference) {
//当某些方法需要提前初始化的时候则会调用 addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactories
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//调用预先设定的getObject方法
singletonObject = singletonFactory.getObject();
//记录在缓存中,earlySingletonObjects 和 singletonFactories互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject != NULL_OBJECT ? singletonObject : null;
}

这里还是看得迷迷糊糊的,毕竟一来就各种取值, 往后看看在哪塞值的吧!

从bean的实例中获取对象 getObjectForBeanInstance

​ 我们得到bean的实例后要做的第一步都是调用这个方法来检测一下正确性,其实就是用于检测当前bean是否是FactoryBean 类型的bean,如果是,就要调用getObject() 方法作为返回值

FactoryBean 在之前我们便已经接触过.

getObjectForBeanInstance 方法就不贴了, 主要就是各种验证, 取缓存等等, 里面需要注释的一段如下

1
2
3
4
5
   	//将存储XML配置文件的GernericBeanDefinition 转换为RootBeanDefinition,
//如果指定BeanName是子bean的话,同时会合并父类的相关属性
if (mbd == null && this.containsBeanDefinition(beanName)) {
mbd = this.getMergedLocalBeanDefinition(beanName);
}

​ 方法中的关键是 getObjectFromFactoryBean , 实现类为 FactoryBeanRegistrySupport

​ 而 getObjectFromFactoryBean 方法中也还不是最核心的, 其代码主要是保证单例bean的全局唯一. 如果是单例,那就不用重复创建,可以使用缓存来提高性能. 另外方法还根据需要对bean进行了后处理postProcessObjectFromFactoryBean()

后处理即是遍历所有的bean后处理器,在bean初始化后调用它的处理方法,后面还会详细学习.

​ 它的关键是 doGetObjectFromFactoryBean ,方法名前面多加了个do…

在这个方法里面,我们终于看到想要看到的 `object = factory.getObject();`  ,虽然早已知道必须要走到这,但是到这一步`getObject()` 还是绕了很多路,包括到这里居然还使用了`java.security.AccessController` 权限验证...

评论和共享

1
2
3
4
5
6
7
8
9
10
package org.springframework.beans.factory;

public interface FactoryBean<T> {
//返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中
T getObject() throws Exception;
//返回FactoryBean创建的bean类型
Class<?> getObjectType();
//返回bean实例的作用域是singleton还是prototype
boolean isSingleton();
}

​ 当配置文件的class属性配置的实现类是FactoryBean 时,通过getBean() 方法返回的不是FactoryBean 本身,而是FactoryBean.getObject() 方法所返回的对象.

​ 相当于FactoryBean.getObject() 代理了getBean() 方法.

​ 例如,如果使用传统方式配置Car的bean,Car的每个属性对应一个 元素标签

1
2
3
4
5
6
public class Car {
private int maxSpeed;
private String brand;
private double price;
//get/set
}

​ 如果使用FactoryBean的方式就会灵活一些,下面通过逗号分隔符的方式一次性地为Car的所有属性指定配置值:

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
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo;

@Override
public Car getObject() throws Exception {
Car car = new Car();
String[] infos = carInfo.split(",");
car.setBrand(infos[0]);
car.setMaxSpeed(Integer.valueOf(infos[1]));
car.setPrice(Double.valueOf(infos[2]));
return car;
}

@Override
public Class<?> getObjectType() {
return Car.class;
}

@Override
public boolean isSingleton() {
return false;
}

public String getCarInfo() {
return carInfo;
}

public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
}

有了这个CarFactoryBean之后,就可以在配置文件使用下面这种自定义的配置方式配置Car bean了

1
<bean id="car" class="com.test.factoryBean.CarFactoryBean" carInfo="超级跑车,400,3000" />

调用 getBean(“car”) , Spring并不会返回CarFactoryBean 而是返回car

如果希望返回CarFactoryBean 那就 getBean(“&car”)


书本作者讲到FactoryBean 接口对于Spring框架很关键, Spring自身就提供了70多个实现.

它们隐藏了实例化一些复杂的bean的细节,给上层应用带来了便利.

疑问: 具体哪些地方用FactoryBean 带来了真正的便利呢?

答:

评论和共享

本文要看啥?

​ 前面已经了解了bean从配置文件到解析成BDHolder到注册的流程,我们已经将bean的信息封装好,塞入了map中,这个map可能在不同的实现里面,前面重点学的就是DefaultListableBeanFactory里的beanDefinitionMap.

​ 我们现在要探索bean的加载,围绕最初的示例代码:

1
MyTestBean bean =(MyTestBean)bf.getBean("myTestBean");

​ BeanFactory是个接口,其下实现关系很复杂, getBean方法的实现主要是在AbstractBeanFactory 这一层.

​ 本文就是先来快速体验一下加载bean的大体流程

进入代码吧

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
protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
//转换beanName
final String beanName = this.transformedBeanName(name);
//根据beanName找其单例
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if (sharedInstance != null && args == null) {
if (this.logger.isDebugEnabled()) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//返回对应的实例
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
//原型模式下,如果这个bean已经正在创建中,说明是如下情况
//A中有B的属性,B中有A的属性,当依赖注入的时候,就回产生当A还未创建完的时候,
//因为对于B的创建,再次返回创建A,造成循环依赖
//所以就会报错
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//获取父工厂
BeanFactory parentBeanFactory = this.getParentBeanFactory();
//如果本工厂没有这个bean,存在父工厂,就去父工厂找
if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
//注意下面是递归地去父工厂找
if (args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
}
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
//如果不是仅仅做类检查则是创建bean,这里要进行记录
if (!typeCheckOnly) {
this.markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var11;
//如果存在依赖,就递归地先去实例化依赖的bean
if (dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length;

for(int var13 = 0; var13 < var12; ++var13) {
String dep = var11[var13];
if (this.isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
this.registerDependentBean(dep, beanName);
this.getBean(dep);
}
}
if (mbd.isSingleton()) {
//单例模式的创建
sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return AbstractBeanFactory.this.createBean(beanName, mbd, args);
} catch (BeansException var2) {
AbstractBeanFactory.this.destroySingleton(beanName);
throw var2;
}
}
});
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
//原型模式的创建
var11 = null;
Object prototypeInstance;
try {
//创建原型之前,先把prototypesCurrentlyInCreation里塞值,表示当前正在创建哪些原型
this.beforePrototypeCreation(beanName);
//注意到createBean这个方法留给了子类去实现
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
//移出prototypesCurrentlyInCreation,表示创建这个原型结束
this.afterPrototypeCreation(beanName);
}

bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
//其它模式的创建(指定的scope上实例化bean
String scopeName = mbd.getScope();
Scope 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, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
AbstractBeanFactory.this.beforePrototypeCreation(beanName);

Object var1;
try {
var1 = AbstractBeanFactory.this.createBean(beanName, mbd, args);
} finally {
AbstractBeanFactory.this.afterPrototypeCreation(beanName);
}
return var1;
}
});
bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException var21) {
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", var21);
}
}
} catch (BeansException var23) {
this.cleanupAfterBeanCreationFailure(beanName);
throw var23;
}
}

if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
//检查类型是否符合bean的实际类型
try {
return this.getTypeConverter().convertIfNecessary(bean, requiredType);
} catch (TypeMismatchException var22) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var22);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
} else {
return bean;
}
}

提炼大致步骤

这120多行的代码,Spring都并没有再进行重构,可见其复杂程度,辛亏有书本解释,了解到大致步骤:

  1. 转换对应的beanName,因为传入的参数可能是alias

    从其具体方法中看,是之前见过的, 处理& 和别名的递归寻找本名.

    去前面笔记中寻找,在 SimpleAliasRegistry 中已经研究过此方法

  2. 尝试从缓存中加载单例

    此时可能从缓存中取出的是还没创建好的bean,主要是因为防止循环依赖

  3. bean的实例化

    如果从缓存中得到了bean的原始状态,则需要对bean进行实例化.

  4. 原型模式的依赖检查

  5. 检测parentBeanFactory

  6. 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition

  7. 寻找依赖

    因为bean的初始化过程中很可能会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean.

  8. 针对不同的scope进行bean的创建

  9. 类型转换

    有可能有这种情况,返回的bean,是个String,但是requiredType传入的是Integer类型,那么这时候本步骤就会起作用了. Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求

评论和共享

自定义标签的使用

主要内容都在书上,p80

关键的部分为

  • 创建XSD文件
  • 创建类 继承AbstractSingleBeanDefinitionParser , 其继承关系最主要是实现了BeanDefinitionParser 接口,顾名思义,可以用来解析bean.
  • 创建Handler文件, 继承自 NamespaceHandlerSupport ,目的是将上面的组件注册到Spring容器内
  • 编写Spring.handlers 和 Spring.schemas文件.

这样,自定义的配置就结束了.

Spring加载自定义bean的流程主要就是遇到自定义标签后就去Spring.handlers和Spring.schemas中取找对应的handler 和 XSD .从而可以拿到parser

而代码里的主要步骤为

  1. 拿到标签对应的命名空间
  2. 根据命名空间找到对应的handler
  3. 调用handler的parse方法

获取标签的命名空间

调用org.w3c.dom.Node中的getNamespaceURI()

提取自定义标签处理器

1
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

这个resolve方法是接口,由DefaultNamespaceHandlerResolver 默认命名空间解析器来实现,其实现里面的第一步便是

1
Map<String, Object> handlerMappings = this.getHandlerMappings();

原来handlerMappings 是个map,想必是在注册时肯定把解析器添加到这个map里面来,用namespaceUri做key,这样找的时候就很好找了.

取出结果如果是NamespaceHandler 便可以返回,往下读我们发现,之所以这么爽取出来就是handler,是因为已经做过这个解析,把找出的handler塞入了map,相当于是缓存了.

否则就是类名 className, 我们需要把它转为handler

1
2
3
4
5
6
7
8
9
10
11
12
13
//使用反射,将类路径转化为类
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
} else {
//初始化类
NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);
//调用类自定义的init()方法,这是所有handler都必须实现的方法
namespaceHandler.init();
//塞入缓存
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}

设计模式–单例模式

this.getHandlerMappings(); 获取handlerMapping处使用了单例模式

声明为volatile

1
private volatile Map<String, Object> handlerMappings;

获取单例时使用双重检查锁定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private Map<String, Object> getHandlerMappings() {
if (this.handlerMappings == null) {
synchronized(this) {
if (this.handlerMappings == null) {
try {
//读取"META-INF/spring.handlers" 转为map
Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded NamespaceHandler mappings: " + mappings);
}

Map<String, Object> handlerMappings = new ConcurrentHashMap(mappings.size());
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
} catch (IOException var5) {
throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", var5);
}
}
}
}

return this.handlerMappings;
}

上面的volatile非常关键,如果没有的话,在初始化对象设置handlerMapping指向内存空间 中间可能发生重排序,导致另外的线程拿到了handlerMapping的空间地址,但是其实还没有初始化完成.

标签解析

拿到解析器之后,就调用解析的parse方法,返回BeanDefinition

我们的自定义handler里面无需实现parse方法,在父类NamespaceHandlerSupport 中自有实现,

1
2
3
public BeanDefinition parse(Element element, ParserContext parserContext) {
return this.findParserForElement(element, parserContext).parse(element, parserContext);
}

而parse方法主要步骤就是调用自己实现类的parseInternal 方法,parseInternal 方法除了调用我们实现的doParse方法之外,首先会进行一系列的数据准备,包括对beanClass.scope.lazyInit等属性的准备

评论和共享

作者的图片

heeexy

世上是不是就没有你不认识的字了?


JAVA


南京