zoukankan      html  css  js  c++  java
  • 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依赖注入,怎么实例化并依赖注入,带着这些问题?下一篇我们继续解析。

  • 相关阅读:
    《独立网店经营十招招招制胜》
    行业礼品解决方案集
    北京第一礼品网
    ecshop网店系统+Ucenter用户中心+Cyask问答系统整合
    北京礼品在线入驻CRD核心商业区万达广场
    SEO中的关键字扩展
    礼问天下上线
    好网推荐
    北京礼品在线夏日礼の尚礼品促销第二波
    广告管理中的热点问题
  • 原文地址:https://www.cnblogs.com/Henry-pan/p/7268101.html
Copyright © 2011-2022 走看看