Spring源码分析系列----ClassPathXmlApplicationContext加载xml中bean定义注册容器的执行过程分析

本篇分析经典ClassPathXmlApplicationContext加载指定xml中bean定义注册到BeanFactory的执行过程分析,通过debug方式分析spring调用栈。

  1. 确定beanfactory是具体哪个实现

        我们知道applicationContext是用外观模式代理内部持有的BeanFactory,那具体是创建的哪个BeanFactory实现对象呢?来分析一下,看一下ApplicationContext的继承体系,如图1

图1
图1

   通过ApplicationContext的getBean()方法跟进去看一下,他的实现是在AbstractApplicationContext的getBean()方法,如图2

图2

 再看getBeanFactory()方法,这是个抽象方法,实现自ConfigurableApplicationContext接口,如图3

图3

 查看它的实现方法,有两个类实现了,AbstractRefreshableApplicationContext和GenericApplicationContext,正好对应图1的继承体系。而我们classpathXmlApplicationContext继承自AbstractRefreshableApplicationContext,所以来看一下图4、图5

图4

 

 

图5
 

 可以确定了真正的BeanFactory是DefaultListableBeanFactory。

    2. 找到DefaultListableBeanFactory注定bean定义的方法 registerBeanDefinition()方法,并打上断点。如图6

图6
 

3. 编写测试类,如图7

 

图7

其他实体类和xml配置省略。另因为我们测试的是bean name为“swk”,所以断点可以设置条件为"swk".equals(beanName)如图8

 

图8
 

 4.运行测试,逐步查看调用栈如图9

图9

5.观察类名,细分调用栈, 可分为4大步骤,如图10

图10
 

第一步是在ClassPathXmlApplicationContext、AbstractApplicationContext、AbstarctRefreshableApplicationContext、AbstractXmlApplicationContext

第二步是在AbstractBeanDefinitionReader、XmlBeanDefinitionReader

第三步是在DefaultBeanDefinitionDocumentReader

第四步是在BeanDefinitionReaderUtils、DefaultListableBeanFactory

6. 依次看看每一步都做了什么,先看第一步

    关键代码refresh()方法,如图11

图11
 

 而refresh()方法是在AbstractApplicationContext的方法,如下

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				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.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

refresh()方法主要采用模板方法,规定了applicationContext容器刷新步骤,由子类实现自己方法。之后会详细介绍每个方法,现在主要根据调用栈来看obtainFreshBeanFactory()。该方法是获得刷新后的beanFactory,详细看一下,如图12

图12
 

 先刷新bean工厂,然后获得bean工厂。

refreshBeanFactory()方法如刚才所说是模板方法的抽象方法,子类AbstractRefreshableApplicationContext实现如下

@Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

可以看到刷新bean工厂就是先销毁之前的bean工厂,然后创建新的DefaultListableBeanFactory,并且设置this.beanFactory为该bean工厂。回到obtainFreshBeanFactory()方法看,refreshBeanFactory()方法之后,返回该bean工厂,调用的是getBeanFactory()方法,该方法在abstractRefreshApplicationContext中的实现如下,

@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
		DefaultListableBeanFactory beanFactory = this.beanFactory;
		if (beanFactory == null) {
			throw new IllegalStateException("BeanFactory not initialized or already closed - " +
					"call 'refresh' before accessing beans via the ApplicationContext");
		}
		return beanFactory;
	}

可以看到,就是返回的this.beanFactory.

好了,现在外层逻辑理清了,那么我们再来看创建完DefaultListableBeanFactory之后,是怎么把xml中的bean定义注册到bean工厂中的呢?

关键方法loadBeanDefinitions(beanFactory)。

refreshBeanFactory()方法中创建完DefaultListableBeanFactory后,执行loadBeanDefinitions(beanFactory),加载bean定义并且注册到beanFactory。

具体实现AbstractXmlApplicationContext,代码如下

@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}

可以看到此处是创建了一个XmlBeanDefinitionReader,并且将beanFactory传进去,看一下该构造方法,代码如下

public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
		super(registry);
	}



调用父类AbstractBeanDefinitionReader构造方法,代码如下

protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		this.registry = registry;

		// Determine ResourceLoader to use.
		if (this.registry instanceof ResourceLoader) {
			this.resourceLoader = (ResourceLoader) this.registry;
		}
		else {
			this.resourceLoader = new PathMatchingResourcePatternResolver();
		}

		// Inherit Environment if possible
		if (this.registry instanceof EnvironmentCapable) {
			this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
		}
		else {
			this.environment = new StandardEnvironment();
		}
	}

可以看到此处最终是将beanFactory作为BeanDefinitionRegistry(DefaultListableBeanFactory实现了BeanDefinitionRegistry)赋值给this.registry

private final BeanDefinitionRegistry registry;

所以此时创建出来的XmlBeanDefinitionReader的registry属性持有了DefaultListableBeanFactory

继续走调用栈,调用AbstractXmlApplicationContext的loadBeanDefinitions(beanDefinitionReader)方法,代码如下

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);
		}
	}
继续走调用栈此时调用XmlBeanDefinitionReader的loadBeanDefinitions(configLocations)方法。第一部分classpathXmlApplicationContext类的方法走完,进入XmlBeanDefinitionReader类第二部分

7.第二步,XmlBeanDefinitionReader类

经过一系列转换把String的xml路径资源转换为加载Resource

AbstractBeanDefinitionReader的loadBeanDefinitions(location,actualResources),代码如下

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 {
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				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.
			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;
		}
	}
getResourceLoader获取的是ClasspathXmlApplicationContext 它也是个ResourceLoader

然后调用

Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

得到resources数组

进一步调用到XmlBeanDefinitionReader 的loadBeanDefinitions(Resouce resource)方法

进一步调用XmlBeanDefinitionReader 的doLoadBeanDefinitions(inputSource,Resource)方法

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			Document doc = doLoadDocument(inputSource, resource);
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
}

该方法中将inputSource、resource转换为w3c的Document,从而可以解析xml文档

进一步调到XmlBeanDefinitionReader的registerBeanDefinitions(Document doc,Resource resource)方法

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

该方法创建了一个BeanDefinitionDocumentReader bean定义文档读取器,并且通过createReaderContext(resource)方法创建了XmlReaderContext,createReaderContext代码如下

public XmlReaderContext createReaderContext(Resource resource) {
		return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
				this.sourceExtractor, this, getNamespaceHandlerResolver());
	}

XmlReaderContext构造方法如下

public XmlReaderContext(
			Resource resource, ProblemReporter problemReporter,
			ReaderEventListener eventListener, SourceExtractor sourceExtractor,
			XmlBeanDefinitionReader reader, NamespaceHandlerResolver namespaceHandlerResolver) {

		super(resource, problemReporter, eventListener, sourceExtractor);
		this.reader = reader;
		this.namespaceHandlerResolver = namespaceHandlerResolver;
	}

可以看到在创建XmlReaderContext创建过程中,把XmlBeanDefinitionReader本身传进XmlReaderContext的this.reader属性

再来看BeanDefinitionDocumentReader 的registerBeanDefinitions(Document,XmlReaderContext)方法,实际是DefaultBeanDefinitionDocumentReader实现

@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}

将刚才创建的XmlReaderContext传进DefaultBeanDefinitionDocumentReader的this.readerContext属性。

所以可以得出这样的属性调用链,DefaultBeanDefinitionDocumentReader 有XmlReaderContext属性 ==》XmlReaderContext中有XmlBeanDefinitionReader属性==》XmlBeanDefinitionReader中有BeanDefinitionRegistry属性,而被赋值的BeanDefinitionRegistry就是创建的DefaultListableBeanFactory

继续看调用链 ,调用DefaultBeanDefinitionDocumentReader  的  doRegisterBeanDefinitions(Element)方法

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.
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		if (this.delegate.isDefaultNamespace(root)) {
			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;
				}
			}
		}

		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}

看createDelegate(getReaderContext(),root,parent)方法

