先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里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、分布式、高并发等架构技术
【附】架构书籍
- BAT面试的20道高频数据库问题解析
- Java面试宝典
- Netty实战
- 算法
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、分布式、高并发等架构技术
【附】架构书籍
- BAT面试的20道高频数据库问题解析
- Java面试宝典
- Netty实战
- 算法
[外链图片转存中…(img-7NozUpTv-1713571817641)]
BATJ面试要点及Java架构师进阶资料
[外链图片转存中…(img-irWEQOJD-1713571817641)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-885ij0sC-1713571817641)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!