SpringMVC 源代码深度解析 IOC容器(Bean 解析、注册)

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

 

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

   


  

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


 

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

  refresh方法的源代码如下:

  

[java] view plain copy
 
  1. public void refresh() throws BeansException, IllegalStateException {  
  2.         synchronized (this.startupShutdownMonitor) {  
  3.             // 准备对上下文进行刷新  
  4.             prepareRefresh();  
  5.             // 初始化beanFactory   
  6.             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  7.             // 为BeanFactory配置容器特性,例如类加载器、事件处理器等  
  8.             prepareBeanFactory(beanFactory);  
  9.             try {  
  10.                 // 为容器的某些子类指定特殊的BeanPost事件处理器  
  11.                 postProcessBeanFactory(beanFactory);  
  12.                 // 调用beanFactory处理器  
  13.                 invokeBeanFactoryPostProcessors(beanFactory);  
  14.                 // 注册beanFactory处理器  
  15.                 registerBeanPostProcessors(beanFactory);  
  16.                 // 初始化消息源  
  17.                 initMessageSource();  
  18.                 // 初始化上下文事件广播.  
  19.                 initApplicationEventMulticaster();  
  20.                 // 初始化其它特殊bean,由子类来实现  
  21.                 onRefresh();  
  22.                 // 注册事件监听器.  
  23.                 registerListeners();  
  24.                 // 初始化所有单实例的bean,使用懒加载除外  
  25.                 finishBeanFactoryInitialization(beanFactory);  
  26.                 // 完成刷新并发布容器刷新事件  
  27.                 finishRefresh();  
  28.             }catch (BeansException ex) {  
  29.                 // Destroy already created singletons to avoid dangling resources.  
  30.                 destroyBeans();  
  31.                 // Reset 'active' flag.  
  32.                 cancelRefresh(ex);  
  33.                 // Propagate exception to caller.  
  34.                 throw ex;  
  35.             }  
  36.         }  
  37.     }  

  这个方法做了很多事情,主要有初始化beanFactory 、注册BeanFactory处理器等工作。我们接下来对里面重要的功能进行解析,它怎么读取我们配置文件并解析文件和注册配置文件里的bean。

 

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

     

[java] view plain copy
 
  1. **  
  2.      * Tell the subclass to refresh the internal bean factory.  
  3.      * @return the fresh BeanFactory instance  
  4.      * @see #refreshBeanFactory()  
  5.      * @see #getBeanFactory()  
  6.      */  
  7.     protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  
  8.         refreshBeanFactory();  
  9.         ConfigurableListableBeanFactory beanFactory = getBeanFactory();  
  10.         if (logger.isDebugEnabled()) {  
  11.             logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  
  12.         }  
  13.         return beanFactory;  
  14.     }  
[java] view plain copy
 
  1. @Override  
  2.     protected final void refreshBeanFactory() throws BeansException {  
  3.         if (hasBeanFactory()) {  
  4.             destroyBeans();  
  5.             closeBeanFactory();  
  6.         }  
  7.         try {  
  8.             DefaultListableBeanFactory beanFactory = createBeanFactory();  
  9.             beanFactory.setSerializationId(getId());  
  10.             customizeBeanFactory(beanFactory);  
  11.             loadBeanDefinitions(beanFactory);  
  12.             synchronized (this.beanFactoryMonitor) {  
  13.                 this.beanFactory = beanFactory;  
  14.             }  
  15.         }  
  16.         catch (IOException ex) {  
  17.             throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);  
  18.         }  
  19.     }  

   第一步:

 

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

 

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

    

[java] view plain copy
 
  1. protected DefaultListableBeanFactory createBeanFactory() {  
  2. return new DefaultListableBeanFactory(getInternalParentBeanFactory());  
  3. }  

 

 

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

 

 

[java] view plain copy
 
  1. protected BeanFactory getInternalParentBeanFactory() {  
  2. return (getParent() instanceof ConfigurableApplicationContext) ?  
  3. ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();  
  4. }  

 

 获取父BeanFactory

  

[java] view plain copy
 
  1. public DefaultListableBeanFactory(BeanFactory parentBeanFactory) {  
  2. super(parentBeanFactory);  
  3. }  
  4. public AbstractAutowireCapableBeanFactory(BeanFactory parentBeanFactory) {  
  5. this();  
  6. setParentBeanFactory(parentBeanFactory);  
  7. }  

 