protected BeanDefinitionParserDelegate createDelegate(
			XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {

		BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
		delegate.initDefaults(root, parentDelegate);
		return delegate;
	}

创建了BeanDefinitionParserDelegate(readerContext)代理,查看此构造函数

public BeanDefinitionParserDelegate(XmlReaderContext readerContext) {
		Assert.notNull(readerContext, "XmlReaderContext must not be null");
		this.readerContext = readerContext;
	}

可以看到将DefaultBeanDefinitionDocumentReader的xmlReaderContext属性复制到BeanDefinitionParserDelegate的XmlReaderContext属性,所以之前的属性调用链变为:

BeanDefinitionParserDelegate 有XmlReaderContext属性 ==》DefaultBeanDefinitionDocumentReader 有XmlReaderContext属性 ==》XmlReaderContext中有XmlBeanDefinitionReader属性==》XmlBeanDefinitionReader中有BeanDefinitionRegistry属性,而被赋值的BeanDefinitionRegistry就是创建的DefaultListableBeanFactory

继续走调用链 DefaultBeanDefinitionDocumentReader 的 parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法

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;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

此处走的是parseDefaultElement(ele,delegate)方法,插一句,如果是aop等非默认标签,则走delegate.parseCustomElement(ele),有兴趣可以详细查看

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

此处element元素肯定是bean标签,所以走的肯定是processBeanDefinition(ele,delegate)方法

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

此处delegate.parseBeanDefinitionElement(ele)创建了BeanDefinitionHolder bean定义持有器,我们跟进去查看创建的是什么beanDefinition

@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isTraceEnabled()) {
				logger.trace("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}

		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}

		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
					if (logger.isTraceEnabled()) {
						logger.trace("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}
public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, @Nullable BeanDefinition containingBean)方法调用
@Nullable
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

		this.parseState.push(new BeanEntry(beanName));

		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

查看createBeanDefinition方法

protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
			throws ClassNotFoundException {

		return BeanDefinitionReaderUtils.createBeanDefinition(
				parentName, className, this.readerContext.getBeanClassLoader());
	}

继续走

public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

		GenericBeanDefinition bd = new GenericBeanDefinition();
		bd.setParentName(parentName);
		if (className != null) {
			if (classLoader != null) {
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}

终于看到了 创建的是GenericBeanDefinition.
继续走调用链 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry())

查看getReaderContext()方法和getRegistry方法

protected final XmlReaderContext getReaderContext() {
		Assert.state(this.readerContext != null, "No XmlReaderContext available");
		return this.readerContext;
	}

public final BeanDefinitionRegistry getRegistry() {
		return this.reader.getRegistry();
	}

可以得知就是得到的defaultListableBeanFactory

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);
			}
		}
	}

终于走到最后一步

registry.registerBeanDefinition(beanName,BeanDefinition)

至此,走到了bean工厂注册bean定义。

8.总结

  1. 通过AbstractApplicationContext的refresh()方法获得DefaultListableBeanFactory
  2. 创建XmlBeanDefinitionReader,并将DefaultListableBeanFactory作为BeanDefinitionRegistry复制给register属性。同时ClasspathXmlApplicationContext作为ResourceLoader赋值给resourceLoader属性
  3. XmlBeanDefinitionReader将string的xml地址通过resourceLoader转换为Resource资源
  4. XmlBeanDefinitionReader用w3c解析创建Document,并创建DefaultBeanDefinitionDocumentReader,读取xml文档
  5. DefaultBeanDefinitionDocumentReader 创建BeanDefinitionParserDelegate代理
  6. BeanDefinitionParserDelegate创建bean定义为GenericBeanDefinition,封装为BeanDefinitionHolder
  7. 最后通过BeanDefinitionReaderUtils把bean定义注册到DefaultListableBeanFactory
  8. DefaultListableBeanFactory在各关键类中属性的调用链,BeanDefinitionParserDelegate 有XmlReaderContext属性 ==》DefaultBeanDefinitionDocumentReader 有XmlReaderContext属性 ==》XmlReaderContext中有XmlBeanDefinitionReader属性==》XmlBeanDefinitionReader中有BeanDefinitionRegistry属性,而被赋值的BeanDefinitionRegistry就是创建的DefaultListableBeanFactory
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值