Spring IoC源码学习:parseDefaultElement 详解,应届毕业生java面试准备材料

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

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

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正文

// 解析destroy-method属性

if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {

String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);

bd.setDestroyMethodName(destroyMethodName);

}

else {

if (this.defaults.getDestroyMethod() != null) {

bd.setDestroyMethodName(this.defaults.getDestroyMethod());

bd.setEnforceDestroyMethod(false);

}

}

// 解析factory-method属性

if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {

bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));

}

// 解析factory-bean属性

if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {

bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));

}

return bd;

}

内容比较简单,就是从节点 ele 拿到所有的属性值,塞给 AbstractBeanDefinition 的对应属性。这些属性的使用如下图。

代码块4:parseConstructorArgElements


public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {

// 拿到beanEle节点的所有子节点

NodeList nl = beanEle.getChildNodes();

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

Node node = nl.item(i);

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

// 解析constructor-arg

parseConstructorArgElement((Element) node, bd);

}

}

}

拿到 beanEle 节点的所有子节点,遍历解析所有是 constructor-arg 节点的子节点,见代码块5详解

例子:

constructor-arg 的使用如下图所示,constructor-arg 节点类似于构造函数,bean 中必须要有相应的构造函数才可以使用,否则会报错。

代码块5:parseConstructorArgElement


public void parseConstructorArgElement(Element ele, BeanDefinition bd) {

// 1.提取基础属性index、type、name属性值

// 提取index属性

String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);

// 提取type属性

String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);

// 提取name属性

String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

if (StringUtils.hasLength(indexAttr)) {

try {

int index = Integer.parseInt(indexAttr);

if (index < 0) {

error(“‘index’ cannot be lower than 0”, ele);

}

else {

try {

// 2.index不为空的处理

this.parseState.push(new ConstructorArgumentEntry(index));

// 2.1解析ele节点对应的属性值

Object value = parsePropertyValue(ele, bd, null);

// 2.2使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素

ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);

// 2.3将type属性封装到ConstructorArgumentValues.ValueHolder

if (StringUtils.hasLength(typeAttr)) {

valueHolder.setType(typeAttr);

}

// 2.4将name属性封装到ConstructorArgumentValues.ValueHolder

if (StringUtils.hasLength(nameAttr)) {

valueHolder.setName(nameAttr);

}

valueHolder.setSource(extractSource(ele));

// 2.5判断index是否重复指定, 如果是则抛出异常

if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {

error("Ambiguous constructor-arg entries for index " + index, ele);

}

else {

// 将index和valueHolder以key-value形式添加至当前BeanDefinition的constructorArgumentValues

// 的indexedArgumentValues属性中,(用于上面判断index是否重复指定)

bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);

}

}

finally {

this.parseState.pop();

}

}

}

catch (NumberFormatException ex) {

error(“Attribute ‘index’ of tag ‘constructor-arg’ must be an integer”, ele);

}

}

else {

try {

// 3.index为空的处理

this.parseState.push(new ConstructorArgumentEntry());

// 3.1解析ele节点对应的属性值

Object value = parsePropertyValue(ele, bd, null);

// 3.2使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素

ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);

// 3.3将type属性封装到ConstructorArgumentValues.ValueHolder

if (StringUtils.hasLength(typeAttr)) {

valueHolder.setType(typeAttr);

}

// 3.4将name属性封装到ConstructorArgumentValues.ValueHolder

if (StringUtils.hasLength(nameAttr)) {

valueHolder.setName(nameAttr);

}

valueHolder.setSource(extractSource(ele));

// 3.5将valueHolder添加至当前BeanDefinition的constructorArgumentValues的genericArgumentValues属性中

// 与上面的indexedArgumentValues类似,上面有index存为map,这边没index存为list

bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);

}

finally {

this.parseState.pop();

}

}

}

1.首先拿到基础属性 index、type、name 的属性值。

2.index不为空的处理:

2.1 首先解析 ele 节点的值,可以看代码块4里的图,每个 constructor-arg 节点必然有一个属性值,可能是通过 value 属性、ref 属性、list 属性等。见代码块6详解。

