Spring(六),业内“大师级Dubbo实战笔记”面世

subElement = (Element) node;

}

}

}

//获取construct-arg的ref和value属性

boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);

boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);

//假如两个同时拥有,或者两个属性拥有一个,但解析出的子标签不为null,证明有子标签

//就代表出现了重复给构造参数了

if ((hasRefAttribute && hasValueAttribute) ||

((hasRefAttribute || hasValueAttribute) && subElement != null)) {

//重复给构造参数,报错处理

error(elementName +

" is only allowed to contain either ‘ref’ attribute OR ‘value’ attribute OR sub-element", ele);

}

//如果并没有重复,假如是ref属性

if (hasRefAttribute) {

String refName = ele.getAttribute(REF_ATTRIBUTE);

if (!StringUtils.hasText(refName)) {

error(elementName + " contains empty ‘ref’ attribute", ele);

}

//ref属性用RuntimeBeanReference对象存储

RuntimeBeanReference ref = new RuntimeBeanReference(refName);

//标明来源

ref.setSource(extractSource(ele));

//返回

return ref;

}

//如果是value属性

else if (hasValueAttribute) {

//使用TypedStringValue进行存储

TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));

valueHolder.setSource(extractSource(ele));

//返回

return valueHolder;

}

//如果是子标签形式

else if (subElement != null) {

//交由parsePropertySubElement继续处理子标签

//因为子标签也是有多种形式的

return parsePropertySubElement(subElement, bd);

}

//既没有value属性,又没有ref属性,又没有子标签

else {

// Neither child element nor “ref” or “value” attribute found.

error(elementName + " must specify a ref or value", ele);

return null;

}

}

这里就不再赘述了

PropertyValue是怎样被记录的?

前面不是说了,对于property标签,是会被放进去PropertyValues对象里面的(与Construct-arg标签被存放进ConstructArgumentValues对象一样)

在这里插入图片描述

BeanDefinition这个接口只有一个实现类就是AbstractBeanDefinition,也就是在AbstractBeanDefinition中,就初始化了这个存储容器了(与ConstructorArgumentValues一样),可知AbstractBeanDefinition有着记录创建Bean的细节

在这里插入图片描述

可以见到,其本质是MutablePropertyValues对象

在这里插入图片描述

在这里插入图片描述

而且其底层的容器有两个

  • PropertyValueList:一个ArrayList集合,并且默认容量为0,这个ArrayList就是用来存储PropertyValue的

  • proccessedProperties:一个String的集合,这个就是用来去重的!也就是原先判断这个property是否正在注册(通过name属性判断,),里面存储的就是name属性,本质上是一个HashSet并且初始化的容量为4

在这里插入图片描述

不过,决定这个property是否可以存放进来,是由这两个容器共同决定的

在这里插入图片描述

在这里插入图片描述

从代码上可以看到,判断这个property是否已经加载过,需要满足2个条件

  • 遍历PropertyValueList,里面没有一个propertyValue的name是与其一样的

  • 且proccessedProperties里面为空或者proccessedProperties没有这个propertyName记录

满足上面两个条件,才会返回false,代表这个property没有被加载过

下面再看看添加propertyValue进propertyValueList的逻辑

public MutablePropertyValues addPropertyValue(PropertyValue pv) {

//遍历存储propertyValue的propertyValueList

for (int i = 0; i < this.propertyValueList.size(); i++) {

PropertyValue currentPv = this.propertyValueList.get(i);

//如果出现了重复PropertyName

if (currentPv.getName().equals(pv.getName())) {

//判断是否需要合并处理

pv = mergeIfRequired(pv, currentPv);

//合并处理后重新修改这个propertyValue

setPropertyValueAt(pv, i);

return this;

}

}

//没有出现重复的propertyName,直接往propertyValueList里面添加

this.propertyValueList.add(pv);

return this;

}

可以看到,spring的逻辑真的严谨,前面已经判断过一次了,这里又要进行判断(一般来说,应该不会走去合并处理的)

合并的逻辑

private PropertyValue mergeIfRequired(PropertyValue newPv, PropertyValue currentPv) {

Object value = newPv.getValue();

//如果value实现了Mergeable接口

//那就进行合并!

if (value instanceof Mergeable) {

Mergeable mergeable = (Mergeable) value;

if (mergeable.isMergeEnabled()) {

//value进行合并后,产生新的propertyValue并返回

Object merged = mergeable.merge(currentPv.getValue());

return new PropertyValue(newPv.getName(), merged);

}

}

//没实现Mergeable接口,直接返回旧值

return newPv;

}

解析qualifier标签


终于到最后一个qualifier标签了

对于qualifier我们通常都是使用注解@Qualifier的,那么这个qualifier标签有什么用呢?

要知道,在使用Spring框架中进行自动注入的时候,Spring容器中提供的候选Bean必须有而且仅仅只能有一个,当找不到匹配的Bean时,Spring容器将抛出BeanCreationException

qualifier标签就是用来定义这个bean的别名的,代表这个bean必须根据名称(ByName)才会被选为候选bean(一般时ByType),即根据bean的名称进行注入!

/**

  • Parse qualifier sub-elements of the given bean element.

*/

public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {

NodeList nl = beanEle.getChildNodes();

//同理,遍历所有子标签

for (int i = 0; i < nl.getLength(); i++) {

Node node = nl.item(i);

//遇到qualifier标签就执行方法,parseQualifierElement

if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {

parseQualifierElement((Element) node, bd);

}

}

}

parseQualifierElement方法

public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {

String typeName = ele.getAttribute(TYPE_ATTRIBUTE);

//判断type属性是否为空

//type属性是

if (!StringUtils.hasLength(typeName)) {

error(“Tag ‘qualifier’ must have a ‘type’ attribute”, ele);

return;

}

//开始跟踪

this.parseState.push(new QualifierEntry(typeName));

try {

//使用AutowireCandidateQualifier去存储qualifier标签

AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);

qualifier.setSource(extractSource(ele));

String value = ele.getAttribute(VALUE_ATTRIBUTE);

if (StringUtils.hasLength(value)) {

qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);

}

NodeList nl = ele.getChildNodes();

//对Qualifier子标签进行解析!

for (int i = 0; i < nl.getLength(); i++) {

Node node = nl.item(i);

if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {

Element attributeEle = (Element) node;

//必须要有key属性和value属性

String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);

String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);

if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {

BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);

attribute.setSource(extractSource(attributeEle));

qualifier.addMetadataAttribute(attribute);

}

else {

error(“Qualifier ‘attribute’ tag must have a ‘name’ and ‘value’”, attributeEle);

return;

}

}

}

//当前bean去存储qualiier

bd.addQualifier(qualifier);

}

finally {

this.parseState.pop();

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

写在最后

学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!

最后再分享的一些BATJ等大厂20、21年的面试题,把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

Mybatis面试专题

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

MySQL面试专题

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

并发编程面试专题

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!

最后再分享的一些BATJ等大厂20、21年的面试题,把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

[外链图片转存中…(img-kFrlQI86-1712675881804)]

Mybatis面试专题

[外链图片转存中…(img-ALrr9vn9-1712675881804)]

MySQL面试专题

[外链图片转存中…(img-4Qw2R6yt-1712675881804)]

并发编程面试专题

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-d9c6SinW-1712675881805)]

  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值