Spring IoC容器的初始化过程

转载自:http://blog.csdn.net/u010723709/article/details/47046211
原题是:2 IOC容器初始化过程
作者:@小小旭GISer

===================================================================================================================================

IOC容器的初始化分为三个过程实现:

  • 第一个过程是Resource资源定位。这个Resouce指的是BeanDefinition的资源定位。这个过程就是容器找数据的过程,就像水桶装水需要先找到水一样。
  • 第二个过程是BeanDefinition的载入过程。这个载入过程是把用户定义好的Bean表示成Ioc容器内部的数据结构,而这个容器内部的数据结构就是BeanDefition。
  • 第三个过程是向IOC容器注册这些BeanDefinition的过程,这个过程就是将前面的BeanDefition保存到HashMap中的过程。

上面提到的过程一般是不包括Bean的依赖注入的实现。在Spring中,Bean的载入和依赖注入是两个独立的过程。依赖注入一般发生在应用第一次通过getBean向容器索取Bean的时候。下面的一张图描述了这三个过程调用的主要方法,图中的四个过程其实描述的是上面的第二个过程和第三个过程:

1 Resource定位

下面来看看主要的三个ApplicationContext的实现类是如何定位资源的,也就是找到我们通常所说“applicationContetx.xml”等配置文件的。

1.1 ClassPathXmlApplicationContext与FileSystemXmlApplicationContext

这两个类都是非Web容器时,常用的ApplicationContext类。他们很相似,所有的构造方法都在重载调用一段核心的代码。这段代码虽然很短,但是其中是一个很复杂的执行过程,它完成了IOC容器的初始化。

  1. super(parent);  
  2.         setConfigLocations(configLocations);  
  3.         if (refresh) {  
  4.             refresh();  
  5.         }  
super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}

这其中的setConfigLocations方法就是在进行资源定位。这个方法在AbstractRefreshableConfigApplicationContext类中实现。这个方法首先进行了非空了检验。这个Assert是Spring框架的一个工具类,这里面进行了一个非空判断。然后对这个路径进行了一些处理。这样就完成了资源的定位。这个定位其实就是使用者主动把配置文件的位置告诉Spring框架。

  1. if (locations != null) {  
  2.             Assert.noNullElements(locations, "Config locations must not be null");  
  3.             this.configLocations = new String[locations.length];  
  4.             for (int i = 0; i < locations.length; i++) {  
  5.                 this.configLocations[i] = resolvePath(locations[i]).trim();  
  6.             }  
  7.         }  
  8.         else {  
  9.             this.configLocations = null;  
  10.         }  