2.5 判断index是否重复指定,如果是则抛出异常;如果不重复,则将 index 和 valueHolder 以 key-value 形式添加至当前BeanDefinition 的 constructorArgumentValues 的 indexedArgumentValues 属性中(用于前面判断index是否重复指定)。

3.index为空的处理。基本与2相同,不在赘述。

代码块6:parsePropertyValue


public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {

String elementName = (propertyName != null) ?

“ element for property '” + propertyName + “'” :

“ element”;

// Should only have one child element: ref, value, list, etc.

// 1.拿到ele节点的子节点,例如list、map

NodeList nl = ele.getChildNodes();

Element subElement = null;

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

Node node = nl.item(i);

// 跳过description或者meta节点

if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&

!nodeNameEquals(node, META_ELEMENT)) {

// Child element is what we’re looking for.

if (subElement != null) {

// 只能有1个子节点,否则抛出异常

error(elementName + " must not contain more than one sub-element", ele);

} else {

// 找到子节点,赋值给subElement

subElement = (Element) node;

}

}

}

// 2.解析constructor-arg上的ref属性

boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);

// 3.解析constructor-arg上的value属性

boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);

// 4.合法性校验。在constructor-arg上:ref属性、value属性、子节点,三者只能有1个,因为这三个都是用来表示该节点的值。

if ((hasRefAttribute && hasValueAttribute) ||

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

error(elementName +

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

}

if (hasRefAttribute) {

// 5.ref属性的处理,使用RuntimeBeanReference封装对应的ref值(该ref值指向另一个bean的beanName),

// RuntimeBeanReference起到占位符的作用,ref指向的beanName将在运行时被解析成真正的bean实例引用

String refName = ele.getAttribute(REF_ATTRIBUTE);

if (!StringUtils.hasText(refName)) {

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

}

RuntimeBeanReference ref = new RuntimeBeanReference(refName);

ref.setSource(extractSource(ele));

return ref;

} else if (hasValueAttribute) {

// 6.value属性的处理,使用TypedStringValue封装

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

valueHolder.setSource(extractSource(ele));

return valueHolder;

} else if (subElement != null) {

// 7.解析子节点

return parsePropertySubElement(subElement, bd);

} else {

// 8.既没有ref属性,也没有value属性,也没有子节点,没法获取ele节点的值,直接抛异常

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

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

return null;

}

}

1.拿到 ele 节点的子节点,并赋值给变量 subElement。例如下图中 index=“3” 的节点就有子节点,子节点为 list,其他 4 个都没有子节点。

7.解析子节点,见代码块7详解

代码块7:parsePropertySubElement


public Object parsePropertySubElement(Element ele, BeanDefinition bd) {

return parsePropertySubElement(ele, bd, null);

}

public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {

// 1.校验是否为默认的命名空间,如果不是则走解析自定义节点代码

if (!isDefaultNamespace(ele)) {

return parseNestedCustomElement(ele, bd);

}

// 2.解析bean节点

else if (nodeNameEquals(ele, BEAN_ELEMENT)) {

BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);

if (nestedBd != null) {

nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);

}

return nestedBd;

}

// 3.解析ref节点

else if (nodeNameEquals(ele, REF_ELEMENT)) {

// A generic reference to any name of any bean.

String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);

boolean toParent = false;

if (!StringUtils.hasLength(refName)) {

// A reference to the id of another bean in the same XML file.

refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);

if (!StringUtils.hasLength(refName)) {

// A reference to the id of another bean in a parent context.

refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);

toParent = true;

if (!StringUtils.hasLength(refName)) {

error(“‘bean’, ‘local’ or ‘parent’ is required for element”, ele);

return null;

}

}

}

if (!StringUtils.hasText(refName)) {

error(“ element contains empty target attribute”, ele);

return null;

}

RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);

ref.setSource(extractSource(ele));

return ref;

}

// 4.解析idref节点

else if (nodeNameEquals(ele, IDREF_ELEMENT)) {

return parseIdRefElement(ele);

}

// 5.解析value节点

else if (nodeNameEquals(ele, VALUE_ELEMENT)) {

return parseValueElement(ele, defaultValueType);

}

