本来这一篇是要写如何加载所有的单实例bean对象,但是回顾第二篇,发现对于解析xml文件加载bean定义信息的部分理解表达的并不是很好,所以在此补充一篇Spring解析配置文件,加载bean定义信息的文章。
1.以refresh()作为抓手
**refresh()**
作为容器的刷新方法,重要性不必多说,在里面的第二个方法**obtainFreshBeanFactory()**
里面,解析了xml配置文件或注解,载入bean定义资源信息,返回了一个全新的bean工厂。接下来来分析**obtainFreshBeanFactory()**
。
2.obtainFreshBeanFactory()
解析xml文件或者注解,加载bean 的定义信息,创建一个全新的bean工厂。
�
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新bean工厂
refreshBeanFactory();
/**返回bean工厂*/
return getBeanFactory();
}
3.refreshBeanFactory()
这里面主要就是判断当前有没有bean工厂,如果有的话,就把工厂关了,重新造一个,如果没有的话,直接造一个。总之一定要造一个新的工厂。**createBeanFactory()**
@Override
protected final void refreshBeanFactory() throws BeansException {
/*如果已经有了bean工厂,通常情况下并不会,什么情况下会有?通过applicationContext直接调用refresh方法*/
if (hasBeanFactory()) {
/*销毁里面的所有bean*/
destroyBeans();
/*关闭bean工厂*/
closeBeanFactory();
}
try {
//不管上面是否已经有bean工厂存在,最终都会走到这里,去创建一个bean工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
/*设置序列化id*/
beanFactory.setSerializationId(getId());
/*对工厂进行一些定制化设置*/
customizeBeanFactory(beanFactory);
/*加载bean的定义信息*/
loadBeanDefinitions(beanFactory);
/*将当前类的bean工厂引用指向创建的bean工厂*/
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
**createBeanFactory()**
返回一个全新的bean工厂。
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
每次容器刷新的时候尝试调用此方法。默认创建一个**DefaultListableBeanFactory**
,并将此上下文父级的内部bean工厂作为父bean工厂。
可以再子类中覆盖,例如自定义**DefaultListableBeanFactory**
的设置。
创建完工厂了,就要往工厂里面放东西,** loadBeanDefinitions(beanFactory)**
。
4.loadBeanDefinitions(beanFactory)
载入bean的定义信息 **beanDefinition**
。
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建一个xml 的beanDefinition加载器 这个玩意里面持有一个beanFactory的引用
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
/*给beanDefinition 加载器设置上下文环境 资源加载器 实体解析器*/
/*这玩意我记得都是用的默认的*/
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
/*初始化beanDefinition加载器*/
initBeanDefinitionReader(beanDefinitionReader);
/*使用beanDefinition加载器加载beanDefinitions*/
loadBeanDefinitions(beanDefinitionReader);
}
首先创建了一个bean定义信息的加载器 **XmlBeanDefinitionReader**
,用来解析xml文件。
然后给**XmlBeanDefinitionReader**
设置一些相关信息。
然后初始化 **XmlBeanDefinitionReader**
。**initBeanDefinitionReader(beanDefinitionReader)**
最后使用**XmlBeanDefinitionReader**
加载bean的定义信息。**loadBeanDefinitions(beanDefinitionReader)**
�
5.bean定义信息加载器
**XmlBeanDefinitionReader**
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
构造器里面传入了一个**BeanDefinitionRegistry**
,给父类**AbstractBeanDefinitionReader**
的属性赋值。
6.Bean定义信息注册器
**BeanDefinitionRegistry**
持有bean定义的注册表接口。例如_**RootBeanDefinition**_
和 _**ChildBeanDefinition**_
实例。
通常由在内部使用_**AbstractBeanDefinition**_
层次结构的**beanFactory**
实现。
这是spring的bean工厂中唯一封装**BeanDefinitionRegistry**
的接口。标准的**BeanFactory**
接口仅仅涵盖对完全配置的工厂的工厂实例的访问。
spring的**BeanDefinitionRegistry**
期待作用于该接口的实现。spring中已经有的实现是_**DefaultListableBeanFactory**_
& _**GenericApplicationContext**_
。
public interface BeanDefinitionRegistry extends AliasRegistry {
/*注册一个bean的定义信息,支持指定bean的名字*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
/*根据bean的名字移除掉已经注册的beanDefinition*/
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/*根据名字查找BeanDefinition*/
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/*判断是否包含给定名字的BeanDefinition信息*/
boolean containsBeanDefinition(String beanName);
/*返回已经注册的BeanDefinition名字列表*/
String[] getBeanDefinitionNames();
/*返回已经注册的BeanDefinition数量*/
int getBeanDefinitionCount();
/*确定给定的bean名称是否已经在注册中心使用, 怎么判断是否使用呢?就是是否有别名注册在此名称下,或者已经有注册在这里的bean。*/
boolean isBeanNameInUse(String beanName);
}
7.初始化beanDefinition的加载器
**initBeanDefinitionReader(beanDefinitionReader)**
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
reader.setValidating(this.validating);
}
初始化用于加载次上下文的beanDefinition的beanDefinitionReader。默认实现为空。可以再子类中覆盖,例如关闭xml验证或使用不同的_**XmlBeanDefinitionParser**_
实现。
8.加载bean的定义信息
**loadBeanDefinitions(beanDefinitionReader)**
使用给定的_**XmlBeanDefinitionReader**_
加载**beanDefinition**
。
**BeanFactory**
的生命周期由_**refreshBeanFactory() **_
处理,因此此方法仅用于加载和注册**beanDefinition**
。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
/*这里实际上是一个钩子方法,经典的模板模式,子类根据需要对方法进行重写,实际上加载xml的时候,这里锤子也没拿到*/
Resource[] configResources = getConfigResources();
/*如果资源不为空,走这里的逻辑,但是上面已经分析过,实际上锤子也没拿到,所以走下面的逻辑*/
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
/*获取配置文件位置*/
String[] configLocations = getConfigLocations();
/*此时读取到了我们在配置文件指定的配置文件 beans.xml*/
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
在这里我们注意两个方法:
**getConfigLocations()**
获取到配置文件的位置**reader.loadBeanDefinitions(configLocations)**
使用bean定义信息的加载器加载**beanDefinition**
。
@Nullable
protected String[] getConfigLocations() {
return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
}
返回一个资源位置数组,指的是构建此上下文应用的时候使用的 xml配置文件。还可以包括位置模式,这将通过_**ResourcePatternResolver**_
处理。默认实现返回null。子类可以重写这个方法用来提供一组资源位置来加载**beanDefinition**
。
9.reader.loadBeanDefinitions(configLocations)
用bean定义信息的加载器加载**beanDefinition**
。
�
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
/*断言 判空*/
Assert.notNull(locations, "Location array must not be null");
/*记录beanDefinition的数量*/
int count = 0;
/*迭代加载beanDefinition*/
for (String location : locations) {
count += loadBeanDefinitions(location);
}
return count;
}
这里是根据配置文件的位置数组进行循环迭代加载并记录**beanDefinition**
的数量。
来到了**AbstractBeanDefinitionReader**
的**loadBeanDefinitions()**
。
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
/*获取资源加载器*/
ResourceLoader resourceLoader = getResourceLoader();
/*如果资源加载器为空,抛异常*/
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
/*如果资源加载器是资源模式解析器类型的*/
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
/*
将xml配置文件加载到resources中,resource其实就是spring底层封装了很多的细节,
抽象出来的资源顶层接口
让开发人员不必专注于底层配置文件的加载细节
*/
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
/*加载beanDefinition*/
int count = loadBeanDefinitions(resources);
/*这玩意不知道是啥,反正是空,没啥锤子用*/
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}/*走到这里说明资源加载器肯定不是资源模式解析器类型的*/
else {
// 只能通过绝对网址加载单个资源
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
首先获取到资源的加载器,如果加载器是空,那就说明程序无法往下执行了,直接抛异常。
如果资源加载器是资源解析器模式的,加载xml文件到**Resource**
数组中,**Resource**
是什么在上一篇中已经介绍过了,在此不再赘述。
此时在根据**Resource**
数组去加载**beanDefinition**
,最后返回加载的**beanDefinition**
的数量。(注意:这里走的是else的逻辑,因为默认我们不是位置模式。)
注意这个时候思路已经很明确了,准备了这么多实际上到这里就分为了两步:
- 加载xml配置文件
**getResource(location)**
- 通过xml配置文件去加载
**beanDefinition**
**loadBeanDefinitions(resource)**
10.加载xml配置文件
来到**DefaultResourceLoader**
。
@Override
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
//循环遍历使用解析器解析该location的资源,如果资源不为空,直接返回
for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
/*以/开头那么根据path去寻找*/
if (location.startsWith("/")) {
return getResourceByPath(location);
}
/*以classpath开头,那么抽象为ClassPathResource*/
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
/*其他情况采用urlResource来加载*/
URL url = new URL(location);
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
}
}
11.加载beanDefinition
**loadBeanDefinitions(resource)**
来到了 **XmlBeanDefinitionReader**
。
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//1.将resource包装成带有编码格式的EncodedResource
//2.重载调用loadBeanDefinitions()
return loadBeanDefinitions(new EncodedResource(resource));
}
我们来到重载的方法。**loadBeanDefinitions(resource)**
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
//跳过断言 日志
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
//获取引用:当前线程已经加载过的encodingResource资源
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
//将当前的encodingResource加入到threadlocal的set中,加入失败说明当前资源已经加载过了,不能重复加载,需要抛出异常
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
//jdk新版本的语法糖 拿到资源的输入流
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
//因为接下来要使用 sax解析器,解析xml文件 ,所以需要将输入流包装成inputsource,
//inputsource是sax中表示资源的对象
InputSource inputSource = new InputSource(inputStream);
//设置字符编码 spring源码中判断逻辑特别多 ,稳定化的框架并不相信一切外部的输入
//这也是软件架构原则中的规范之一 稳定性体现
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//真正干活的逻辑 ,加载beanDefinition的入口
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
//因为resourcesCurrentlyBeingLoaded表示当前线程正在加载的redource
//执行到这里说明资源已经加载完了或者失败了
//所以需要将当前资源移除出去
currentResources.remove(encodedResource);
//set没有数据了,说明没啥乱用了,清理一下内存 防止threadlocal内存泄漏
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
这里使用了一个委派模式,将真正干活的逻辑交给了**doLoadBeanDefinitions()**
。
�
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//把 resource 转换成程序层面可以识别的有层次结构的document对象
Document doc = doLoadDocument(inputSource, resource);
//解析文档对象,生成beanDefinition注册到beanFactory中,最终返回新注册到beanFactory的beanDefinition数量
int count = registerBeanDefinitions(doc, resource);
//日志打印
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
//返回新注册 bean定义信息的数量
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
//这里省略部分catch的逻辑
}
这里再次分成了两步:
- 将
**Resource**
转换成**Document**
。**doLoadDocument(inputSource, resource)**
- 解析文档对象,生成
**beanDefinition**
注册到**BeanFactory**
。**registerBeanDefinitions(doc, resource)**
12.Resource转化成Document
**doLoadDocument(inputSource, resource)**
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
//这个方法就是将inputSource转化成可以识别的文档对象
//通过文档加载器来转化的
//1. getEntityResolver? 这个实体解析器
//spring官网说明:如果sax应用程序中需要实现自定义处理外部实体,则必须实现此接口并使用setEntityResolver方法向sax驱动器注册一个实例
//也就是说,对于解析一个xml,sax首先读取xml文档上的声明,根据声明去寻找相应的DTD/XSD定义,以便对文档进行一个校验。
//默认的寻找校验规则,即通过网络来下载响应的DTD/XSD声明,在进行校验。并且下载的过程是一个漫长且不可控的过程,当下在失败后,这里还会抛出异常
//那么有什么办法可以避免直接从网络上下载呢?使用EntityResolver
//EntityResolver的作用是项目本身可以提供一个如何寻找DTD/XSD声明的方法,即让程序来实现寻找定义声明的过程,比如我们将定义文件
//放到项目的某个地方,在实现时直接将此文件读取并返回给sax即可,这样避免了通过网络来寻找对应的声明。
//2.验证模式是怎么获取的?getValidationModeForResource()
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
**getValidationModeForResource(resource)**
protected int getValidationModeForResource(Resource resource) {
//获取默认的validationMode
int validationModeToUse = getValidationMode();
//条件成立:说明set过默认值,一般情况下,不会走这里,都是使用自动检测
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
//自动检查xml使用的是哪种验证模式?由这个方法决定
int detectedMode = detectValidationMode(resource);
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
// Hmm, we didn't get a clear indication... Let's assume XSD,
// since apparently no DTD declaration has been found up until
// detection stopped (before finding the document's root tag).
return VALIDATION_XSD;
}
**documentLoader.loadDocument()**
@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
**DocumentBuilder.parse() **
就是真正的解析逻辑。
13.解析文档对象注册到BeanFactory
**registerBeanDefinitions()**
解析文档对象,生成beanDefinition注册到beanFactory中,最终返回新注册到beanFactory的beanDefinition数量。
�
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建一个 BeanDefinitionDocumentReader 一对一处理 每个文档对象都会创建一个 BeanDefinitionDocumentReader 对象
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//getRegistry 会返回程序创建的beanFactory实例
//countBefore 解析doc之前,bf中已经有的bd数量
int countBefore = getRegistry().getBeanDefinitionCount();
//解析文档,并且注册到bf中
//xmlReaderContext :包含最主要的参数是当前 this -> xmlBeanDefinitionReader -> bf
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回值 返回新注册的bd数量 最新的 - 注册之前的
return getRegistry().getBeanDefinitionCount() - countBefore;
}
看重载的方法
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
//引用上下文对象
this.readerContext = readerContext;
//doc.getDocumentElement() 拿出文档代表的xml的顶层标签 <beans></beans>
/*真正的解析xml的逻辑*/
doRegisterBeanDefinitions(doc.getDocumentElement());
}
又是一个委派模式,终于来到了解析xml的逻辑,这里的逻辑其实没有什么可以学习的点,追到这里主要是为了串起来整个解析xml文件的流程,具体解析xml的过程不做重点说明。
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
//方法返回一个beans标签 解析器对象
this.delegate = createDelegate(getReaderContext(), root, parent);
//解析器对象去判断是不是默认的命名空间 一般情况下 条件成立
if (this.delegate.isDefaultNamespace(root)) {
//获取 profile 属性, 环境 Dev prod test
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
//条件成立 说明 beans 标签上 有 profile 属性
if (StringUtils.hasText(profileSpec)) {
//将属性值按照,拆分成字符串数组
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
// Environment.acceptsProfiles(String [] args) 条件成立 :说明beans 标签可以继续解析 bd
//这里取反 ,所以 就是 if里面整个条件成立 ,说明该 beans 标签不在继续解析 ,直接返回
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//这里是留给子类的扩展点
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
//这里也是留给子类扩展 体现的软件设计模式的开闭原则
postProcessXml(root);
this.delegate = parent;
}
已经走到了这里,大概看一下里面的逻辑。
**parseBeanDefinitions(root, this.delegate)**
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
/*条件成立说明root是spring缺省的命名空间*/
if (delegate.isDefaultNamespace(root)) {
/*这里获取的,大部分情况下,其实都是bean标签*/
NodeList nl = root.getChildNodes();
/*迭代处理每一个子标签*/
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
/*说明子标签也是默认的spring标签*/
if (delegate.isDefaultNamespace(ele)) {
/*默认标签解析逻辑 step into*/
parseDefaultElement(ele, delegate);
}/*自定义标签解析逻辑*/
else {
delegate.parseCustomElement(ele);
}
}
}
}/*root不是默认的命名空间,解析自定义标签逻辑*/
else {
delegate.parseCustomElement(root);
}
}
因为我们没有自定义标签,所以看默认标签的解析逻辑 **parseDefaultElement(ele, delegate)**
。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
/*条件成立,说明此时是import标签*/
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}/*条件成立说明是alias别名标签*/
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}/*此时说明是bean标签*/
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
/*解析bean标签*/
processBeanDefinition(ele, delegate);
}/*说明是嵌套beans标签*/
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 递归到上层重新来了
doRegisterBeanDefinitions(ele);
}
}
�继续看一下bean标签的解析逻辑**processBeanDefinition(ele, delegate)**
。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/*用解析器对象解析标签 hodler里面包含三个属性:beanDefinition,beanName,Alias别名信息*/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/*如果当前hodler需要被装饰,执行装饰逻辑 主要是处理自定义属性*/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
/*注册当前bean倒容器中 通过readerContext拿到XMLBeanDefinition拿到beanFactory*/
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
/*发送一个bean注册完成的事件*/
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
**BeanDefinitionReaderUtils.registerBeanDefinition()**
单实例bean的注册逻辑。
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
最终将**beanDefinition**
放到了**beanDefinitionMap**
里面,至此整个解析xml配置文件,加载**beanDefinition**
并返回全新**BeanFactory**
的逻辑结束了。