if (locations != null) {
			Assert.noNullElements(locations, "Config locations must not be null");
			this.configLocations = new String[locations.length];
			for (int i = 0; i < locations.length; i++) {
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
			this.configLocations = null;
		}

1.2 XmlWebApplicationContext

这个类是web容器初始化spring IOC容器的类。对于web应用来说,我们通常是不是直接去初始化这个容器的,它的装载是一个自动进行的过程。这是因为我们在web.xml中配置了这样一句话,这其实就是spring的入口

  1. <listener>  
  2.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  3.     </listener>  
<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>


(1)下面来看这个类ContextLoaderListener,从它的定义就能看出,这是一个ServletContextListener,它的核心方法就是下面的contextInitialized事件,也就是当web容器初始化的时候,spring容器也进行了初始化。

  1. public class ContextLoaderListener extends ContextLoader implements ServletContextListener  
public class ContextLoaderListener extends ContextLoader implements ServletContextListener

  1. /** 
  2.  * Initialize the root web application context. 
  3.  */  
  4. @Override  
  5. public void contextInitialized(ServletContextEvent event) {  
  6.     initWebApplicationContext(event.getServletContext());  
  7. }  
	/**
	 * Initialize the root web application context.
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}
这个方法将servletContext作为参数传入,它的目标就是为了读取web.xml配置文件,找到我们对spring的配置。

(2)下面来看initWebApplicationContext方法,它完成了对webApplictionContext的初始化工作。这个方法里的有比较重要的几段代码,他们主要完成了webAppliction构建,参数的注入,以及保存

  • 构建webApplictionContext
  1. if (this.context == null) {  
  2.                 this.context = createWebApplicationContext(servletContext);  
  3.             }  
if (this.context == null) {
				this.context = createWebApplicationContext(servletContext);
			}

这段代码看字面意思就知道是新建了一个webApplicationContext。它是由一个工具类产生一个新的wac,这个方法中调用了determineContextClass方法,它决定了容器初始化为哪种类型的ApplicationContext,因为我们可以在web.xml中对这种类型进行指定。而如果没有指定的话,就将使用默认的XmlWebApplicationContext。

  1. protected Class<?> determineContextClass(ServletContext servletContext) {  
  2.         String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);  
  3.         if (contextClassName != null) {  
  4.             try {  
  5.                 return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());  
  6.             }  
  7.             catch (ClassNotFoundException ex) {  
  8.                 throw new ApplicationContextException(  
  9.                         "Failed to load custom context class [" + contextClassName + "]", ex);  
  10.             }  
  11.         }  
  12.         else {  
  13.             contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());  
  14.             try {  
  15.                 return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());  
  16.             }  
  17.             catch (ClassNotFoundException ex) {  
  18.                 throw new ApplicationContextException(  
  19.                         "Failed to load default context class [" + contextClassName + "]", ex);  
  20.             }  
  21.         }  
  22.     }  
protected Class<?> determineContextClass(ServletContext servletContext) {
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
		if (contextClassName != null) {
			try {
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load custom context class [" + contextClassName + "]", ex);
			}
		}
		else {
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load default context class [" + contextClassName + "]", ex);
			}
		}
	}

  • 注入参数,初始化这个空的容器 。这个过程的入口是configureAndRefreshWebApplicationContext这个方法中完成了wac的Id设置,将servletContext注入到wac中,还有最重要的方法,就是setConfigLocation.这里从web.xml中寻找指定的配置文件的位置,也就是我们通常配置的“contextConfigLocation”属性

  1. String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);  
  2.         if (configLocationParam != null) {  
  3.             wac.setConfigLocation(configLocationParam);  
  4.         }  
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);
		}

那么如果没有指定呢?在XMLWebApplicationContext中这样一些常量,他们表示了配置文件的默认位置

  1. /** Default config location for the root context */  
  2.     public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";  
  3.   
  4.     /** Default prefix for building a config location for a namespace */  
  5.     public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";  
  6.   
  7.     /** Default suffix for building a config location for a namespace */  
  8.     public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";  
/** Default config location for the root context */
	public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

	/** Default prefix for building a config location for a namespace */
	public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";

	/** Default suffix for building a config location for a namespace */
	public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";





  • spring容器初始化完成后,放入serverletContext中,这样在web容器中就可以拿到applicationContext


  1. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);  
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

2 BeanDefinition载入

这个过程是最繁琐,也是最重要的一个过程。这一个过程分为以下几步,

  • 构造一个BeanFactory,也就是IOC容器
  • 调用XML解析器得到document对象
  •  按照Spring的规则解析BeanDefition

