private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
//
@Nullable
private Supplier<?> instanceSupplier;
//允许访问非公开的构造器和方法,后面反射需要用到
private boolean nonPublicAccessAllowed = true;
//是否以宽松模式去解析构造函数
private boolean lenientConstructorResolution = true;
//bean工厂的名字
@Nullable
private String factoryBeanName;
//bean工厂的方法名字
@Nullable
private String factoryMethodName;
//记录construct-arg标签对象的,即构造函数给的参数
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
//记录property标签的
@Nullable
private MutablePropertyValues propertyValues;
//记录lookup-method、replaced-method标签的
private MethodOverrides methodOverrides = new MethodOverrides();
//初始化bean的方法,对应bean的init-method,即创建bean时就会调用
@Nullable
private String initMethodName;
//销毁Bean的方法,即bean的生命周期过了之后会调用的方法
@Nullable
private String destroyMethodName;
//是否执行init-method
private boolean enforceInitMethod = true;
//是否执行destiry-method
private boolean enforceDestroyMethod = true;
//标明该bean是用户定义的,还是程序本身定义的
private boolean synthetic = false;
//
private int role = BeanDefinition.ROLE_APPLICATION;
//bean的描述信息
@Nullable
private String description;
//bean的资源来源,也就是XML文件
@Nullable
private Resource resource;
现在我们已经解析完XML,并且产生了BeanDefinition对象了,但这一大串的逻辑仅仅只是转换成功而已,还没有进行注册了,现在返回BeanDefinitionDocumentReader的processBeanDefinition里面
我们仅仅只是完成了bgHolder的创建,但还没有进行下面的修饰和注册了
从代码上可以看到,XML转换成BeanDefinition是由delegate(BeanDefinitionParserDelegate)去实现,然后对新建的BeanDefinition进行修饰,同样也是交给了delegate去做,而注册BeanDefinition的逻辑是交由BeanDefinitionReaderUtils去实现
为什么要进行修饰呢?下面来看一个场景
<mybean:user username=“abc”/>
可以看到,这一段Bean的XML配置使用了自定义类型的解析
拓展:对于bean的解析分为两种类型
-
一种是默认类型的解析
-
另一种是自定义类型的解析
而上面的正是为自定义类型解析,前面已经基本上对bean标签做了默认的解析,但对于自定义类型的解析,要在哪里做呢?
这一切的逻辑都在下一行的代码执行的方法,decorateBeanDefinitionIfRequired
源码如下
注意这里,有一个参数为null了!
第三个参数其实是父类的bean,当对某个嵌套配置进行分析时,这里是需要传递父类的BeanDefinition的
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
// 记录解析了默认标签的bean
BeanDefinitionHolder finalDefinition = originalDef;
// Decorate based on custom attributes first.
// 获取bean标签的所有属性
NamedNodeMap attributes = ele.getAttributes();
//遍历所有属性
for (int i = 0; i < attributes.getLength(); i++) {
//获取当前属性
Node node = attributes.item(i);
//对该属性进行修饰
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
//
// Decorate based on custom nested elements.
//获取bean标签的所有子标签
NodeList children = ele.getChildNodes();
//遍历所有子标签
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
//如果当前的子标签
//并且如果子标签是一个XML标签的子标签
//就进行修饰
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
可以看到,这个方法对标签进行了修饰,分别修饰两个方面,并且修饰的方法是一样的!!!
-
属性
-
子标签
因为修饰方法是一样的,所以就不细分了
修饰子标签与属性
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
//获取标签的命名空间
String namespaceUri = getNamespaceURI(node);
//如果命名空间不为空,并且不是默认的命名空间,才进行下面处理
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
//根据命名空间找到对应的处理器
//命名空间决定了哪些标签能用
//因为可以通过命名空间找到那些标签的处理器
//有处理器才能使用标签
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
//判断是否找到处理器
if (handler != null) {
//用处理器进行修饰
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
//修饰的结果不为空,返回结果
if (decorated != null) {
return decorated;
}
}
//如果找不到处理器且命名空间是spring的命名空间
//抛出错误,自定义的标签怎么可能使用sprinf的命名空间!!!
else if (namespaceUri.startsWith(“http://www.springframework.org/schema/”)) {
error(“Unable to locate Spring NamespaceHandler for XML schema namespace [” + namespaceUri + “]”, node);
}
//其他情况,即没有找到处理器,且又不是Spring的命名空间
//抛出错误,没有处理器可以解析XML标签
else {
// A custom namespace, not to be handled by Spring - maybe “xml:…”.
if (logger.isDebugEnabled()) {
logger.debug(“No Spring NamespaceHandler found for XML schema namespace [” + namespaceUri + “]”);
}
}
}
//如果没有命名空间或者是默认的命名空间,不处理直接返回
return originalDef;
}
可以对于子标签和属性之所以可以一起处理,是因为对于子标签和属性,命名空间都有对应的处理器去处理,这里我们暂且将进来二点对象默认为子结点(属性与子标签),步骤如下
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
最后
由于篇幅限制,小编在此截出几张知识讲解的图解
目、讲解视频,并且后续会持续更新**
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-vpgbQLqf-1711997579161)]
最后
由于篇幅限制,小编在此截出几张知识讲解的图解
[外链图片转存中…(img-B5zZcEJn-1711997579162)]
[外链图片转存中…(img-ExGhKZuf-1711997579163)]
[外链图片转存中…(img-IFOSEn66-1711997579164)]
[外链图片转存中…(img-hi17BTp6-1711997579165)]
[外链图片转存中…(img-5RtM4NXC-1711997579166)]