从FileSystemXmlApplicationContext开始 ApplicationContext applicationContext = new FileSystemXmlApplicationContext(xmlPath); 由上面的入口进入到构造方法中 public FileSystemXmlApplicationContext(String configLocation) throws B
从FileSystemXmlApplicationContext开始
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(xmlPath);由上面的入口进入到构造方法中
public FileSystemXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } public FileSystemXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { //从此处开始IOC容器的初始化 refresh(); } }设置好配置资源的路径之后,就会调用refresh()方法进行容器的初始化
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { /** * 加载或刷新一个持久化的配置,可能是XML文件、属性文件或关系数据库模式。 * 由于这是一种启动方法,如果失败,应该销毁已经创建的单例,以避免悬空资源。 * 换句话说,在调用该方法之后,要么全部实例化,要么完全不实例化。 * @throws 如果bean工厂无法初始化,则抛出 BeansException 异常 * @throws 如果已经初始化且不支持多次刷新,则会抛出 IllegalStateException 异常 */ @Override public void refresh() throws BeansException, IllegalStateException { // 给容器refresh加锁,避免容器处在refresh阶段时,容器进行了初始化或者销毁的操作 synchronized (this.startupShutdownMonitor) { // 调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识,具体方法 prepareRefresh(); //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从 //子类的refreshBeanFactory()方法启动,里面有抽象方法 //针对xml配置,最终创建内部容器,该容器负责 Bean 的创建与管理,此步会进行BeanDefinition的注册 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 注册一些容器中需要的系统Bean.例如classloader,beanfactoryPostProcessor等 prepareBeanFactory(beanFactory); try { //允许容器的子类去注册postProcessor ,钩子方法 postProcessBeanFactory(beanFactory); // 激活在容器中注册为bean的BeanFactoryPostProcessors //对于注解容器,org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry //方法扫描应用中所有BeanDefinition并注册到容器之中 invokeBeanFactoryPostProcessors(beanFactory); // 注册拦截bean创建过程的BeanPostProcessor registerBeanPostProcessors(beanFactory); // 找到“messageSource”的Bean提供给ApplicationContext使用, // 使得ApplicationContext具有国际化能力。 initMessageSource(); // 初始化ApplicationEventMulticaster该类作为事件发布者, // 可以存储所有事件监听者信息,并根据不同的事件,通知不同的事件监听者。 initApplicationEventMulticaster(); // 预留给 AbstractApplicationContext 的子类用于初始化其他特殊的 bean, // 该方法需要在所有单例 bean 初始化之前调用 // 比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource) onRefresh(); // 注册监听器(检查监听器的bean并注册它们) registerListeners(); //设置自定义的类型转化器ConversionService, // 设置自定义AOP相关的类LoadTimeWeaverAware, // 清除临时的ClassLoader // ,实例化所有的类(懒加载的类除外) finishBeanFactoryInitialization(beanFactory); // 初始化容器的生命周期事件处理器,(默认使用DefaultLifecycleProcessor),调用扩展了SmartLifecycle接口的start方法 // 当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法) // 并发布容器刷新完毕事件ContextRefreshedEvent给对应的事件监听者 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. //销毁已创建的Bean destroyBeans(); // Reset 'active' flag. //取消refresh操作,重置容器的同步标识 cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // 重置Spring内核中的共用的缓存,因为我们可能再也不需要单例bean的元数据了…… resetCommonCaches(); } } } }AbstractApplicationContext的refresh()方法是容器刷新都会执行的方法,在refresh()方法里面配置的解析逻辑都在obtainFreshBeanFactory()方法中进行。
跟进obtainFreshBeanFactory方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //调用子类容器的refreshBeanFactory()刷新子类容器 refreshBeanFactory(); return getBeanFactory(); }跟进refreshBeanFactory()方法,该方法由其子类AbstractRefreshableApplicationContext提供
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { @Override protected final void refreshBeanFactory() throws BeansException { //如果已经有容器,销毁容器中的bean,关闭容器 if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //创建容器 DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); //对容器进行定制化,默认主要设置是否允许BeanDefinition的重复注册, // Bean之间是否允许循环引用等,此外还可以设置启动参数,开启注解的自动装配等 customizeBeanFactory(beanFactory); //加载BeanDefinition,for xml,使用了委派模式 loadBeanDefinitions(beanFactory); //将 BeanFactory 设置为 Spring 容器的内部 BeanFactory synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } }xml方式加载BeanDefinition,跟进loadBeanDefinitions(beanFactory)
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext { @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. // 1、为给定的BeanFactory创建一个新的XmlBeanDefinitionReader XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. // 2、设置 BeanDefinitionReader 的相关属性 // 2.1.设置 Environment,即环境,与容器的环境一致 beanDefinitionReader.setEnvironment(this.getEnvironment()); // 2.2.设置 ResourceLoader,即资源加载器,因为容器实现了该接口,具体加载资源的功能 beanDefinitionReader.setResourceLoader(this); // 2.3.设置 EntityResolver,即实体解析器,这里用于解析资源加载器加载的资源内容 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. // 3.初始化 BeanDefinitionReader ,空方法,允许子类提供阅读器的自定义初始化 // 钩子方法,允许子类在加载bean definition之前进一步设置XmlBeanDefinitionReader // ->比如,更改XmlBeanDefinitionReader自己提供的DocumentLoader // 或者BeanDefinitionDocumentReader等默认对象 initBeanDefinitionReader(beanDefinitionReader); // 4.通过 BeanDefinitionReader 加载 Bean loadBeanDefinitions(beanDefinitionReader); } }观察代码,该方法的主要目的是创建了BeanDefinitionReader ,并由它去加载 Bean。其过程如下:
- 创建 BeanDefinitionReader
- 设置 BeanDefinitionReader 的相关属性
- 初始化 BeanDefinitionReader
- 通过 BeanDefinitionReader 加载 Bean
通过 BeanDefinitionReader 加载 Bean
在创建完 BeanDefinitionReader 后,则就需要通过它来 加载 Bean,接着跟进loadBeanDefinitions(beanDefinitionReader)方法
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext { protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } } }接着跟进reader.loadBeanDefinitions(configLocations)
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable { @Override public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int count = 0; for (String location : locations) { count += loadBeanDefinitions(location); } return count; } }根据locations逐个调用loadBeanDefinitions(location)加载
通过 Location 加载 Bean
加载的 Bean 的责任被交给了 BeanDefinitionReader ,下面来看看该类的 loadBeanDefinitions 方法。在跟进loadBeanDefinitions(String location)方法
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable { @Override public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { return loadBeanDefinitions(location, null); } public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { // 1.取得资源加载器,即容器本身 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. // 说明该 ResourceLoader 可以基于路径加载多个资源 try { // 2.加载资源 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); // 3.通过 Resource 加载 Bean 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 { // Can only load single resources by absolute URL. // 表示 ResourceLoader 只能加载一个资源 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; } } }该方法的工作流程:
- 取得资源加载器
- 加载资源,通过 location 利用 ResourcePatternResolver加载
- 通过 Resource 加载 Bean
接着在跟进loadBeanDefinitions(resources)方法
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable { @Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int count = 0; for (Resource resource : resources) { count += loadBeanDefinitions(resource); } return count; } }通过 Resource 加载 Bean
在得到资源(Resource)后,该方法对它进行了封装,使其变成一个 EncodedResource 对象。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { @Override public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { // EncodedResource 表示编码类型的资源 return loadBeanDefinitions(new EncodedResource(resource)); } }通过 EncodedResource 加载 Bean
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { 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); } // 1.取得[已加载的资源]的集合,用于存在已加载的资源。空,则创建。 Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); // 2.将当前资源加入集合 if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } // 3.将资源转换成流 try (InputStream inputStream = encodedResource.getResource().getInputStream()) { //5.通过流创建 InputSource ,并设置编码 InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //6.调用同类方法,通过 InputSource 加载 Bean return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { // 移除已完成解析的资源 currentResources.remove(encodedResource); // 集合为空,则一并删除 if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } }加载步骤:
- 1、取得已加载的资源集合
- 2、将当前资源添加到集合
- 3、将资源转换成流
- 4、通过流创建 InputSource ,并设置编码
- 5、通过 InputSource 加载 Bean
通过 InputSource 加载 Bean
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { // 1.解析 XML 文件 //创建Document对象,XML的文档对象,就是dom树 // 使用这个Document可以获取XML文件中的节点并且创建节点 // SAX XML //将InputSource转换为DOM对象,解析过程由documentLoader实现 Document doc = doLoadDocument(inputSource, resource); // 2.注册 Bean //解析dom树,即解析出一个个属性,将其保存到BeanDefinition当中 //并向容器注册BeanDefinition int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } } }解析并注册 BeanDefinitions
将文件装换为Document以后,接下来的提取以及注册Bean就是我们的重头戏。 上一步中 XmlBeanDefinitionReader 已经取得了 XML 的 Document 对象,完成了资源的解析过程。
下一步就是 Bean 的注册过程。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //创建BeanDefinitionDocumentReader,这个是实际从XML的DOM树中读取BeanDefiniton BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //获取注册表beanDefinitionMap的在本次加载前的BeanDefinition数量 int countBefore = getRegistry().getBeanDefinitionCount(); //加载并注册 //这里使用到了单一职责原则,将逻辑处理委托给单一的类进行处理,这个逻辑处理类就是 BeanDefinitionDocumentReader 对象 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //本次加载注册后容器里BeanDefinition的数量减去先前的,即本次加载的BeanDefinition数量 return getRegistry().getBeanDefinitionCount() - countBefore; } }继续深入registerBeanDefinitions方法:
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { @Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; doRegisterBeanDefinitions(doc.getDocumentElement()); } }继续深入doRegisterBeanDefinitions方法:doRegisterBeanDefinitions算开始真正解析XML文件了。
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { protected void doRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. //BeanDefinition解析委托类 BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); //判断这个根节点是否是默认的命名空间 //底层就是判断这个根节点的NamespaceUrl=="http://www.springframework.org/schema/beans" if (this.delegate.isDefaultNamespace(root)) { //获取这个profile属性的值,表示剖面,用于设置环境 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); 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. //判断这个切面是否是激活的环境,如果不是直接返回,表示这个配置文件不是当前运行环境的配置文件 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; } } } //在解析xml之前做的准备工作,其实什么也没做 //空代码留给子类去实现 模板设计模式 继承 DefaultBeanDefinitionDocumentReader 的子类在XML解析前做一些处理,可以实现此方法 preProcessXml(root); //调用这个方法,解析 parseBeanDefinitions(root, this.delegate); //后续处理的 //空代码留给子类去实现 模板设计模式 继承 DefaultBeanDefinitionDocumentReader 的子类在XML解析后做一些处理,可以实现此方法 postProcessXml(root); this.delegate = parent; } }继续深入parseBeanDefinitions(root, this.delegate),进入到真正的解析逻辑里面对BeanDefinition进行解析
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //如果是默认的命名空间 if (delegate.isDefaultNamespace(root)) { //获取根节点下的所有子节点 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; //Bean定义的Document对象使用了Spring默认的XML命名空间,如http://www.springframework.org/schema/beans if (delegate.isDefaultNamespace(ele)) { //若是则按照spring原有的逻辑进行解析 parseDefaultElement(ele, delegate); } else { //否则使用扩展的自定义代理类进行解析 delegate.parseCustomElement(ele); } } } } else { //使用扩展的自定义代理类进行解析 delegate.parseCustomElement(root); } } }继续深入parseDefaultElement(ele, delegate),此方法会完成对标签的解析
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //如果元素节点是<Import>导入元素,进行导入解析 //<import resource="classpath:applicationContext-datasource.xml" /> if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } //如果元素节点是<Alias>别名元素,进行别名解析 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } //元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素, //按照Spring的Bean规则解析元素 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } //解析beans,递归调用doRegisterBeanDefinitions else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } } }继续深入processBeanDefinition(ele, delegate),此方法会真正解析出BeanDefinition
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类 //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //向Spring IOC容器注册解析得到的BeanDefinition,这是BeanDefinition向IOC容器注册的入口 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. // 在完成BeanDefinition注册之后,往容器发送注册完成的事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } } }- 由BeanDefinitionParserDelegate将解析出来的BeanDefinition封装到BeanDefinitionHolder中。
- 由BeanDefinitionReaderUtils的registerBeanDefinition方法将BeanDefinition注册到Spring IOC容器中。
- 最终调用DefaultListableBeanFactory类的registerBeanDefinition方法将beanDefinition注册到beanDefinitionMap中。
以上便是资源定位、加载、解析、注册的整个流程。
XML配置方式的BeanDefinition注册流程:
- 1、在FileSystemXmlApplicationContext的构造函数中设置配置资源的路径,接着调用refresh()方法进行容器的初始化。
- 2、refresh方法中的obtainFreshBeanFactory()方法进行配置的解析逻辑。
- 3、调用子类容器的refreshBeanFactory()刷新子类容器。
- 4、在AbstractRefreshableApplicationContext类的refreshBeanFactory方法中创建DefaultListableBeanFactory实例。
- 5、将DefaultListableBeanFactory实例作为参数传入到loadBeanDefinitions方法中。
- 6、在loadBeanDefinitions方法中通过DefaultListableBeanFactory创建XmlBeanDefinitionReader实例。
- 7、在loadBeanDefinitions方法中设置ResourceLoader用于加载资源,(即容器实例,容器实现了ResourceLoader接口)
- 8、通过BeanDefinitionReader加载Bean资源。
- 9、通过ResourcePatternResolver来加载资源,并通过EncodedResource包装资源实例。
- 10、XmlBeanDefinitionReader类的doLoadBeanDefinitions通过 InputSource加载Bean。
- 11、XmlBeanDefinitionReader类的doLoadDocument方法将xml解析成Document对象。
- 12、XmlBeanDefinitionReader类的registerBeanDefinitions方法创建BeanDefinitionDocumentReader实例。
- 13、在BeanDefinitionDocumentReader类的registerBeanDefinitions方法中,从Document对象中解析并注册BeanDefiniton。
- 14、DefaultBeanDefinitionDocumentReader类中的parseBeanDefinitions方法通过参数BeanDefinitionParserDelegate解析BeanDefinition。
- 15、DefaultBeanDefinitionDocumentReader类的parseDefaultElement按照spring原有的逻辑进行解析。
- 16、通过BeanDefinitionParserDelegate的parseBeanDefinitionElement解析出包含了BeanDefinition实例的BeanDefinitionHolder包装实例。
- 17、通过BeanDefinitionReaderUtils类的registerBeanDefinition方法将BeanDefinition实例注册到容器中,如果BeanDefinition是单例的化,之前已经注册过了的,就需要清空之前的注册信息。
- 18、使用beanName做唯一标识注册到DefaultListableBeanFactory类中的beanDefinitionMap中,有别名注册别名。
参考: https://www.cnblogs.com/moxiaotao/p/9349536.html
https://www.cnblogs.com/histlyb/p/8976635.html