对于以上过程,都需要一个入口,也就是前面提到的refresh()方法,这个方法AbstractApplicationContext类中,它描述了整个ApplicationContext的初始化过程,比如BeanFactory的更新,MessgaeSource和PostProcessor的注册等等。它更像是个初始化的提纲,这个过程为Bean的声明周期管理提供了条件。


  1. public void refresh() throws BeansException, IllegalStateException {  
  2.         synchronized (this.startupShutdownMonitor) {  
  3.             // Prepare this context for refreshing.  
  4.             prepareRefresh();  
  5.   
  6.             // Tell the subclass to refresh the internal bean factory.  
  7.             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  8.   
  9.             // Prepare the bean factory for use in this context.  
  10.             prepareBeanFactory(beanFactory);  
  11.   
  12.             try {  
  13.                 // Allows post-processing of the bean factory in context subclasses.  
  14.                 postProcessBeanFactory(beanFactory);  
  15.   
  16.                 // Invoke factory processors registered as beans in the context.  
  17.                 invokeBeanFactoryPostProcessors(beanFactory);  
  18.   
  19.                 // Register bean processors that intercept bean creation.  
  20.                 registerBeanPostProcessors(beanFactory);  
  21.   
  22.                 // Initialize message source for this context.  
  23.                 initMessageSource();  
  24.   
  25.                 // Initialize event multicaster for this context.  
  26.                 initApplicationEventMulticaster();  
  27.   
  28.                 // Initialize other special beans in specific context subclasses.  
  29.                 onRefresh();  
  30.   
  31.                 // Check for listener beans and register them.  
  32.                 registerListeners();  
  33.   
  34.                 // Instantiate all remaining (non-lazy-init) singletons.  
  35.                 finishBeanFactoryInitialization(beanFactory);  
  36.   
  37.                 // Last step: publish corresponding event.  
  38.                 finishRefresh();  
  39.             }  
  40.   
  41.             catch (BeansException ex) {  
  42.                 logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);  
  43.   
  44.                 // Destroy already created singletons to avoid dangling resources.  
  45.                 destroyBeans();  
  46.   
  47.                 // Reset 'active' flag.  
  48.                 cancelRefresh(ex);  
  49.   
  50.                 // Propagate exception to caller.  
  51.                 throw ex;  
  52.             }  
  53.         }  
  54.     }  
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) {
				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;
			}
		}
	}

2.1 构建IOC容器

这个过程的入口是refresh方法中的obtainFreshBeanFactory()方法。整个过程构建了一个DefaultListableBeanFactory对象,这也就是IOC容器的实际类型。这一过程的核心如下:

2.1.1 obtainFreshBeanFactory

这个方法的作用是通知子类去初始化ioc容器,它调用了AbstractRefreshableApplicationContext的refreshBeanFactory 方法 进行后续工作。同时在日志是debug模式的时候,向日志输出初始化结果。

  1. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  
  2.         refreshBeanFactory();  
  3.         ConfigurableListableBeanFactory beanFactory = getBeanFactory();  
  4.         if (logger.isDebugEnabled()) {  
  5.             logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  
  6.         }  
  7.         return beanFactory;  
  8.     }  
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

2.1.2 refreshBeanFactory

这个方法在创建IOC容器前,如果已经有容器存在,那么需要将已有的容器关闭和销毁,保证refresh之后使用的是新建立的容器。同时 在创建了空的IOC容器后,开始了对BeanDefitions的载入

  1. protected final void refreshBeanFactory() throws BeansException {  
  2.         if (hasBeanFactory()) {  
  3.             destroyBeans();  
  4.             closeBeanFactory();  
  5.         }  
  6.         try {  
  7.             DefaultListableBeanFactory beanFactory = createBeanFactory();//创建了IOC容器  
  8.             beanFactory.setSerializationId(getId());  
  9.             customizeBeanFactory(beanFactory);  
  10.             loadBeanDefinitions(beanFactory);// 启动对BeanDefitions的载入  
  11.             synchronized (this.beanFactoryMonitor) {  
  12.                 this.beanFactory = beanFactory;  
  13.             }  
  14.         }  
  15.         catch (IOException ex) {  
  16.             throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);  
  17.         }  
  18.     }  
protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();//创建了IOC容器
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);// 启动对BeanDefitions的载入
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
  1. protected DefaultListableBeanFactory createBeanFactory() {  
  2.         return new DefaultListableBeanFactory(getInternalParentBeanFactory());  
  3.     }  
protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

2.2 解析XML文件

对于Spring,我们通常使用xml形式的配置文件定义Bean,在对BeanDefition载入之前,首先需要进行的就是XML文件的解析。整个过程的核心方法如下:



2.2.1 loadBeanDefinitions(DefaultListableBeanFactory beanFactory)