// 6.解析null节点

else if (nodeNameEquals(ele, NULL_ELEMENT)) {

// It’s a distinguished null value. Let’s wrap it in a TypedStringValue

// object in order to preserve the source location.

TypedStringValue nullHolder = new TypedStringValue(null);

nullHolder.setSource(extractSource(ele));

return nullHolder;

}

// 7.解析array节点

else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {

return parseArrayElement(ele, bd);

}

// 8.解析list节点

else if (nodeNameEquals(ele, LIST_ELEMENT)) {

return parseListElement(ele, bd);

}

// 9.解析set节点

else if (nodeNameEquals(ele, SET_ELEMENT)) {

return parseSetElement(ele, bd);

}

// 10.解析map节点

else if (nodeNameEquals(ele, MAP_ELEMENT)) {

return parseMapElement(ele, bd);

}

// 11.解析props节点

else if (nodeNameEquals(ele, PROPS_ELEMENT)) {

return parsePropsElement(ele);

}

else {

// 12.未知属性,抛异常

error(“Unknown property sub-element: [” + ele.getNodeName() + “]”, ele);

return null;

}

}

1.解析自定义命名空间节点。之后会介绍该内容,本处暂不介绍。

2.解析 bean 节点,之前已经走过该方法,见代码块1详解

5.解析 value 节点,见代码块8详解

8.解析 list 节点,7 到 11 的解析都比较类似,这边拿常用的 list 来介绍。见代码块10详解

代码块8:parseValueElement


public Object parseValueElement(Element ele, String defaultTypeName) {

// It’s a literal value.

// 拿到ele节点值

String value = DomUtils.getTextValue(ele);

// 拿到ele节点的type属性

String specifiedTypeName = ele.getAttribute(TYPE_ATTRIBUTE);

String typeName = specifiedTypeName;

if (!StringUtils.hasText(typeName)) {

// ele节点没有type属性则则使用入参defaultTypeName

typeName = defaultTypeName;

}

try {

// 1.使用value和type构建TypedStringValue

TypedStringValue typedValue = buildTypedStringValue(value, typeName);

typedValue.setSource(extractSource(ele));

typedValue.setSpecifiedTypeName(specifiedTypeName);

return typedValue;

}

catch (ClassNotFoundException ex) {

error(“Type class [” + typeName + “] not found for element”, ele, ex);

return value;

}

}

1.使用 value 和 typeName 构建 TypedStringValue,见代码块9详解

代码块9:buildTypedStringValue


protected TypedStringValue buildTypedStringValue(String value, String targetTypeName)

throws ClassNotFoundException {

ClassLoader classLoader = this.readerContext.getBeanClassLoader();

TypedStringValue typedValue;

// 1.targetTypeName为空,则只使用value来构建TypedStringValue

if (!StringUtils.hasText(targetTypeName)) {

typedValue = new TypedStringValue(value);

}

// 2.targetTypeName不为空,并且classLoader不为null

else if (classLoader != null) {

// 2.1 利用反射,构建出type的Class,如果type是基本类型,或者 java.lang 包下的常用类,

// 可以直接从缓存(primitiveTypeNameMap、commonClassCache)中获取

Class<?> targetType = ClassUtils.forName(targetTypeName, classLoader);

typedValue = new TypedStringValue(value, targetType);

} else {

typedValue = new TypedStringValue(value, targetTypeName);

}

return typedValue;

}

代码块10:parseListElement


public List parseListElement(Element collectionEle, BeanDefinition bd) {

// 1.拿到collectionEle节点的value-type,顾名思义,该属性就是该list节点下的value的类型

String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);

// 2.拿到collectionEle节点的所有子节点, 一般为

NodeList nl = collectionEle.getChildNodes();

// 3.new一个ManagedList,用于存放字节点的值

ManagedList target = new ManagedList(nl.getLength());

target.setSource(extractSource(collectionEle));

target.setElementTypeName(defaultElementType);

target.setMergeEnabled(parseMergeAttribute(collectionEle));

// 4.解析子节点集合

parseCollectionElements(nl, target, bd, defaultElementType);

return target;

}

