spring ioc容器初始化

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容器的初始化。

[java] view plain copy

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

  2. setConfigLocations(configLocations);

  3. if (refresh) {

  4. refresh();

  5. }


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

[java] view plain copy

  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.         }  
 
  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. }

1.2 XmlWebApplicationContext

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

[html] view plain copy

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

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

  3. </listener>


 

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

[java] view plain copy

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

[java] view plain copy

  1. /** 
  2.  * Initialize the root web application context. 
  3.  */  
  4. @Override  
  5. public void contextInitialized(ServletContextEvent event) {  
  6.     initWebApplicationContext(event.getServletContext());  
  7. }  
 
  1. /**

  2. * Initialize the root web application context.

  3. */

  4. @Override

  5. public void contextInitialized(ServletContextEvent event) {

  6. initWebApplicationContext(event.getServletContext());

  7. }

这个方法将servletContext作为参数传入,它的目标就是为了读取web.xml配置文件,找到我们对spring的配置。

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

  • 构建webApplictionContext

[java] view plain copy

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

  2. this.context = createWebApplicationContext(servletContext);

  3. }

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

[java] view plain copy

  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.     }  
 
  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. }

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

[java] view plain copy

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

  2. if (configLocationParam != null) {

  3. wac.setConfigLocation(configLocationParam);

  4. }


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

[java] view plain copy

  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";  
 
  1. /** Default config location for the root context */

  2. public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

  3. /** Default prefix for building a config location for a namespace */

  4. public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";

  5. /** Default suffix for building a config location for a namespace */

  6. public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";


 


 

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

[java] view plain copy

  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的声明周期管理提供了条件。

[java] view plain copy

  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.     }  
 
  1. public void refresh() throws BeansException, IllegalStateException {

  2. synchronized (this.startupShutdownMonitor) {

  3. // Prepare this context for refreshing.

  4. prepareRefresh();

  5. // Tell the subclass to refresh the internal bean factory.

  6. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

  7. // Prepare the bean factory for use in this context.

  8. prepareBeanFactory(beanFactory);

  9. try {

  10. // Allows post-processing of the bean factory in context subclasses.

  11. postProcessBeanFactory(beanFactory);

  12. // Invoke factory processors registered as beans in the context.

  13. invokeBeanFactoryPostProcessors(beanFactory);

  14. // Register bean processors that intercept bean creation.

  15. registerBeanPostProcessors(beanFactory);

  16. // Initialize message source for this context.

  17. initMessageSource();

  18. // Initialize event multicaster for this context.

  19. initApplicationEventMulticaster();

  20. // Initialize other special beans in specific context subclasses.

  21. onRefresh();

  22. // Check for listener beans and register them.

  23. registerListeners();

  24. // Instantiate all remaining (non-lazy-init) singletons.

  25. finishBeanFactoryInitialization(beanFactory);

  26. // Last step: publish corresponding event.

  27. finishRefresh();

  28. }

  29. catch (BeansException ex) {

  30. logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

  31. // Destroy already created singletons to avoid dangling resources.

  32. destroyBeans();

  33. // Reset 'active' flag.

  34. cancelRefresh(ex);

  35. // Propagate exception to caller.

  36. throw ex;

  37. }

  38. }

  39. }

2.1 构建IOC容器

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

2.1.1 obtainFreshBeanFactory

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

[java] view plain copy

  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.     }  
 
  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. }

2.1.2 refreshBeanFactory

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

[java] view plain copy

  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.     }  
 
  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. }

[java] view plain copy

  1. protected DefaultListableBeanFactory createBeanFactory() {  
  2.         return new DefaultListableBeanFactory(getInternalParentBeanFactory());  
  3.     }  
 
  1. protected DefaultListableBeanFactory createBeanFactory() {

  2. return new DefaultListableBeanFactory(getInternalParentBeanFactory());

  3. }

2.2 解析XML文件

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

2.2.1 loadBeanDefinitions(DefaultListableBeanFactory beanFactory)

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

[java] view plain copy

  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.     }  
 
  1. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

  2. // 定义一个XmlBeanDefinitionReader对象 用于解析XML

  3. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

  4. //进行一些初始化和环境配置

  5. // Configure the bean definition reader with this context's

  6. // resource loading environment.

  7. beanDefinitionReader.setEnvironment(this.getEnvironment());

  8. beanDefinitionReader.setResourceLoader(this);

  9. beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

  10. // Allow a subclass to provide custom initialization of the reader,

  11. // then proceed with actually loading the bean definitions.

  12. initBeanDefinitionReader(beanDefinitionReader);

  13. //解析入口

  14. loadBeanDefinitions(beanDefinitionReader);

  15. }

