博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMVC 源代码深度解析 IOC容器(Bean 解析、注册)
阅读量:2447 次
发布时间:2019-05-10

本文共 21009 字,大约阅读时间需要 70 分钟。

      SpringMVC通过一个配置文件描述Bean以及Bean之间的依赖关系,利用java的反射机制实例化Bean并建立Bean之间的依赖关系。IOC容器在完成这些底层工作的基础还提供了Bean的实例缓、生命周期、Bean实例代理等。BeanFacorySpringMVC框架最核心的接口,他提供了最高级IOC的配置机制。ApplicationContextBeanFactory派生而来,这也说明了 SpringMVC容器中运行的主体对象是 Bean,另外 ApplicationContext 继承了 ResourceLoader 接口,使得 ApplicationContext 可以访问到任何外部资源,提供了更多面向实际应用的功能。SpringMVC初始化时在什么时候读取配置我们配置好的bean的文件,怎么解析和注册Bean接下来我们带着问题来分析。 

   上一篇,我们在介绍,父类FrameworkServlet在创建上下文时,调用了一个重启上下文时,并初始化Bean。如图所示:

   

  

ConfigurableWebApplicationContext wac;调用了wac.refresh();方法,完成了对ApplicationContext的初始化,注册啊,封装bean的工作,ConfigurableWebApplicationContext 的子类AbstractApplicationContext实现了bean初始化。我们来了解一下上下文(容器)整个继承关系。这边的箭头表示继承或者实现的,如图所示:

    从上图我们可以看出,ApplicationContext也是继承BeanFactoryApplicationContext 也继承了 ResourceLoader 接口,使得 ApplicationContext 可以访问到任何外部资源,提供了更多面向实际应用的功能,我们通过refresh为入口点,分析Bean整个初始化过程,并了解ApplicationContext的子类AbstractApplicationContext做了哪些工作并了解父类实现了哪些功能?每个接口都有他使用的场合,它主要是为了区分在 SpringMVC内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。我们现在先头脑中有这个继承的关系图,以后深度的了解,比较不会那么晕,这样思路就比较清晰,我们以refresh为入口点,带着这些问题进行解析。

  refresh方法的源代码如下:

  