protected void parseCollectionElements(

NodeList elementNodes, Collection target, BeanDefinition bd, String defaultElementType) {

// 4.1 遍历elementNodes

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

Node node = elementNodes.item(i);

// 4.2 跳过description节点

if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {

// 4.3 调用parsePropertySubElement方法对节点进行解析, 正常list的子节点为节点会直接走到value节点的解析

// 如果list的子节点还是list,则相当于递归在走到此方法

target.add(parsePropertySubElement((Element) node, bd, defaultElementType));

}

}

}

4.3 调用 parsePropertySubElement 方法对节点进行解析,见代码块7详解

正常情况下,list 里面应该是 value节点(见下图),则会走到代码块8解析出对应的value,然后结束。特殊情况下,可能 list 里面还是 list,则相当于递归在走到此方法。

至此,代码块4 ~ 代码块10 完成了constructor-arg 节点的解析,让我们回到代码块2的第5点,继续解析 property 子节点。

代码块11:parsePropertyElements


public void parsePropertyElements(Element beanEle, BeanDefinition bd) {

// 拿到beanEle节点的所有子节点

NodeList nl = beanEle.getChildNodes();

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

Node node = nl.item(i);

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

// 解析property节点

parsePropertyElement((Element) node, bd);

}

}

}

拿到 beanEle 节点的所有子节点,遍历解析所有是 property 节点的子节点,见代码块12详解

property 的使用如下图所示,property 节点类似于set方法,bean 中的属性必须要有 set 方法才可以使用,否则会报错。

代码块12:parsePropertyElement


public void parsePropertyElement(Element ele, BeanDefinition bd) {

// 1.拿到name属性

String propertyName = ele.getAttribute(NAME_ATTRIBUTE);

if (!StringUtils.hasLength(propertyName)) {

// name属性为必要属性,如果没有配置,则抛出异常

error(“Tag ‘property’ must have a ‘name’ attribute”, ele);

return;

}

this.parseState.push(new PropertyEntry(propertyName));

try {

// 2.校验在相同bean节点下,是否存在相同的name属性,如果存在则抛出异常

if (bd.getPropertyValues().contains(propertyName)) {

error(“Multiple ‘property’ definitions for property '” + propertyName + “'”, ele);

return;

}

// 3.解析属性值

Object val = parsePropertyValue(ele, bd, propertyName);

// 4.将解析的属性值和属性name封装成PropertyValue

PropertyValue pv = new PropertyValue(propertyName, val);

// 5.解析meta节点(基本不用,不深入解析)

parseMetaElements(ele, pv);

pv.setSource(extractSource(ele));

// 6.将解析出来的PropertyValue,添加到BeanDefinition的propertyValues属性中(上面的重复校验用到)

bd.getPropertyValues().addPropertyValue(pv);

}

finally {

this.parseState.pop();

}

}

3.解析属性值,上文已经介绍过该方法,见代码块6详解

代码块13:registerBeanDefinition