2.2.2 loadBeanDefinitions

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

[java] view plain copy

  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.     }  
 
  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. }

(2) AbstractBeanDefinitionReader 类 解析Resource  向下调用

[java] view plain copy

  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.     }  
 
  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. }

(3) XmlBeanDefinitionReader 

[java] view plain copy

  1. public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {  
  2.         return loadBeanDefinitions(new EncodedResource(resource));  
  3.     }  
 
  1. public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {

  2. return loadBeanDefinitions(new EncodedResource(resource));

  3. }

在下面方法得到了XML文件,并打开IO流,准备进行解析。实际向下调用

[java] view plain copy

  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.     }  
 
  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. Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

  7. if (currentResources == null) {

  8. currentResources = new HashSet<EncodedResource>(4);

  9. this.resourcesCurrentlyBeingLoaded.set(currentResources);

  10. }

  11. if (!currentResources.add(encodedResource)) {

  12. throw new BeanDefinitionStoreException(

  13. "Detected cyclic loading of " + encodedResource + " - check your import definitions!");

  14. }

  15. try {

  16. InputStream inputStream = encodedResource.getResource().getInputStream();

  17. try {

  18. InputSource inputSource = new InputSource(inputStream);

  19. if (encodedResource.getEncoding() != null) {

  20. inputSource.setEncoding(encodedResource.getEncoding());

  21. }

  22. return doLoadBeanDefinitions(inputSource, encodedResource.getResource());

  23. }

  24. finally {

  25. inputStream.close();

  26. }

  27. }

  28. catch (IOException ex) {

  29. throw new BeanDefinitionStoreException(

  30. "IOException parsing XML document from " + encodedResource.getResource(), ex);

  31. }

  32. finally {

  33. currentResources.remove(encodedResource);

  34. if (currentResources.isEmpty()) {

  35. this.resourcesCurrentlyBeingLoaded.remove();

  36. }

  37. }

  38. }


(4) doLoadBeanDefinitions

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

[java] view plain copy

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

  2. Document doc = doLoadDocument(inputSource, resource);

  3. return registerBeanDefinitions(doc, resource);

  4. }

2.3 解析Spring数据结构

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

2.3.1 registerBeanDefinitions

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

[java] view plain copy

  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.     }  
 
  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. }

2.3.2 doRegisterBeanDefinitions

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

[java] view plain copy

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

  11. String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);

  12. if (StringUtils.hasText(profileSpec)) {

  13. String[] specifiedProfiles = StringUtils.tokenizeToStringArray(

  14. profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);

  15. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {

  16. return;

  17. }

  18. }

  19. }

  20. preProcessXml(root);

  21. parseBeanDefinitions(root, this.delegate);

  22. postProcessXml(root);

  23. this.delegate = parent;

  24. }

2.3.3 parseBeanDefinitions

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

[java] view plain copy

  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.     }  
 
  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. }

2.3.4 parseDefaultElement

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

[java] view plain copy

  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.     }  
 
  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. }

2.3.5 processBeanDefinition

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

[java] view plain copy

  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.       
 
  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. }

2.3.6 parseBeanDefinitionElement

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

[java] view plain copy

  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.     }  
 
  1. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {

  2. String id = ele.getAttribute(ID_ATTRIBUTE);

  3. String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

  4. List<String> aliases = new ArrayList<String>();

  5. if (StringUtils.hasLength(nameAttr)) {

  6. String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);

  7. aliases.addAll(Arrays.asList(nameArr));

  8. }

  9. String beanName = id;

  10. if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {

  11. beanName = aliases.remove(0);

  12. if (logger.isDebugEnabled()) {

  13. logger.debug("No XML 'id' specified - using '" + beanName +

  14. "' as bean name and " + aliases + " as aliases");

  15. }

  16. }

  17. if (containingBean == null) {

  18. checkNameUniqueness(beanName, aliases, ele);

  19. }

  20. AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);

  21. if (beanDefinition != null) {

  22. if (!StringUtils.hasText(beanName)) {

  23. try {

  24. if (containingBean != null) {

  25. beanName = BeanDefinitionReaderUtils.generateBeanName(

  26. beanDefinition, this.readerContext.getRegistry(), true);

  27. }

  28. else {

  29. beanName = this.readerContext.generateBeanName(beanDefinition);

  30. // Register an alias for the plain bean class name, if still possible,

  31. // if the generator returned the class name plus a suffix.

  32. // This is expected for Spring 1.2/2.0 backwards compatibility.

  33. String beanClassName = beanDefinition.getBeanClassName();

  34. if (beanClassName != null &&

  35. beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&

  36. !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {

  37. aliases.add(beanClassName);

  38. }

  39. }

  40. if (logger.isDebugEnabled()) {

  41. logger.debug("Neither XML 'id' nor 'name' specified - " +

  42. "using generated bean name [" + beanName + "]");

  43. }

  44. }

  45. catch (Exception ex) {

  46. error(ex.getMessage(), ele);

  47. return null;

  48. }

  49. }

  50. String[] aliasesArray = StringUtils.toStringArray(aliases);

  51. return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);

  52. }

  53. return null;

  54. }