这里构造一个XmlBeanDefinitionReader对象,把解析工作交给他去实现

  1. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {  
  2.         // 定义一个XmlBeanDefinitionReader对象 用于解析XML  
  3.         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
  4.   
  5.         //进行一些初始化和环境配置  
  6.         // Configure the bean definition reader with this context's  
  7.         // resource loading environment.  
  8.         beanDefinitionReader.setEnvironment(this.getEnvironment());  
  9.         beanDefinitionReader.setResourceLoader(this);  
  10.         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
  11.   
  12.         // Allow a subclass to provide custom initialization of the reader,  
  13.         // then proceed with actually loading the bean definitions.  
  14.         initBeanDefinitionReader(beanDefinitionReader);  
  15.         //解析入口  
  16.         loadBeanDefinitions(beanDefinitionReader);  
  17.     }  
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// 定义一个XmlBeanDefinitionReader对象 用于解析XML
		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);
	}

2.2.2 loadBeanDefinitions

(1) AbstractXmlApplicationContext类 ,利用reader的方法解析,向下调用(Load the bean definitions with the given XmlBeanDefinitionReader.)

  1. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {  
  2.         Resource[] configResources = getConfigResources();  
  3.         if (configResources != null) {  
  4.             reader.loadBeanDefinitions(configResources);  
  5.         }  
  6.         String[] configLocations = getConfigLocations();  
  7.         if (configLocations != null) {  
  8.             reader.loadBeanDefinitions(configLocations);  
  9.         }  
  10.     }  
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);
		}
	}
(2) AbstractBeanDefinitionReader 类 解析Resource  向下调用
  1. public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {  
  2.         Assert.notNull(resources, "Resource array must not be null");  
  3.         int counter = 0;  
  4.         for (Resource resource : resources) {  
  5.             counter += loadBeanDefinitions(resource);  
  6.         }  
  7.         return counter;  
  8.     }  
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
		Assert.notNull(resources, "Resource array must not be null");
		int counter = 0;
		for (Resource resource : resources) {
			counter += loadBeanDefinitions(resource);
		}
		return counter;
	}
(3) XmlBeanDefinitionReader 

  1. public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {  
  2.         return loadBeanDefinitions(new EncodedResource(resource));  
  3.     }  
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}
在下面方法得到了XML文件,并打开IO流,准备进行解析。实际向下调用
  1. public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {  
  2.         Assert.notNull(encodedResource, "EncodedResource must not be null");  
  3.         if (logger.isInfoEnabled()) {  
  4.             logger.info("Loading XML bean definitions from " + encodedResource.getResource());  
  5.         }  
  6.   
  7.         Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();  
  8.         if (currentResources == null) {  
  9.             currentResources = new HashSet<EncodedResource>(4);  
  10.             this.resourcesCurrentlyBeingLoaded.set(currentResources);  
  11.         }  
  12.         if (!currentResources.add(encodedResource)) {  
  13.             throw new BeanDefinitionStoreException(  
  14.                     "Detected cyclic loading of " + encodedResource + " - check your import definitions!");  
  15.         }  
  16.         try {  
  17.             InputStream inputStream = encodedResource.getResource().getInputStream();  
  18.             try {  
  19.                 InputSource inputSource = new InputSource(inputStream);  
  20.                 if (encodedResource.getEncoding() != null) {  
  21.                     inputSource.setEncoding(encodedResource.getEncoding());  
  22.                 }  
  23.                 return doLoadBeanDefinitions(inputSource, encodedResource.getResource());  
  24.             }  
  25.             finally {  
  26.                 inputStream.close();  
  27.             }  
  28.         }  
  29.         catch (IOException ex) {  
  30.             throw new BeanDefinitionStoreException(  
  31.                     "IOException parsing XML document from " + encodedResource.getResource(), ex);  
  32.         }  
  33.         finally {  
  34.             currentResources.remove(encodedResource);  
  35.             if (currentResources.isEmpty()) {  
  36.                 this.resourcesCurrentlyBeingLoaded.remove();  
  37.             }  
  38.         }  
  39.     }  
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<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<EncodedResource>(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();
			}
		}
	}

(4) doLoadBeanDefinitions

