# 本文要看啥
这个bean总算是解析完了,也装饰完了,等于是说信息我们都提取好了,现在该做的就是去注册啦.
|
|
就是这个方法了
# 开始进入方法吧
|
|
拿到beanName
用beanName和bd去registry里注册.
registry是个接口,具体的实现在4.3.7版本中看到两种,一种是SimpleBeanDefinitionRegistry里,和它名字一样非常简单,就是塞进map, 另外一种就复杂了,稍后我们再来看
用beanName和alias去registry里注册
注册aliases也是接口 ,BeanDefinitionRegistry还是继承自AliasRegistry的, 4.3.7只看到SimpleAliasRegistry一种实现
注册alias就简单多了, SimpleAliasRegistry里有
1
private final Map<String, String> aliasMap = new ConcurrentHashMap(16);
稍后我再另开一文把SimpleAliasRegistry来读一遍
# 注册BeanDefinitionHolder
除了之前的SimpleBeanDefinitionRegistry
直接往map里面塞值的注册方式之外,我们还有DefaultListableBeanFactory 这个类来实现注册功能,我们主要来了解一下这种注册方式
校验空参数
如果bdh是
AbstractBeanDefinition
,那就要执行它的validate()
校验- bdh的methodOverride和它的工厂不能同时存在
- 如果它beanClass有值,那就要为方法覆盖做准备
prepareMethodOverrides()
,遍历它的overrides,找这个Bean的Class里面有几个叫这个名字的方法, 如果0个,就抛错,如果1个,就设置重载属性为false表示没重载.
从这个工厂里面
beanDefinitionMap
拿原来的叫这个beanName的bd出来,如果不为空,进行下列校验及操作书中源码spring 3.2 采用sychronized , 而4.3版本的beanDefinitionMap已经用上了ConcurrentHashMap,并且map的value用了BD,而不是3.2里面的Object
- 如果工厂不允许bean覆盖,那么抛错
- 如果旧bean的role值小于新的,或者新旧bd完全相等,或者不相等,各打印一下日志
- 把新的bd放入
beanDefinitionMap
第一次注册这个bean, 如果本工厂的
alreadyCreated
也是空的话,那就不用加锁,直接1 2 3 4 5 6
//map里塞入bd this.beanDefinitionMap.put(beanName, beanDefinition); //已注册名字里加入beanName this.beanDefinitionNames.add(beanName); //唯一名册里移出beanName(啥时候加入了???) this.manualSingletonNames.remove(beanName);
如果本工程已经有创建过bean了,那么接下来一段代码就要加synchronized了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Map var4 = this.beanDefinitionMap; synchronized(this.beanDefinitionMap) { //map里塞入bd this.beanDefinitionMap.put(beanName, beanDefinition); //注意到后面这段操作其实是新建个数组,加上这次注册beanName,然后替换之前的数组.... //为什么这么复杂呢??? List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; //如果唯一名册里包含beanName if (this.manualSingletonNames.contains(beanName)) { //就移出去,但是这里也和上面一样,搞替换.... Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } }
疑问: 这里都用了替换,明明
beanDefinitionNames
和manualSingletonNames
都是volatile声明的,每次读都从主内存取,每次写都都将值写到主内存, 这里为什么还要这么麻烦得去开新的list和set,替换旧的呢?答:从网上搜到,volatile修饰的变量如果是对象或数组之类的,其含义是对象或数组的地址具有可见性,但是数组或对象内部的成员改变不具备可见性,那等于就是说非得整个地址替换才行咯.
很爽,从这本书要跳到我正在读的并发编程相关的内容了,这几天再去研究一波volatile,可以再开一文. 准备参考地址
然后this.frozenBeanDefinitionNames = null;
这个冻结/取消冻结bdNames的功能暂时也不知道干啥的,在注册和删除bd的地方看到了这样的置为null,
只在freezeConfiguration()
方法内看到把它置为bdNames转的String[] .
另外在getBeanDefinitionNames()
方法里有判断这个
然后
|
|
重置的主要内容有
- 清除mergedBD
- 销毁单例
- 遍历之前的bean,看新注册的这个bean是谁的爹(parent),那些儿子也都要调用这个方法进行重置
不得不说这个
DefaultListableBeanFactory
的成员变量实在太多了,搞不清楚一个个都是要干啥的,后面再次遇到的时候再慢慢看吧
# 注册Alias
4.3.7版本的实现在SimpleAliasRegistry
里, 详情见 这一篇博文
# 注册完成
其实没有操作了, 但是作者留了个位置在这
|
|
如果程序开发人员需要对注册BeanDefinition时间进行监听时,可以通过注册监听器的方式来做.Spring并没有再此做任何逻辑处理
# 告一段落
至此,我们的解析注册Bean标签可算是告一段落啦,虽然里面还留下了很多疑问待后续阅读中弄清.
先想想之前是在哪分叉出去的吧.
|
|
再之前呢,
|
|
再之前呢
|
|
到这还要温习一遍的话,可以去看Spring的第一篇笔记了
哈哈,这么点东西,读了一个礼拜,读了后面的忘了前面的,还是在读读记记的情况下,
要是没有这个笔记,这时候估计已经迷路得要放弃了,不容易啊
不说了 SimpleAliasRegistry 和volatile
两篇文章的坑还留着呢,继续…