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?接下來咱們帶着問題來分析。 java

 

   上一篇,咱們在介紹DispatcherServlet初始化的介紹時,父類FrameworkServlet在建立上下文時,調用了一個重啓上下文時,並初始化Bean。如圖所示:node

   


  

ConfigurableWebApplicationContext wac;調用了wac.refresh();方法,完成了對ApplicationContext的初始化,註冊啊,封裝bean的工做,由ConfigurableWebApplicationContext 的子類AbstractApplicationContext實現了bean初始化。咱們來了解一下上下文(容器)整個繼承關係。這邊的箭頭表示繼承或者實現的,如圖所示:web


 

    從上圖咱們能夠看出,ApplicationContext也是繼承BeanFactory,ApplicationContext 也繼承了 ResourceLoader 接口,使得 ApplicationContext 能夠訪問到任何外部資源,提供了更多面向實際應用的功能,咱們經過refresh爲入口點,分析Bean整個初始化過程,並瞭解ApplicationContext的子類AbstractApplicationContext作了哪些工做並瞭解父類實現了哪些功能?每一個接口都有他使用的場合,它主要是爲了區分在 SpringMVC內部在操做過程當中對象的傳遞和轉化過程當中,對對象的數據訪問所作的限制。咱們如今先頭腦中有這個繼承的關係圖,之後深度的瞭解,比較不會那麼暈,這樣思路就比較清晰,咱們以refresh爲入口點,帶着這些問題進行解析。算法

  refresh方法的源代碼以下:spring

  

[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的默認實現。ide

    

[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依賴注入,怎麼實例化並依賴注入,帶着這些問題?下一篇咱們繼續解析。

相關文章
相關標籤/搜索