下面是它的核心方法,第一句调用Spring解析XML的方法得到document对象,而第二句则是载入BeanDefitions的入口

  1. try {  
  2.             Document doc = doLoadDocument(inputSource, resource);  
  3.             return registerBeanDefinitions(doc, resource);  
  4.         }  
try {
			Document doc = doLoadDocument(inputSource, resource);
			return registerBeanDefinitions(doc, resource);
		}

2.3 解析Spring数据结构

这一步是将document对象解析成spring内部的bean结构,实际上是AbstractBeanDefinition对象。这个对象的解析结果放入BeanDefinitionHolder中,而整个过程是由BeanDefinitionParserDelegate完成。

2.3.1 registerBeanDefinitions

解析BeanDefinitions的入口,向下调用doRegisterBeanDefinitions方法

  1. public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {  
  2.         this.readerContext = readerContext;  
  3.         logger.debug("Loading bean definitions");  
  4.         Element root = doc.getDocumentElement();  
  5.         doRegisterBeanDefinitions(root);  
  6.     }  
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
		Element root = doc.getDocumentElement();
		doRegisterBeanDefinitions(root);
	}

2.3.2 doRegisterBeanDefinitions

定义了BeanDefinitionParserDelegate 解析处理器对象,向下调用parseBeanDefinitions 方法

  1. protected void doRegisterBeanDefinitions(Element root) {  
  2.         // Any nested <beans> elements will cause recursion in this method. In  
  3.         // order to propagate and preserve <beans> default-* attributes correctly,  
  4.         // keep track of the current (parent) delegate, which may be null. Create  
  5.         // the new (child) delegate with a reference to the parent for fallback purposes,  
  6.         // then ultimately reset this.delegate back to its original (parent) reference.  
  7.         // this behavior emulates a stack of delegates without actually necessitating one.  
  8.         BeanDefinitionParserDelegate parent = this.delegate;  
  9.         this.delegate = createDelegate(getReaderContext(), root, parent);  
  10.   
  11.         if (this.delegate.isDefaultNamespace(root)) {  
  12.             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);  
  13.             if (StringUtils.hasText(profileSpec)) {  
  14.                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(  
  15.                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);  
  16.                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {  
  17.                     return;  
  18.                 }  
  19.             }  
  20.         }  
  21.   
  22.         preProcessXml(root);  
  23.         parseBeanDefinitions(root, this.delegate);  
  24.         postProcessXml(root);  
  25.   
  26.         this.delegate = parent;  
  27.     }  
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);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					return;
				}
			}
		}

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

		this.delegate = parent;
	}

2.3.3 parseBeanDefinitions

从document对象的根节点开始,依据不同类型解析。具体调用parseDefaultElement和parseCustomElement两个方法进行解析。这个主要的区别是因为bean的命名空间可能不同,Spring的默认命名空间是“http://www.springframework.org/schema/beans”,如果不是这个命名空间中定义的bean,将使用parseCustomElement方法。

  1. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {  
  2.         if (delegate.isDefaultNamespace(root)) {  
  3.             NodeList nl = root.getChildNodes();  
  4.             for (int i = 0; i < nl.getLength(); i++) {  
  5.                 Node node = nl.item(i);  
  6.                 if (node instanceof Element) {  
  7.                     Element ele = (Element) node;  
  8.                     if (delegate.isDefaultNamespace(ele)) {  
  9.                         parseDefaultElement(ele, delegate);  
  10.                     }  
  11.                     else {  
  12.                         delegate.parseCustomElement(ele);  
  13.                     }  
  14.                 }  
  15.             }  
  16.         }  
  17.         else {  
  18.             delegate.parseCustomElement(root);  
  19.         }  
  20.     }  
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);
		}
	}

2.3.4 parseDefaultElement