public static void registerBeanDefinition(

BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

throws BeanDefinitionStoreException {

// Register bean definition under primary name.

// 1.拿到beanName

String beanName = definitionHolder.getBeanName();

// 2.注册beanName、BeanDefinition到缓存中(核心逻辑),实现类为; DefaultListableBeanFactory

registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

// Register aliases for bean name, if any.

// 注册bean名称的别名(如果有的话)

String[] aliases = definitionHolder.getAliases();

if (aliases != null) {

for (String alias : aliases) {

// 3.注册bean的beanName和对应的别名映射到缓存中(缓存:aliasMap)

registry.registerAlias(beanName, alias);

}

}

}

2.注册 beanName、BeanDefinition 到缓存中,见代码块14详解

3.如果有别名,则注册 bean 的 beanName 和对应的别名映射到 aliasMap 缓存中,见代码块16详解

代码块14:registerBeanDefinition


@Override

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

throws BeanDefinitionStoreException {

// 1.beanName和beanDefinition为空校验

Assert.hasText(beanName, “Bean name must not be empty”);

Assert.notNull(beanDefinition, “BeanDefinition must not be null”);

if (beanDefinition instanceof AbstractBeanDefinition) {

try {

// 注册前的最后校验

((AbstractBeanDefinition) beanDefinition).validate();

} catch (BeanDefinitionValidationException ex) {

throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,

“Validation of bean definition failed”, ex);

}

}

BeanDefinition oldBeanDefinition;

// 首先根据beanName从beanDefinitionMap缓存中尝试获取

oldBeanDefinition = this.beanDefinitionMap.get(beanName);

if (oldBeanDefinition != null) {

// 2.beanName存在于缓存中

if (!isAllowBeanDefinitionOverriding()) {

// 如果不允许相同beanName重新注册,则直接抛出异常

throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,

“Cannot register bean definition [” + beanDefinition + “] for bean '” + beanName +

“': There is already [” + oldBeanDefinition + “] bound.”);

} else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {

// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE

if (this.logger.isWarnEnabled()) {

this.logger.warn(“Overriding user-defined bean definition for bean '” + beanName +

“’ with a framework-generated bean definition: replacing [” +

oldBeanDefinition + “] with [” + beanDefinition + “]”);

}

} else if (!beanDefinition.equals(oldBeanDefinition)) {

if (this.logger.isInfoEnabled()) {

this.logger.info(“Overriding bean definition for bean '” + beanName +

“’ with a different definition: replacing [” + oldBeanDefinition +

“] with [” + beanDefinition + “]”);

}

} else {

if (this.logger.isDebugEnabled()) {

this.logger.debug(“Overriding bean definition for bean '” + beanName +

“’ with an equivalent definition: replacing [” + oldBeanDefinition +

“] with [” + beanDefinition + “]”);

}

}

// 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存(以供后续创建bean时使用)

this.beanDefinitionMap.put(beanName, beanDefinition);

} else {

// 3.beanName不存在于缓存中

if (hasBeanCreationStarted()) {

// 3.1 bean创建阶段已经开始

// Cannot modify startup-time collection elements anymore (for stable iteration)

synchronized (this.beanDefinitionMap) {

// 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存

this.beanDefinitionMap.put(beanName, beanDefinition);

// 将本次传进来的beanName 加入beanDefinitionNames缓存

List updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);

updatedDefinitions.addAll(this.beanDefinitionNames);

updatedDefinitions.add(beanName);

this.beanDefinitionNames = updatedDefinitions;

// 将beanName从manualSingletonNames缓存移除

if (this.manualSingletonNames.contains(beanName)) {

Set updatedSingletons = new LinkedHashSet(this.manualSingletonNames);

updatedSingletons.remove(beanName);

this.manualSingletonNames = updatedSingletons;

}

}

} else {

// 3.2 bean创建阶段还未开始

// Still in startup registration phase

// 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存

this.beanDefinitionMap.put(beanName, beanDefinition);

// 将本次传进来的beanName 加入beanDefinitionNames缓存

this.beanDefinitionNames.add(beanName);

// 将beanName从manualSingletonNames缓存移除

this.manualSingletonNames.remove(beanName);

}

this.frozenBeanDefinitionNames = null;

}

// 4.如果存在相同beanName的BeanDefinition,并且beanName已经存在单例对象,则将该beanName对应的缓存信息、单例对象清除,

// 因为这些对象都是通过oldBeanDefinition创建出来的,需要被覆盖掉的,

// 我们需要用新的BeanDefinition(也就是本次传进来的beanDefinition)来创建这些缓存和单例对象

if (oldBeanDefinition != null || containsSingleton(beanName)) {

resetBeanDefinition(beanName);

}

}

这个方法会将 beanName 添加到 beanDefinitionNames 缓存,将 beanName 和 BeanDefinition 的映射关系添加到beanDefinitionMap 缓存。

如果 beanName不重复(一般不会重复),对于我们当前正在解析的 obtainFreshBeanFactory 方法来说,因为 bean 创建还未开始,因此会走到 3.2 进行缓存的注册。

4.如果 beanName 重复,并且该 beanName 已经存在单例对象,则会调用 resetBeanDefinition 方法,见代码块15详解

代码块15:resetBeanDefinition