setParentBeanFactory设置父BeanFactory。

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

  

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

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

 

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

       

[java] view plain copy
 
  1. @Override  
  2.     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {  
  3.         // Create a new XmlBeanDefinitionReader for the given BeanFactory.  
  4.         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
  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.         loadBeanDefinitions(beanDefinitionReader);  
  16.     }  

 

 

   XmlBeanDefinitionReader 来读取并解析 xml 文件,XmlBeanDefinitionReader 是 BeanDefinitionReader 接口的实现。我们来看一下继承关系,如图所示:

      

 

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

  



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

  

[java] view plain copy
 
  1. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {  
  2.         String[] configLocations = getConfigLocations();  
  3.         if (configLocations != null) {  
  4.             for (String configLocation : configLocations) {  
  5.                 reader.loadBeanDefinitions(configLocation);  
  6.             }  
  7.         }  
  8.     }  
[java] view plain copy
 
  1. @Override  
  2.     public String[] getConfigLocations() {  
  3.         return super.getConfigLocations();  
  4.     }  
[java] view plain copy
 
  1. protected String[] getConfigLocations() {  
  2.         return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());  
  3.     }  

 

 

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


 

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

reader.loadBeanDefinitions(configLocation);源代码:

  

[java] view plain copy
 
  1. public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {  
  2.     return loadBeanDefinitions(location, null);  
  3. }  
  4. public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {  
  5.     ResourceLoader resourceLoader = getResourceLoader();  
  6.     if (resourceLoader == null) {  
  7.         throw new BeanDefinitionStoreException(  
  8.                 "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");  
  9.     }  
  10.   
  11.     if (resourceLoader instanceof ResourcePatternResolver) {  
  12.         // Resource pattern matching available.  
  13.         try {  
  14.             Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);  
  15.             int loadCount = loadBeanDefinitions(resources);  
  16.             if (actualResources != null) {  
  17.                 for (Resource resource : resources) {  
  18.                     actualResources.add(resource);  
  19.                 }  
  20.             }  
  21.             if (logger.isDebugEnabled()) {  
  22.                 logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");  
  23.             }  
  24.             return loadCount;  
  25.         }  
  26.         catch (IOException ex) {  
  27.             throw new BeanDefinitionStoreException(  
  28.                     "Could not resolve bean definition resource pattern [" + location + "]", ex);  
  29.         }  
  30.     }  
  31.     else {  
  32.         // Can only load single resources by absolute URL.  
  33.         Resource resource = resourceLoader.getResource(location);  
  34.         int loadCount = loadBeanDefinitions(resource);  
  35.         if (actualResources != null) {  
  36.             actualResources.add(resource);  
  37.         }  
  38.         if (logger.isDebugEnabled()) {  
  39.             logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");  
  40.         }  
  41.         return loadCount;  
  42.     }  
  43. }  

  这个方法有一个ResourcePatternResolver加载了web.xml配置的param-value对应的资源,例如classpath:xxx*.xml 加载了xxx下为xml为后缀的文件资源,loadBeanDefinitions进行对加载进来的资源进行解析。在解析之前先进行转码,是通过EncodedResource对资源文件进行转码,源代码如下: 

 

 

[java] view plain copy
 
  1. public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {  
  2.         return loadBeanDefinitions(new EncodedResource(resource));  
  3.     }  

   对资源文件转码完,就开始读进来,以流的形式,源代码如下:

 

    

[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)getValidationModeForResource(resource);获取对XML文件的验证模式

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

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

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

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

        