这个方法就是根据bean的类型进行不同的方法解析。

  1. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {  
  2.         //解析import  
  3.         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {  
  4.             importBeanDefinitionResource(ele);  
  5.         }  
  6.         //解析alias  
  7.         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {  
  8.             processAliasRegistration(ele);  
  9.         }  
  10.         //解析普通的bean  
  11.         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {  
  12.             processBeanDefinition(ele, delegate);  
  13.         }  
  14.         //解析beans  递归返回  
  15.         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {  
  16.             // recurse  
  17.             doRegisterBeanDefinitions(ele);  
  18.         }  
  19.     }  
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);
		}
		//解析beans  递归返回
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}


2.3.5 processBeanDefinition

这个方法完成对普通,也是最常见的Bean的解析。这个方法实际上完成了解析和注册两个过程。这两个过程分别向下调用parseBeanDefinitionElement和registerBeanDefinition方法。

  1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {  
  2.         //定义BeanDefinitionHolder对象 ,完成解析的对象存放在这个对象里面  
  3.         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  
  4.         if (bdHolder != null) {  
  5.             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  
  6.             try {  
  7.                 // 向容器注册解析完成的Bean  
  8.                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  
  9.             }  
  10.             catch (BeanDefinitionStoreException ex) {  
  11.                 getReaderContext().error("Failed to register bean definition with name '" +  
  12.                         bdHolder.getBeanName() + "'", ele, ex);  
  13.             }  
  14.             // Send registration event.  
  15.             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  
  16.         }  
  17.     }  
  18.       
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		//定义BeanDefinitionHolder对象 ,完成解析的对象存放在这个对象里面
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 向容器注册解析完成的Bean
				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));
		}
	}
	

2.3.6 parseBeanDefinitionElement

定义在BeanDefinitionParserDelegate 类中,完成了BeanDefition解析工作。在这里可以看到,AbstractBeanDefinition实际上spring的内部保存的数据结构

  1. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {  
  2.         String id = ele.getAttribute(ID_ATTRIBUTE);  
  3.         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);  
  4.   
  5.         List<String> aliases = new ArrayList<String>();  
  6.         if (StringUtils.hasLength(nameAttr)) {  
  7.             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);  
  8.             aliases.addAll(Arrays.asList(nameArr));  
  9.         }  
  10.   
  11.         String beanName = id;  
  12.         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {  
  13.             beanName = aliases.remove(0);  
  14.             if (logger.isDebugEnabled()) {  
  15.                 logger.debug("No XML 'id' specified - using '" + beanName +  
  16.                         "' as bean name and " + aliases + " as aliases");  
  17.             }  
  18.         }  
  19.   
  20.         if (containingBean == null) {  
  21.             checkNameUniqueness(beanName, aliases, ele);  
  22.         }  
  23.   
  24.         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  
  25.         if (beanDefinition != null) {  
  26.             if (!StringUtils.hasText(beanName)) {  
  27.                 try {  
  28.                     if (containingBean != null) {  
  29.                         beanName = BeanDefinitionReaderUtils.generateBeanName(  
  30.                                 beanDefinition, this.readerContext.getRegistry(), true);  
  31.                     }  
  32.                     else {  
  33.                         beanName = this.readerContext.generateBeanName(beanDefinition);  
  34.                         // Register an alias for the plain bean class name, if still possible,  
  35.                         // if the generator returned the class name plus a suffix.  
  36.                         // This is expected for Spring 1.2/2.0 backwards compatibility.  
  37.                         String beanClassName = beanDefinition.getBeanClassName();  
  38.                         if (beanClassName != null &&  
  39.                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&  
  40.                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {  
  41.                             aliases.add(beanClassName);  
  42.                         }  
  43.                     }  
  44.                     if (logger.isDebugEnabled()) {  
  45.                         logger.debug("Neither XML 'id' nor 'name' specified - " +  
  46.                                 "using generated bean name [" + beanName + "]");  
  47.                     }  
  48.                 }  
  49.                 catch (Exception ex) {  
  50.                     error(ex.getMessage(), ele);  
  51.                     return null;  
  52.                 }  
  53.             }  
  54.             String[] aliasesArray = StringUtils.toStringArray(aliases);  
  55.             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  
  56.         }  
  57.   
  58.         return null;  
  59.     }  
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<String>();
		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;
	}

  1. /** 
  2.      * Parse the bean definition itself, without regard to name or aliases. May return 
  3.      * {@code null} if problems occurred during the parsing of the bean definition. 
  4.      */  
  5.     public AbstractBeanDefinition parseBeanDefinitionElement(  
  6.             Element ele, String beanName, BeanDefinition containingBean) {  
  7.   
  8.         this.parseState.push(new BeanEntry(beanName));  
  9.   
  10.         String className = null;  
  11.         if (ele.hasAttribute(CLASS_ATTRIBUTE)) {  
  12.             className = ele.getAttribute(CLASS_ATTRIBUTE).trim();  
  13.         }  
  14.   
  15.         try {  
  16.             String parent = null;  
  17.             if (ele.hasAttribute(PARENT_ATTRIBUTE)) {  
  18.                 parent = ele.getAttribute(PARENT_ATTRIBUTE);  
  19.             }  
  20.             AbstractBeanDefinition bd = createBeanDefinition(className, parent);  
  21.   
  22.             parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);  
  23.             bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));  
  24.   
  25.             parseMetaElements(ele, bd);  
  26.             parseLookupOverrideSubElements(ele, bd.getMethodOverrides());  
  27.             parseReplacedMethodSubElements(ele, bd.getMethodOverrides());  
  28.   
  29.             parseConstructorArgElements(ele, bd);  
  30.             parsePropertyElements(ele, bd);  
  31.             parseQualifierElements(ele, bd);  
  32.   
  33.             bd.setResource(this.readerContext.getResource());  
  34.             bd.setSource(extractSource(ele));  
  35.   
  36.             return bd;  
  37.         }  
  38.         catch (ClassNotFoundException ex) {  
  39.             error("Bean class [" + className + "] not found", ele, ex);  
  40.         }  
  41.         catch (NoClassDefFoundError err) {  
  42.             error("Class that bean class [" + className + "] depends on not found", ele, err);  
  43.         }  
  44.         catch (Throwable ex) {  
  45.             error("Unexpected failure during bean definition parsing", ele, ex);  
  46.         }  
  47.         finally {  
  48.             this.parseState.pop();  
  49.         }  
  50.   
  51.         return null;  
  52.     }  