public void refresh() throws BeansException, IllegalStateException {		synchronized (this.startupShutdownMonitor) {			// 准备对上下文进行刷新			prepareRefresh();			// 初始化beanFactory 			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();			// 为BeanFactory配置容器特性,例如类加载器、事件处理器等			prepareBeanFactory(beanFactory);			try {				// 为容器的某些子类指定特殊的BeanPost事件处理器				postProcessBeanFactory(beanFactory);				// 调用beanFactory处理器				invokeBeanFactoryPostProcessors(beanFactory);				// 注册beanFactory处理器				registerBeanPostProcessors(beanFactory);				// 初始化消息源				initMessageSource();				// 初始化上下文事件广播.				initApplicationEventMulticaster();				// 初始化其它特殊bean,由子类来实现				onRefresh();				// 注册事件监听器.				registerListeners();				// 初始化所有单实例的bean,使用懒加载除外				finishBeanFactoryInitialization(beanFactory);				// 完成刷新并发布容器刷新事件				finishRefresh();			}catch (BeansException ex) {				// Destroy already created singletons to avoid dangling resources.				destroyBeans();				// Reset 'active' flag.				cancelRefresh(ex);				// Propagate exception to caller.				throw ex;			}		}	}
  这个方法做了很多事情,主要有初始化
beanFactory 、注册
BeanFactory处理器等工作。我们接下来对里面重要的功能进行解析,它怎么读取我们配置文件并解析文件和注册配置文件里的bean。

     初始化beanFactory工厂时,就对读取我们配置文件并解析文件和注册配置文件里的Bean,是由AbstractApplicationContext.obtainFreshBeanFactory方法实现的,源代码如下:

     

**	 * Tell the subclass to refresh the internal bean factory.	 * @return the fresh BeanFactory instance	 * @see #refreshBeanFactory()	 * @see #getBeanFactory()	 */	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {		refreshBeanFactory();		ConfigurableListableBeanFactory beanFactory = getBeanFactory();		if (logger.isDebugEnabled()) {			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);		}		return beanFactory;	}
@Override	protected final void refreshBeanFactory() throws BeansException {		if (hasBeanFactory()) {			destroyBeans();			closeBeanFactory();		}		try {			DefaultListableBeanFactory beanFactory = createBeanFactory();			beanFactory.setSerializationId(getId());			customizeBeanFactory(beanFactory);			loadBeanDefinitions(beanFactory);			synchronized (this.beanFactoryMonitor) {				this.beanFactory = beanFactory;			}		}		catch (IOException ex) {			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);		}	}
 
 第一步:

     refreshBeanFactory 先销毁所有Bean,关闭BeanFactory,然后重新创建一个BeanFactory,并将其赋给BeanFactory实例变量。我们先看一下它怎么创建BeanFactory? 

    createBeanFactory这个方法是创建新的BeanBeanFactory ,BeanFactory 的原始对象是 DefaultListableBeanFactory,这个非常关键,因为他设计到后面对这个对象的多种操作,DefaultListableBeanFactory是整个Bean加载的核心部分,是SpringMVC注册及加载Bean的默认实现。

    

protected DefaultListableBeanFactory createBeanFactory() {return new DefaultListableBeanFactory(getInternalParentBeanFactory());}

   初始化BeanFactory时,判断是否有父BeanFactory,如果有设置,如果没有就为null

protected BeanFactory getInternalParentBeanFactory() {return (getParent() instanceof ConfigurableApplicationContext) ?((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();}

 获取父BeanFactory

  

public DefaultListableBeanFactory(BeanFactory parentBeanFactory) {super(parentBeanFactory);}public AbstractAutowireCapableBeanFactory(BeanFactory parentBeanFactory) {this();setParentBeanFactory(parentBeanFactory);}

setParentBeanFactory设置父BeanFactory

我们对BeanFactory继承关系了解一下,为后面的解析提供比较清晰的路线,如图所示:

  

  现在BeanFactory创建好了,
ApplicationContext 继承了BeanFactory,还
继承了 
ResourceLoader 
接口,使得 
ApplicationContext 
可以访问到任何外部资源,
提供了更多面向实际应用的功能,接下来我们进行第二步,分析解析配置文件和注册Bean。

 第二步:先转码在读取配置文件

     loadBeanDefinitions(beanFactory) 将找到答案,这个方法将开始加载、解析 Bean 的定义,也就是把用户定义的数据结构转化为 Ioc 容器中的特定数据结构。我们要分析一下这个方法。

       

@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 来读取并解析 xml 文件,XmlBeanDefinitionReader 是 BeanDefinitionReader 接口的实现。我们来看一下继承关系,如图所示:

      

 

   BeanDefinitionReader 读取Resource所指向的配置文件资源,然后解析配置文件,配置文件中每一个Bean解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中。我们这边先了解一下。先实现通过BeanFactory创建XmlBeanDefinitionReader对象,然后XmlBeanDefinitionReader 配置ResourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被使用,ResourceLoader对资源的加载。 如图所示:

  

我们现在获取外面的资源也设置好了,我们进行深入解析,loadBeanDefinitions方法源代码如下:

  

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {		String[] configLocations = getConfigLocations();		if (configLocations != null) {			for (String configLocation : configLocations) {				reader.loadBeanDefinitions(configLocation);			}		}	}
@Override	public String[] getConfigLocations() {		return super.getConfigLocations();	}
protected String[] getConfigLocations() {		return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());	}

   由 AbstractRefreshableWebApplicationContext父类AbstractRefreshableConfigApplicationContext实现getConfigLocations方法,获取了web.xml配置的param-value的值,然后getConfigLocations保存在数组里面。如图所示:

现在获取了param-value的值,接下去就开始读取配置文件,具体实现时由XmlBeanDefinitionReader父类AbstractBeanDefinitionReader实现的,

reader.loadBeanDefinitions(configLocation);源代码:

  

public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {		return loadBeanDefinitions(location, null);	} public int loadBeanDefinitions(String location, Set
actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } 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 loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
  这个方法有一个ResourcePatternResolver加载了
web.xml配置的
param-value对应的资源,例如
classpath:xxx*.xml 加载了
xxx下为
xml为后缀的文件资源,
loadBeanDefinitions进行对加载进来的资源进行解析。在解析之前先进行转码,是通过
EncodedResource
对资源文件进行转码,源代码如下: 

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {		return loadBeanDefinitions(new EncodedResource(resource));	}
   对
资源文件转码完,就开始读进来,以流的形式,源代码如下:

    

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {		Assert.notNull(encodedResource, "EncodedResource must not be null");		if (logger.isInfoEnabled()) {			logger.info("Loading XML bean definitions from " + encodedResource.getResource());		}		Set
currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet
(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }

  说明:

   (1getValidationModeForResource(resource);获取对XML文件的验证模式

   (2Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());加载XML文件,并获取对应的Document。这边是把配置文件读进来,以Document 形式存储。

   (3registerBeanDefinitions(doc, resource);解析并注册bean

       
第三步:解析并注册bean,解析 Bean 的定义,也就是把用户定义的数据结构转化为 Ioc 容器中的特定数据结构。

      我们继续第二步中先把文件读进来,接下来进行解析和注册是由registerBeanDefinitions(doc, resource);这个方法实现的,源代码如下:

        

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();		documentReader.setEnvironment(this.getEnvironment());		int countBefore = getRegistry().getBeanDefinitionCount();//统计前BeanDefinition加载个数		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));		return getRegistry().getBeanDefinitionCount() - countBefore;	}//解析并注册beanpublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {		this.readerContext = readerContext;		logger.debug("Loading bean definitions");		Element root = doc.getDocumentElement();		doRegisterBeanDefinitions(root);	}protected void doRegisterBeanDefinitions(Element root) {		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);		if (StringUtils.hasText(profileSpec)) {			Assert.state(this.environment != null, "Environment must be set for evaluating profiles");			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);			if (!this.environment.acceptsProfiles(specifiedProfiles)) {				return;			}		}		BeanDefinitionParserDelegate parent = this.delegate;		this.delegate = createDelegate(this.readerContext, root, parent);		preProcessXml(root);		parseBeanDefinitions(root, this.delegate);		postProcessXml(root);		this.delegate = parent;	}
 

  说明:

    (1public static final String PROFILE_ATTRIBUTE = "profile";判断bean节点是否定义了profile属性,如果有,就要到环境变量中去寻找

    (2BeanDefinitionParserDelegate是对BeanDefinition的解析的,这里就不具体分析了。

   (2) parseBeanDefinitions(root, this.delegate);bean注册到BeanDefinition对象中。

  这个 parseBeanDefinitions(root, this.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);		}	}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)) {			processBeanDefinition(ele, delegate);		}		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {			// recurse			doRegisterBeanDefinitions(ele);		}	}//我们来对处理bean标签进行分析  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));		}	}
 

 解析Beanidname等元素设置到BeanDefinition然后放到放到BeanDefinitionHolder中,这个是由parseBeanDefinitionElement进行处理的,源代码如下:

   
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {        //解析ID属性		String id = ele.getAttribute(ID_ATTRIBUTE);         //解析name属性		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);		List
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.isDebugEnabled()) { logger.debug("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.isDebugEnabled()) { logger.debug("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, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); //对class属性进行解析 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { //对parent属性进行解析 String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); //解析默认bean的各种属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //解析元数据 parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析构造函数 parseConstructorArgElements(ele, bd); //解析Property parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }

  对beanidnameclass等属性的解析并设置到BeanDefinition然后放到放到BeanDefinitionHolder中,并放入到IOC容器中建立对应的数据结构。

   现在IOC容器中已经建立对应的数据结构,接下来开始对bean进行注册,

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());源代码如下:

   

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 aliase : aliases) {				registry.registerAlias(beanName, aliase);			}		}	}   public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)			throws BeanDefinitionStoreException {		Assert.hasText(beanName, "Bean name must not be empty");		Assert.notNull(beanDefinition, "BeanDefinition must not be null");		if (beanDefinition instanceof AbstractBeanDefinition) {			try {				((AbstractBeanDefinition) beanDefinition).validate();			}			catch (BeanDefinitionValidationException ex) {				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,						"Validation of bean definition failed", ex);			}		}		synchronized (this.beanDefinitionMap) {			Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);			if (oldBeanDefinition != null) {				if (!this.allowBeanDefinitionOverriding) {					throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,							"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +							"': There is already [" + oldBeanDefinition + "] bound.");				}				else {					if (this.logger.isInfoEnabled()) {						this.logger.info("Overriding bean definition for bean '" + beanName +								"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");					}				}			}			else {				this.beanDefinitionNames.add(beanName);				this.frozenBeanDefinitionNames = null;			}			this.beanDefinitionMap.put(beanName, beanDefinition);		}		resetBeanDefinition(beanName);	}

   先检查是不是有相同名字的BeanDefinition已经在IoC容器中注册了,如果有相同名字的BeanDefinition,但又不允许覆盖,那么会抛出异常,如果可以可以覆盖,或者IOC容器中没注册,然后把Bean的名字存入到beanDefinitionNames的同时,把beanName作为Mapkey,beanDefinition作为value存入到IoC容器持有的BeanDefinitionMap中去。

总结:

   (1)SpringMVC先创建BeanFactory时销毁所有Bean,关闭BeanFactory,然后重新创建一个BeanFactory,并将其赋给BeanFactory实例变量。

   (2)创建好了BeanFactory,并设置好环境,ApplicationContext 继承了 ResourceLoader 接口,并通过ResourcePatternResolver加载了web.xml配置的param-value对应的资源,例如classpath:xxx*.xml 加载了xxx下为xml为后缀的文件资源,loadBeanDefinitions进行对加载进来的资源进行解析,在解析之前先进行转码,是通过EncodedResource对资源文件进行转码

   (3)对读取进来的配置文件进行验证,是否是XML格式的,然后配置文件中的Beanidnameclass等属性的解析并设置到BeanDefinition然后放到放到BeanDefinitionHolder中,并放入到IOC容器中建立对应的数据结构。是以Document形式的存储的。

    (4)在IOC容器中已经建立对应的数据结构,解析 Bean 的定义和注册,先检查是不是有相同名字的BeanDefinition已经在IoC容器中注册了,如果有相同名字的BeanDefinition,但又不允许覆盖,那么会抛出异常,如果可以可以覆盖,或者IOC容器中没注册,然后把Bean的名字存入到beanDefinitionNames的同时,把beanName作为Mapkey,beanDefinition作为value存入到IoC容器持有的BeanDefinitionMap中去。

 我们现在注册好,要实例化,还有Spring最核心的IOC依赖注入,怎么实例化并依赖注入,带着这些问题?下一篇我们继续解析。

   

 

你可能感兴趣的文章
windows终端终端_Windows终端介绍
查看>>
小额免密_如何在您的应用中进行小额付款
查看>>
用开源代码如何建立网站_建立全球开源法律网络
查看>>
c&c++语言参考手册_C ++值类别快速参考:第2部分
查看>>
javascript优化_优化性能的十大JavaScript技巧
查看>>
ruby on rails_Ruby on Rails在市场开发中的重要地位
查看>>
react 编程式路由_如何做React式编程。 第2部分:副作用
查看>>
传统网络面临问题_我们每天都面临的最流行的计算机问题
查看>>
aws cmake .._如何将Hyperledger Fabric 1.4部署到AWS
查看>>
机器人学数学理论_基于格理论的机器学习数学
查看>>
unity 场景优化_Unity优化:您的场景层次正在抢劫您
查看>>
如何制作电子邮件而不是一团糟:实用技巧
查看>>
px em rem区别_px,em,rem,%之间有什么区别? 答案在这里
查看>>
pvs-stdio ue4_云中的PVS-Studio:Azure DevOps
查看>>
理想商城_理想产品经理的52个特征
查看>>
移动应用程序开发_7种用于移动应用程序开发的终极编程语言
查看>>
本地应用程序_应用程式本地化的十大语言
查看>>
sds和c字符串比较_SDS虚拟化架构的简要比较
查看>>
java项目中出现的bug_2019年在Java项目中发现的十大bug
查看>>
app开发和web开发_理解现代Web App开发概念的指南
查看>>