[java] view plain copy
 
  1. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {  
  2.         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();  
  3.         documentReader.setEnvironment(this.getEnvironment());  
  4.         int countBefore = getRegistry().getBeanDefinitionCount();//<span style="color:#ff0000;">统计前BeanDefinition加载个数</span>  
  5.         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));  
  6.         return getRegistry().getBeanDefinitionCount() - countBefore;  
  7.     }  
  8. <span style="color:#ff0000;">//解析并注册bean</span>  
  9. public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {  
  10.         this.readerContext = readerContext;  
  11.         logger.debug("Loading bean definitions");  
  12.         Element root = doc.getDocumentElement();  
  13.         doRegisterBeanDefinitions(root);  
  14.     }  
  15.   
  16. protected void doRegisterBeanDefinitions(Element root) {  
  17.         String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);  
  18.         if (StringUtils.hasText(profileSpec)) {  
  19.             Assert.state(this.environment != null, "Environment must be set for evaluating profiles");  
  20.             String[] specifiedProfiles = StringUtils.tokenizeToStringArray(  
  21.                     profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);  
  22.             if (!this.environment.acceptsProfiles(specifiedProfiles)) {  
  23.                 return;  
  24.             }  
  25.         }  
  26.         BeanDefinitionParserDelegate parent = this.delegate;  
  27.         this.delegate = createDelegate(this.readerContext, root, parent);  
  28.         preProcessXml(root);  
  29.         parseBeanDefinitions(root, this.delegate);  
  30.         postProcessXml(root);  
  31.         this.delegate = parent;  
  32.     }  

 

 

  说明:

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

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

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

  这个 parseBeanDefinitions(root, this.delegate)开始注册了,我们解析到重点了,源代码如下:

    

[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.     }  
  21. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {  
  22.        //对IMPORT标签进行处理的  
  23.         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {  
  24.             importBeanDefinitionResource(ele);  
  25.         }  
  26.         //对ALIAS标签进行处理的  
  27.         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {  
  28.             processAliasRegistration(ele);  
  29.         }  
  30.         //对BEAN标签进行处理的  
  31.         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {  
  32.             processBeanDefinition(ele, delegate);  
  33.         }  
  34.         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {  
  35.             // recurse  
  36.             doRegisterBeanDefinitions(ele);  
  37.         }  
  38.     }  
  39. //我们来对处理bean标签进行分析  
  40.   protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {  
  41.         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  
  42.         if (bdHolder != null) {  
  43.             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  
  44.             try {  
  45.                 // Register the final decorated instance.  
  46.                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  
  47.             }  
  48.             catch (BeanDefinitionStoreException ex) {  
  49.                 getReaderContext().error("Failed to register bean definition with name '" +  
  50.                         bdHolder.getBeanName() + "'", ele, ex);  
  51.             }  
  52.             // Send registration event.  
  53.             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  
  54.         }  
  55.     }  

 

 

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

   