protected void resetBeanDefinition(String beanName) {

// Remove the merged bean definition for the given bean, if already created.

// 1.删除beanName的mergedBeanDefinitions缓存(如果有的话)

clearMergedBeanDefinition(beanName);

// Remove corresponding bean from singleton cache, if any. Shouldn’t usually

// be necessary, rather just meant for overriding a context’s default beans

// (e.g. the default StaticMessageSource in a StaticApplicationContext).

// 2.从单例缓存中删除该beanName对应的bean(如果有的话)

destroySingleton(beanName);

// Reset all bean definitions that have the given bean as parent (recursively).

// 3.重置beanName的所有子Bean定义(递归)

for (String bdName : this.beanDefinitionNames) {

if (!beanName.equals(bdName)) {

BeanDefinition bd = this.beanDefinitionMap.get(bdName);

// 当前遍历的BeanDefinition的parentName为beanName,则递归调用resetBeanDefinition进行重置

if (beanName.equals(bd.getParentName())) {

resetBeanDefinition(bdName);

}

}

}

}

比较简单,将该 beanName 的 mergedBeanDefinitions 缓存信息删除、单例缓存删除。如果存在子 bean 定义,则递归重置。实际开发过程中,基本不会出现 beanName 相同的情况,因此基本不会走到该方法。

代码块16:registerAlias


@Override

public void registerAlias(String name, String alias) {

Assert.hasText(name, “‘name’ must not be empty”);

Assert.hasText(alias, “‘alias’ must not be empty”);

// 1.如果别名和beanName相同,则不算别名,从aliasMap缓存中移除

if (alias.equals(name)) {

this.aliasMap.remove(alias);

}

else {

String registeredName = this.aliasMap.get(alias);

if (registeredName != null) {

if (registeredName.equals(name)) {

// An existing alias - no need to re-register

// 2.如果别名已经注册过,直接返回

return;

}

// 3.如果存在相同的别名,并且不允许别名覆盖,则抛出异常

if (!allowAliasOverriding()) {

throw new IllegalStateException(“Cannot register alias '” + alias + “’ for name '” +

name + “': It is already registered for name '” + registeredName + “'.”);

}

}

// 4.检查name和alias是否存在循环引用。例如A的别名为B,B的别名为A

checkForAliasCircle(name, alias);

// 5.将别名和beanName的映射放到aliasMap缓存中

this.aliasMap.put(alias, name);

}

}

将别名和 beanName 注册到 aliasMap 缓存。

最后

小编精心为大家准备了一手资料

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术

【附】架构书籍

  1. BAT面试的20道高频数据库问题解析
  2. Java面试宝典
  3. Netty实战
  4. 算法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

BATJ面试要点及Java架构师进阶资料

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

if (alias.equals(name)) {

this.aliasMap.remove(alias);

}

else {

String registeredName = this.aliasMap.get(alias);

if (registeredName != null) {

if (registeredName.equals(name)) {

// An existing alias - no need to re-register

// 2.如果别名已经注册过,直接返回

return;

}

// 3.如果存在相同的别名,并且不允许别名覆盖,则抛出异常

if (!allowAliasOverriding()) {

throw new IllegalStateException(“Cannot register alias '” + alias + “’ for name '” +

name + “': It is already registered for name '” + registeredName + “'.”);

}

}

// 4.检查name和alias是否存在循环引用。例如A的别名为B,B的别名为A

checkForAliasCircle(name, alias);

// 5.将别名和beanName的映射放到aliasMap缓存中

this.aliasMap.put(alias, name);

}

}

将别名和 beanName 注册到 aliasMap 缓存。

最后

小编精心为大家准备了一手资料

[外链图片转存中…(img-AE5Dj2S7-1713571817640)]

[外链图片转存中…(img-dHAPEejG-1713571817641)]

以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术

【附】架构书籍

  1. BAT面试的20道高频数据库问题解析
  2. Java面试宝典
  3. Netty实战
  4. 算法

[外链图片转存中…(img-7NozUpTv-1713571817641)]

BATJ面试要点及Java架构师进阶资料

[外链图片转存中…(img-irWEQOJD-1713571817641)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-885ij0sC-1713571817641)]

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

  • 30
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值