[java] view plain copy

  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.     }  
 
  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. this.parseState.push(new BeanEntry(beanName));

  8. String className = null;

  9. if (ele.hasAttribute(CLASS_ATTRIBUTE)) {

  10. className = ele.getAttribute(CLASS_ATTRIBUTE).trim();

  11. }

  12. try {

  13. String parent = null;

  14. if (ele.hasAttribute(PARENT_ATTRIBUTE)) {

  15. parent = ele.getAttribute(PARENT_ATTRIBUTE);

  16. }

  17. AbstractBeanDefinition bd = createBeanDefinition(className, parent);

  18. parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

  19. bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

  20. parseMetaElements(ele, bd);

  21. parseLookupOverrideSubElements(ele, bd.getMethodOverrides());

  22. parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

  23. parseConstructorArgElements(ele, bd);

  24. parsePropertyElements(ele, bd);

  25. parseQualifierElements(ele, bd);

  26. bd.setResource(this.readerContext.getResource());

  27. bd.setSource(extractSource(ele));

  28. return bd;

  29. }

  30. catch (ClassNotFoundException ex) {

  31. error("Bean class [" + className + "] not found", ele, ex);

  32. }

  33. catch (NoClassDefFoundError err) {

  34. error("Class that bean class [" + className + "] depends on not found", ele, err);

  35. }

  36. catch (Throwable ex) {

  37. error("Unexpected failure during bean definition parsing", ele, ex);

  38. }

  39. finally {

  40. this.parseState.pop();

  41. }

  42. return null;

  43. }

2.4 注册BeanDefition

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

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

[java] view plain copy

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

  2.     private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);

2.4.1 registerBeanDefinition

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

[java] view plain copy

  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.     }  
 
  1. public static void registerBeanDefinition(

  2. BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

  3. throws BeanDefinitionStoreException {

  4. // Register bean definition under primary name.

  5. String beanName = definitionHolder.getBeanName();

  6. registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

  7. // Register aliases for bean name, if any.

  8. String[] aliases = definitionHolder.getAliases();

  9. if (aliases != null) {

  10. for (String alias : aliases) {

  11. registry.registerAlias(beanName, alias);

  12. }

  13. }

  14. }

2.4.2 registerBeanDefinition

注册Bean 定义在DefaultListableBeanFactory中

[java] view plain copy

  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.     }  
 
  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. if (beanDefinition instanceof AbstractBeanDefinition) {

  7. try {

  8. ((AbstractBeanDefinition) beanDefinition).validate();

  9. }

  10. catch (BeanDefinitionValidationException ex) {

  11. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,

  12. "Validation of bean definition failed", ex);

  13. }

  14. }

  15. BeanDefinition oldBeanDefinition;

  16. oldBeanDefinition = this.beanDefinitionMap.get(beanName);

  17. //同名检测

  18. if (oldBeanDefinition != null) {

  19. //是否能够覆盖检测

  20. if (!this.allowBeanDefinitionOverriding) {

  21. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,

  22. "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +

  23. "': There is already [" + oldBeanDefinition + "] bound.");

  24. }

  25. else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {

  26. // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE

  27. if (this.logger.isWarnEnabled()) {

  28. this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +

  29. " with a framework-generated bean definition ': replacing [" +

  30. oldBeanDefinition + "] with [" + beanDefinition + "]");

  31. }

  32. }

  33. else {

  34. if (this.logger.isInfoEnabled()) {

  35. this.logger.info("Overriding bean definition for bean '" + beanName +

  36. "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");

  37. }

  38. }

  39. }

  40. else {

  41. this.beanDefinitionNames.add(beanName);

  42. this.manualSingletonNames.remove(beanName);

  43. this.frozenBeanDefinitionNames = null;

  44. }

  45. //放入Map中

  46. this.beanDefinitionMap.put(beanName, beanDefinition);

  47. if (oldBeanDefinition != null || containsSingleton(beanName)) {

  48. resetBeanDefinition(beanName);

  49. }

  50. }

2.4.3 registerAlias

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

[java] view plain copy

  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.     }  
 
  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. }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值