[java] view plain copy
 
  1. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {  
  2.         //解析ID属性  
  3.         String id = ele.getAttribute(ID_ATTRIBUTE);  
  4.          //解析name属性  
  5.         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);  
  6.   
  7.         List<String> aliases = new ArrayList<String>();  
  8.         if (StringUtils.hasLength(nameAttr)) {  
  9.             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);  
  10.             aliases.addAll(Arrays.asList(nameArr));  
  11.         }  
  12.   
  13.         String beanName = id;  
  14.         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {  
  15.             beanName = aliases.remove(0);  
  16.             if (logger.isDebugEnabled()) {  
  17.                 logger.debug("No XML 'id' specified - using '" + beanName +  
  18.                         "' as bean name and " + aliases + " as aliases");  
  19.             }  
  20.         }  
  21.   
  22.         if (containingBean == null) {  
  23.             checkNameUniqueness(beanName, aliases, ele);  
  24.         }  
  25. //对其它标签进行解析  
  26.         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  
  27.         if (beanDefinition != null) {  
  28.             if (!StringUtils.hasText(beanName)) {  
  29.                 try {  
  30.                     if (containingBean != null) {  
  31.                         beanName = BeanDefinitionReaderUtils.generateBeanName(  
  32.                                 beanDefinition, this.readerContext.getRegistry(), true);  
  33.                     }  
  34.                     else {  
  35.                         beanName = this.readerContext.generateBeanName(beanDefinition);  
  36.                         // Register an alias for the plain bean class name, if still possible,  
  37.                         // if the generator returned the class name plus a suffix.  
  38.                         // This is expected for Spring 1.2/2.0 backwards compatibility.  
  39.                         String beanClassName = beanDefinition.getBeanClassName();  
  40.                         if (beanClassName != null &&  
  41.                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&  
  42.                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {  
  43.                             aliases.add(beanClassName);  
  44.                         }  
  45.                     }  
  46.                     if (logger.isDebugEnabled()) {  
  47.                         logger.debug("Neither XML 'id' nor 'name' specified - " +  
  48.                                 "using generated bean name [" + beanName + "]");  
  49.                     }  
  50.                 }  
  51.                 catch (Exception ex) {  
  52.                     error(ex.getMessage(), ele);  
  53.                     return null;  
  54.                 }  
  55.             }  
  56.             String[] aliasesArray = StringUtils.toStringArray(aliases);  
  57.             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  
  58.         }  
  59.   
  60.         return null;  
  61.     }  
  62. //对其它标签进行解析  
  63. public AbstractBeanDefinition parseBeanDefinitionElement(  
  64.             Element ele, String beanName, BeanDefinition containingBean) {  
  65.   
  66.         this.parseState.push(new BeanEntry(beanName));  
  67.         //对class属性进行解析  
  68.         String className = null;  
  69.         if (ele.hasAttribute(CLASS_ATTRIBUTE)) {  
  70.             className = ele.getAttribute(CLASS_ATTRIBUTE).trim();  
  71.         }  
  72.   
  73.         try {  
  74.             //对parent属性进行解析  
  75.             String parent = null;  
  76.             if (ele.hasAttribute(PARENT_ATTRIBUTE)) {  
  77.                 parent = ele.getAttribute(PARENT_ATTRIBUTE);  
  78.             }  
  79.             AbstractBeanDefinition bd = createBeanDefinition(className, parent);  
  80.              //解析默认bean的各种属性  
  81.             parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);  
  82.             bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));  
  83.             //解析元数据  
  84.             parseMetaElements(ele, bd);  
  85.             parseLookupOverrideSubElements(ele, bd.getMethodOverrides());  
  86.             parseReplacedMethodSubElements(ele, bd.getMethodOverrides());  
  87.             //解析构造函数  
  88.             parseConstructorArgElements(ele, bd);  
  89.             //解析Property  
  90.             parsePropertyElements(ele, bd);  
  91.             parseQualifierElements(ele, bd);  
  92.   
  93.             bd.setResource(this.readerContext.getResource());  
  94.             bd.setSource(extractSource(ele));  
  95.   
  96.             return bd;  
  97.         }  
  98.         catch (ClassNotFoundException ex) {  
  99.             error("Bean class [" + className + "] not found", ele, ex);  
  100.         }  
  101.         catch (NoClassDefFoundError err) {  
  102.             error("Class that bean class [" + className + "] depends on not found", ele, err);  
  103.         }  
  104.         catch (Throwable ex) {  
  105.             error("Unexpected failure during bean definition parsing", ele, ex);  
  106.         }  
  107.         finally {  
  108.             this.parseState.pop();  
  109.         }  
  110.   
  111.         return null;  
  112.     }  

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

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

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

   

[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 aliase : aliases) {  
  13.                 registry.registerAlias(beanName, aliase);  
  14.             }  
  15.         }  
  16.     }  
  17.    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)  
  18.             throws BeanDefinitionStoreException {  
  19.         Assert.hasText(beanName, "Bean name must not be empty");  
  20.         Assert.notNull(beanDefinition, "BeanDefinition must not be null");  
  21.   
  22.         if (beanDefinition instanceof AbstractBeanDefinition) {  
  23.             try {  
  24.                 ((AbstractBeanDefinition) beanDefinition).validate();  
  25.             }  
  26.             catch (BeanDefinitionValidationException ex) {  
  27.                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
  28.                         "Validation of bean definition failed", ex);  
  29.             }  
  30.         }  
  31.         synchronized (this.beanDefinitionMap) {  
  32.             Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
  33.             if (oldBeanDefinition != null) {  
  34.                 if (!this.allowBeanDefinitionOverriding) {  
  35.                     throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
  36.                             "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +  
  37.                             "': There is already [" + oldBeanDefinition + "] bound.");  
  38.                 }  
  39.                 else {  
  40.                     if (this.logger.isInfoEnabled()) {  
  41.                         this.logger.info("Overriding bean definition for bean '" + beanName +  
  42.                                 "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");  
  43.                     }  
  44.                 }  
  45.             }  
  46.             else {  
  47.                 this.beanDefinitionNames.add(beanName);  
  48.                 this.frozenBeanDefinitionNames = null;  
  49.             }  
  50.             this.beanDefinitionMap.put(beanName, beanDefinition);  
  51.         }  
  52.   
  53.         resetBeanDefinition(beanName);  
  54.     }  

 

 

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


总结:

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

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

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

 

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


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

posted @ 2017-08-01 13:40  Henry、攀  阅读(605)  评论(0编辑  收藏  举报