Spring#IOC#refresh#obtainFreshBeanFactory#parseDefaultElemen
2021-11-08 19:21:47 0 举报
这个流程过程需要根据上一个obtainFreshBeanFactory中继续进行,在Spring源码中还是相对比较重要的
作者其他创作
大纲/内容
用Spring默认的生成规则为当前bean生成beanName
自定义命名空间节点的处理,例如:<context:component-scan/>、<aop:aspectj-autoproxy/>
ComponentScanBeanDefinitionParser.parse
加载Bean的定义
DefaultListableBeanFactory#resetBeanDefinition
1.遍历basePackages
DefaultBeanDefinitionDocumentReader#processBeanDefinition
ClassPathScanningCandidateComponentProvider#registerDefaultFilters
拿到 Document 中的根节点,遍历根节点和所有子节点。
2.扫描basePackage,将符合要求的bean定义全部找出来(这边符合要求最常见的就是使用Component注解)
1.解析use-default-filters属性,默认为true,用于指示是否使用默认的filter
构建 XmlReaderContext
9.将当前遍历bean的 bean定义和beanName封装成BeanDefinitionHolder
wac.refresh();
Spring IoC:obtainFreshBeanFactory
返回结果:BeanDefinition
<context> 节点对应命名空间: http://www.springframework.org/schema/context <aop> 节点对应命名空间: http://www.springframework.org/schema/aop
2.使用BeanDefinition解析器解析element节点
拿到 beanEle 节点的所有子节点,遍历解析所有是 property 节点的子节点
总结:重新梳理一下思路,我们首先将 xml 中的 bean 配置信息进行了解析,并构建了 AbstractBeanDefinition(GenericBeanDefinition) 对象来存放所有解析出来的属性。然后,我们将 AbstractBeanDefinition 、beanName、aliasesArray 构建成 BeanDefinitionHolder 对象并返回。最后,我们通过 BeanDefinitionHolder 将 BeanDefinition 和 beanName 注册到 BeanFactory 中,也就是存放到缓存中。执行完 parseDefaultElement 方法,我们得到了两个重要的缓存:beanDefinitionNames 缓存。beanDefinitionMap 缓存。这两个缓存在之后的 IoC 构建过程中会发挥很重要的作用,大家在这边先有个印象。
AbstractBeanDefinition
进一步解析 bean 的其他所有属性并统一封装至 GenericBeanDefinition 类型实例中
只对第三点解析bean标签
根据配置的beanName生成beanName
根据配置文件路径加载 bean 定义reader.loadBeanDefinitions(configLocation);
BeanDefinitionReaderUtils#registerBeanDefinition
4.如果 beanName 重复,并且该 beanName 已经存在单例对象,则会调用 resetBeanDefinition 方法
拿到节点的localName,例如:annotation-config、component-scan
中中间省略一些调用过程
5.解析scope-resolver、scoped-proxy属性
3.解析节点定义完成后,需要对解析后的bdHolder进行注册
是否是默认命名空间的处理
DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
从节点拿到所有的属性值,塞给 AbstractBeanDefinition 的对应属性
进行节点定义解析
delegate.parseCustomElement(ele);
NamespaceHandler#parse
DefaultListableBeanFactory#registerBeanDefinition
ContextLoader#configureAndRefreshWebApplicationContext
否
4.最后发出响应事件,通知相关的监听器,这个Bean已经加载完成了
6.解析类型过滤器
4.解析 constructor-arg 子节点
ComponentScanBeanDefinitionParser#createScanner
XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource)
2.若存在默认标签的子节点下再有自定义属性,需要再次对自定义标签再进行解析(基本不用,不做深入解析)
BeanDefinitionParserDelegate#parseBeanDefinitionAttributes
1.拿到<context:component-scan>节点的base-package属性值
AbstractApplicationContext#refresh
4.构建和配置ClassPathBeanDefinitionScanner
2.创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition。
是
3.解析resource-pattern属性
解析默认命名空间节点的方法,是加载 bean 定义模块的最核心方法
3.解析base-package(允许通过 \
1.拿到beanName
2.拿到命名空间对应的的handler
1.解析了class、parent属性,因为第2步创建 AbstractBeanDefinition 需要用到这两个属性,否则,这两个属性可以放到第3步一起解析。
获取到web.xml中configLoactions参数配置的路径
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
1.findParserForElement: 给element寻找对应的BeanDefinition解析器
1、拿到节点ele的命名空间
BeanDefinitionParserDelegate#parseCustomElement(Element)
3.解析 bean 的剩余属性
3.beanDefinition beanName存在但是beanName为空
创建一个默认的DefaultNamespaceHandlerResolver
6.进一步处理BeanDefinition对象,比如: 此bean是否可以自动装配到其他bean中
5.使用beanName生成器来生成beanName
XmlWebApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)
ContextLoaderListener#contextInitialized
加载Bean定义过程
拿到 beanEle 节点的所有子节点,遍历解析所有是 constructor-arg 节点的子节点
创建新的BeanFactory
BeanDefinitionParserDelegate#parseConstructorArgElements
3.注册bean的beanName和对应的别名映射到缓存中(缓存:aliasMap)
注册默认的 filter
this.loadBeanDefinitions(beanDefinitionReader);
XmlWebApplicationContext#loadBeanDefinitions(XmlBeanDefinitionReader)
ContextLoader#initWebApplicationContext
int loadCount = loadBeanDefinitions(resources);
根据 Resource 加载 XML 配置文件,并解析成 Document 对象
NamespaceHandlerSupport#parse
遍历root的子节点列表
ComponentScanBeanDefinitionParser#configureScanner
beanName不为空
javax.servlet.ServletContextListener
beanName为空
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
6.组件注册(包括注册一些内部的注解后置处理器、触发注册事件)
默认命名空间节点的处理,例如: <bean id=\"test\" class=\"\" />
4.解析name-generator属性
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
NamespaceHandlerSupport#findParserForElement
3.使用拿到的handler解析节点(ParserContext用于存放解析需要的一些上下文信息)
this.loadBeanDefinitions(beanFactory);
如果 beanName不重复(一般不会重复),对于我们当前正在解析的 obtainFreshBeanFactory 方法来说,因为 bean 创建还未开始,因此会走到 3.2 进行缓存的注册。
registerBeanDefinition会将 beanName 添加到 beanDefinitionNames 缓存,将 beanName 和 BeanDefinition 的映射关系添加到beanDefinitionMap 缓存。
BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element)
接口ConfigurableApplicationContext#refresh
4.将bean定义、beanName、bean别名数组封装成BeanDefinitionHolder
AbstractBeanDefinitionReader#loadBeanDefinitions(String)
1.解析name和id属性,以及校验和为空时的设置
obtainFreshBeanFactory() 方法
BeanDefinitionParserDelegate#parsePropertyElements
将该 beanName 的 mergedBeanDefinitions 缓存信息删除、单例缓存删除。如果存在子 bean 定义,则递归重置。
5.使用scanner在指定的basePackages包中执行扫描,返回已注册的bean定义
3.遍历所有候选的bean定义
2.进一步解析bean的其他所有属性并统一封装至GenericBeanDefinition类型实例中
2.构建ClassPathBeanDefinitionScanner,将bean定义注册委托给scanner类
5.解析 property 子节点
ClassPathBeanDefinitionScanner#doScan
1.对import标签的处理2.对alias标签的处理3.对bean标签的处理(最复杂最重要)4.对beans标签的处理
0 条评论
回复 删除
下一页