/**
	 * Parse the bean definition itself, without regard to name or aliases. May return
	 * {@code null} if problems occurred during the parsing of the bean definition.
	 */
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, BeanDefinition containingBean) {

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

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

		try {
			String parent = null;
			if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
				parent = ele.getAttribute(PARENT_ATTRIBUTE);
			}
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

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

2.4 注册BeanDefition

完成了上面的三步后,目前ApplicationContext中有两种类型的结构,一个是DefaultListableBeanFactory,它是Spring IOC容器,另一种是若干个BeanDefinitionHolder,这里面包含实际的Bean对象,AbstractBeanDefition。

需要把二者关联起来,这样Spring才能对Bean进行管理。在DefaultListableBeanFactory中定义了一个Map对象,保存所有的BeanDefition。这个注册的过程就是把前面解析得到的Bean放入这个Map的过程。

  1. /** Map of bean definition objects, keyed by bean name */  
  2.     private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);  
/** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);




2.4.1 registerBeanDefinition

注册的入口,对于普通的Bean和Alias调用不同类型的注册方法进行注册。

  1. public static void registerBeanDefinition(  
  2.             BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)  
  3.             throws BeanDefinitionStoreException {  
  4.   
  5.         // Register bean definition under primary name.  
  6.         String beanName = definitionHolder.getBeanName();  
  7.         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());  
  8.   
  9.         // Register aliases for bean name, if any.  
  10.         String[] aliases = definitionHolder.getAliases();  
  11.         if (aliases != null) {  
  12.             for (String alias : aliases) {  
  13.                 registry.registerAlias(beanName, alias);  
  14.             }  
  15.         }  
  16.     }  
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);
			}
		}
	}

2.4.2 registerBeanDefinition

注册Bean 定义在DefaultListableBeanFactory中

  1. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)  
  2.             throws BeanDefinitionStoreException {  
  3.         //非空断言  
  4.         Assert.hasText(beanName, "Bean name must not be empty");  
  5.         Assert.notNull(beanDefinition, "BeanDefinition must not be null");  
  6.   
  7.         if (beanDefinition instanceof AbstractBeanDefinition) {  
  8.             try {  
  9.                 ((AbstractBeanDefinition) beanDefinition).validate();  
  10.             }  
  11.             catch (BeanDefinitionValidationException ex) {  
  12.                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
  13.                         "Validation of bean definition failed", ex);  
  14.             }  
  15.         }  
  16.   
  17.         BeanDefinition oldBeanDefinition;  
  18.   
  19.         oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
  20.         //同名检测  
  21.         if (oldBeanDefinition != null) {  
  22.             //是否能够覆盖检测  
  23.             if (!this.allowBeanDefinitionOverriding) {  
  24.                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
  25.                         "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +  
  26.                         "': There is already [" + oldBeanDefinition + "] bound.");  
  27.             }  
  28.             else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {  
  29.                 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE  
  30.                 if (this.logger.isWarnEnabled()) {  
  31.                     this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +  
  32.                             " with a framework-generated bean definition ': replacing [" +  
  33.                             oldBeanDefinition + "] with [" + beanDefinition + "]");  
  34.                 }  
  35.             }  
  36.             else {  
  37.                 if (this.logger.isInfoEnabled()) {  
  38.                     this.logger.info("Overriding bean definition for bean '" + beanName +  
  39.                             "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");  
  40.                 }  
  41.             }  
  42.         }  
  43.         else {  
  44.             this.beanDefinitionNames.add(beanName);  
  45.             this.manualSingletonNames.remove(beanName);  
  46.             this.frozenBeanDefinitionNames = null;  
  47.         }  
  48.         //放入Map中  
  49.         this.beanDefinitionMap.put(beanName, beanDefinition);  
  50.   
  51.         if (oldBeanDefinition != null || containsSingleton(beanName)) {  
  52.             resetBeanDefinition(beanName);  
  53.         }  
  54.     }  
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);
			}
		}

		BeanDefinition oldBeanDefinition;

		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 (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
							" with a framework-generated bean definition ': replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
		}
		else {
			this.beanDefinitionNames.add(beanName);
			this.manualSingletonNames.remove(beanName);
			this.frozenBeanDefinitionNames = null;
		}
		//放入Map中
		this.beanDefinitionMap.put(beanName, beanDefinition);

		if (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

2.4.3 registerAlias

定义在SimpleAliasRegistry类,对别名进行注册

  1. public void registerAlias(String name, String alias) {  
  2.         Assert.hasText(name, "'name' must not be empty");  
  3.         Assert.hasText(alias, "'alias' must not be empty");  
  4.         if (alias.equals(name)) {  
  5.             this.aliasMap.remove(alias);  
  6.         }  
  7.         else {  
  8.             if (!allowAliasOverriding()) {  
  9.                 String registeredName = this.aliasMap.get(alias);  
  10.                 if (registeredName != null && !registeredName.equals(name)) {  
  11.                     throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +  
  12.                             name + "': It is already registered for name '" + registeredName + "'.");  
  13.                 }  
  14.             }  
  15.             checkForAliasCircle(name, alias);  
  16.             this.aliasMap.put(alias, name);  
  17.         }  
  18.     }  
public void registerAlias(String name, String alias) {
		Assert.hasText(name, "'name' must not be empty");
		Assert.hasText(alias, "'alias' must not be empty");
		if (alias.equals(name)) {
			this.aliasMap.remove(alias);
		}
		else {
			if (!allowAliasOverriding()) {
				String registeredName = this.aliasMap.get(alias);
				if (registeredName != null && !registeredName.equals(name)) {
					throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
							name + "': It is already registered for name '" + registeredName + "'.");
				}
			}
			checkForAliasCircle(name, alias);
			this.aliasMap.put(alias, name);
		}
	}






















  • 11
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值