9159金沙游艺场

图片 14
Kafka概念入门(一)

utf-8-用pip下载gensim出现exception 求大佬们指点!!!

IoC 容器的初始化之 BeanDefinition 的载入和解析

在上一篇文章,我们讲了 IoC 容器初始化的准备阶段,即找到 BeanDefinition
的 Resource
定位,就好比我们用水桶打水,首先要找到水源所在。找到水源之后,我们关注的就是打水的过程了,相比于之前,这个过程更加的精妙,下面我们一起来了解一下
IoC 容器初始化的第二个过程: BeanDefinition 的载入和解析

1.在完成对代表BeanDefinition的Resource定位的分析后,下面来了解整个BeanDefinition信息的载入过程。

简单介绍

1,在Spring中,SpringIoC提供了一个主要的JavaBean容器。通过IoC模式管理依赖关系。并通过依赖注入和AOP切面增强了为JavaBean这样子的POJO提供事务管理,生命周期管理等功能。

2,Spring IoC的设计中,主要包括两个基本的容器系列:

    -1,BeanFactory系列。该序列实现了容器的基本功能。

    -2。ApplicationContext应用上下文。

  • 在完成对 BeanDefinition 的 Resource
    定位的分析之后,接下来我们来了解整个 BeanDefinition
    信息的载入过程。对于 IoC 容器而言,这个载入相当于把定义的
    BeanDefinition 在 IoC 容器中转化成 Spring 内部表示的数据结构的过程。
    IoC 容器对 Bean 的管理和依赖注入功能的实现,是通过其持有的
    BeanDefinition 进行各种相关操作来完成的。这些 BeanDefinition 数据在
    IoC 容器中通过一个 HashMap
    来保持和维护。下面,我们从源码出发来看一下 IoC 容器是如何对
    BeanDefinition 载入的。

    BeanDefinition 载入的具体交互过程如下

    图片 1BeanDefinition
    载入交互过程

    • 在上一篇文章中我们说过,refresh() 是一个非常重要的方法,是 IoC
      容器初始化的入口,那么我们找到其实现的源码。它首先是在
      FileSystemXmlApplicationContext 中调用,并在
      AbstractApplicationContext 中被实现。

      public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // 为防止资源占用,在异常处理中,销毁掉前面已经生成的单例 Bean destroyBeans(); // Reset 'active' flag. cancelRefresh; // Propagate exception to caller. throw ex; } }}
      

      该方法详细地描述了整个 ApplicationContext 的初始化过程,比如
      BeanFactory 的更新等,可以看成是对 ApplicationContext
      初始化的模板或执行提纲,这个执行为 Bean
      的生命周期管理提供了条件。熟悉 IoC
      容器使用的读者,从这一系列调用的名字大概就能了解整个
      ApplicationContext 初始化的主要内容。同时在 try-catch
      之前,我们可以看到首先调用了 obtainBeanFactory 方法来获取一个
      BeanFactory,我们进去看一下发生了什么。

    • 最终到 AbstractRefreshableApplicationContext 类的
      refreshBeanFactory() 方法:

      protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId; customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName; }}
      

      在该方法中,首先判断是否已经存在了基础的 BeanFactory
      容器,有的话就销毁。接着调用 createBeanFactory() 方法创建了一个
      DefaultListableBeanFactory。这也验证了我们在上一文说到的,ApplicationContext
      是在基础 BeanFactory 上添加了高级容器特征的 IoC
      容器,而且大多数情况下是使用 DefaultListableBeanFactory
      这个具有基础容器功能的 BeanFactory。

    • 接着最主要的就是 loadBeanDefinitions()
      方法,但是在这里这只是一个抽象方法,在上面的交互图我们可以看到,其具体实现是在
      AbstractXmlApplicationContext 中实现的。

      protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 创建一个 XmlBeanDefinitionReader,并通过回调设置到 BeanFactory 中去。 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment; beanDefinitionReader.setResourceLoader; beanDefinitionReader.setEntityResolver(new ResourceEntityResolver; // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader);}
      

      其实到了这里,如果在上面有亲自动手追踪 BeanDefinition 的
      Resource 定位的读者,应该会对当前 AbstractXmlApplicationContext
      这个类比较熟悉,因为我们上面提到的获取 configuration 也是
      在这个类中调用的。这更加可以说明 refresh() 是 IoC
      容器初始化的如果,毕竟在上一个步骤中我们并没有进入到 refresh()
      这个方法里面去查看。

    • 接着就是 loadBeanDefinitions 调用的地方,首先得到 BeanDefinition
      的 Resource
      定位,其具体过程已经在上文讲过,我们就不再介绍了,代码清单如下:

      protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); }}
      
    • 通过对以上实现原理的分析,我们可以看到,refresh() 方法启动对 IoC
      容器的初始化,具体的过程是在 XmlBeanDefinitionReader
      中完成的。因为 Spring 对应不用形式的
      BeanDefinition,这里使用的是 XML 方式定义,所以需要使用
      XmlBeanDefinitionReader,如果使用了其他 BeanDefinition
      方式,就需要使用其他中来的 BeanDefinitionReader
      来完成载入工作。这里 XmlBeanDefinitionReader 的父类
      AbstractBeanDefinitionReader
      已经为这个载入工作做好了准备。代码如下:

      public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { counter += loadBeanDefinitions; } return counter;}
      

      但是这里 loadBeanDefinitions
      仅仅是一个接口方法,具体的实现交由各个子类去完成。下面我们进去到
      XmlBeanDefinitionReader 去查看实现过程。

      • 我们看一下源码:

        public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled { logger.info("Loading XML bean definitions from " + encodedResource.getResource; } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>; this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } // 这里得到XML 文件,并得到 IO 的 InputStream 准备进行读取。 try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding; } return doLoadBeanDefinitions(inputSource, encodedResource.getResource; } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource; } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty { this.resourcesCurrentlyBeingLoaded.remove(); } }}
        
      • 具体的读取过程可以在 doLoadBeanDefinitions() 方法中找到。

        protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource; Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware; return registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); }}
        
      • 感兴趣的读者可以到 DefaultDocumentLoader 里面看看如何得到
        Document 对象,这里就不详细分析的。我们关系的是 Spring 的
        BeanDefinition 是如何按照 Spring 的 Bean
        语义要求进行解析并转化成容器内部数据结构的。这个过程是在
        registerBeanDefinitions() 方法实现的,还对载入的 Bean
        数量进行了统计。

        public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); documentReader.setEnvironment(this.getEnvironment; int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext); return getRegistry().getBeanDefinitionCount() - countBefore;}
        

        可以看到,这个解析过程是在 documentReader
        里面进行的,这里使用的是
        DefaultBeanDefinitionDocumentReader。

      • 我们继续追踪 registerBeanDefinitions()
        方法,并结合最上面的交互过程,得到方法调用栈图下图所示:图片 2image
        我们首先进入到 DefaultBeanDefinitionDocumentReader
        里面,可以看到 processBeanDefinition 方法中,调用了
        BeanDefinitionParserDelegate
        来最终完成这个整个解析过程,得到的结果由
        BeanDefinitionHolder 来持有,源码清单如下:

        protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement; if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry; } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition); }}
        

        BeanDefinitionHolder 是 BeanDefinition
        对象类的封装类,封装了 BeanDefinition、Bean
        的名字和别名,用它来向 IoC 容器注册。而具体的解析过程交由
        BeanDefinitionParserDelegate
        完成,感兴趣的读者可以继续仔细最终研究。下面我们举个例子来分析一下。

    • 我们先来看一下最常见的 Bean 元素解析:

      public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { // 这里取得 bean 元素定义里面 id、name、aliase 属性的值。 String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList; } String beanName = id; if (!StringUtils.hasText && !aliases.isEmpty { beanName = aliases.remove; if (logger.isDebugEnabled { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } // 这个方法引发对 bean 元素的详细解析 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry; } else { beanName = this.readerContext.generateBeanName(beanDefinition); String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage; return null; } } String[] aliasesArray = StringUtils.toStringArray; return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null;}
      

      在这里我们会看到 XML 定义文件常见到的属性元素,如
      id、name、aliase 等,把这些元素从 XML 文件转化而来的 element
      中取出来,并设置到 BeanDefinitionHolder
      中去,这些属性的解析还是比较简单的。对于其他元素配置的解析,如各种
      Bean 的属性配置,则为一个较为复杂的过程,由
      parseBeanDefinitionElement 方法完成。

      • 以上介绍了对 Bean 元素进行解析的过程。也就是 BeanDefinition
        根据 XML 的 <bean> 定义被创建的过程。这个
        BeanDefinition 可以看成 <bean>
        定义的抽象。这个数据对象中封装的数据大都是与 <bean>
        定义相关的,也就是我们在定义 Bean 时看到的那些 Spring
        标记,如 init-method、destroy-method 等。这个 BeanDefinition
        数据类型是非常重要的,它封装了很多基本数据,这些基本数据都是
        IoC 容器需要的。 BeanDefinition 是 IoC
        容器中非常核心的数据结构,而通过上述的解析,这些数据已经准备好在
        IoC 容器中大显身手了。
      • 下面我们再接着跟踪,进入 parseBeanDefinitionElement
        源码之中:

        public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 这里对当前的 Bean 元素进行属性分析,并设置描述信息。 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); // 从名字可以看出,这里是对各种 <bean> 元素的信息进行解析的地方。 parseMetaElements; parseLookupOverrideSubElements(ele, bd.getMethodOverrides; parseReplacedMethodSubElements(ele, bd.getMethodOverrides; parseConstructorArgElements; parsePropertyElements; parseQualifierElements; bd.setResource(this.readerContext.getResource; bd.setSource(extractSource; return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null;}
        
      • 上面是具体生成 BeanDefinition 的地方。在这里,我们举一个对
        property 进行解析的例子,最终完成对整个 BeanDefinition
        载入和解析的过程。这里是指对 Bean 元素下的 property
        子元素进行解析。

        public void parsePropertyElements(Element beanEle, BeanDefinition bd) { // 遍历 Bean 元素下的定义的 property NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength { Node node = nl.item; if (isCandidateElement && nodeNameEquals(node, PROPERTY_ELEMENT)) { // 进行详细的解析 parsePropertyElement node, bd); } }}
        
        public void parsePropertyElement(Element ele, BeanDefinition bd) { / 这里取得 property 的名字。 String propertyName = ele.getAttribute(NAME_ATTRIBUTE); if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); // 这里是解析 property 的过程。返回的对象对应在 Bean 中定义的 property 属性的解析结果,这个结果会封装到 PropertyValue 中。 try { if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } Object val = parsePropertyValue(ele, bd, propertyName); PropertyValue pv = new PropertyValue(propertyName, val); parseMetaElements; pv.setSource(extractSource; bd.getPropertyValues().addPropertyValue; } finally { this.parseState.pop(); }}
        
        // 这里取得 peoperty 元素的值public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // Should only have one child element: ref, value, list, etc. NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength { Node node = nl.item; if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement =  node; } } } boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference; ref.setSource(extractSource; return ref; } else if (hasValueAttribute) { TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource; return valueHolder; } else if (subElement != null) { return parsePropertySubElement(subElement, bd); } else { // Neither child element nor "ref" or "value" attribute found. error(elementName + " must specify a ref or value", ele); return null; }}
        
        // 这里是对 property 子元素的解析过程,Array、List、Set、Map 等元素都会在这里解析public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { if (!isDefaultNamespace { return parseNestedCustomElement; } else if (nodeNameEquals(ele, BEAN_ELEMENT)) { BeanDefinitionHolder nestedBd = parseBeanDefinitionElement; if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, REF_ELEMENT)) { // A generic reference to any name of any bean. String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength { // A reference to the id of another bean in the same XML file. refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength { // A reference to the id of another bean in a parent context. refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); toParent = true; if (!StringUtils.hasLength { error("'bean', 'local' or 'parent' is required for <ref> element", ele); return null; } } } if (!StringUtils.hasText { error("<ref> element contains empty target attribute", ele); return null; } RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource; return ref; } else if (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement; } else if (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } else if (nodeNameEquals(ele, NULL_ELEMENT)) { // It's a distinguished null value. Let's wrap it in a TypedStringValue // object in order to preserve the source location. TypedStringValue nullHolder = new TypedStringValue; nullHolder.setSource(extractSource; return nullHolder; } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement; } else if (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement; } else if (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement; } else if (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement; } else if (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement; } else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; }}
        

        property 子元素的解析,最终会生成对应的数据对象,比如
        ManagedList、ManagedArray、ManagedSet等,这些 Managed 类是
        Spring 的具体的 BeanDefinition
        的数据封装。具体的过程读者可以去查看具体的解析过程。从一系列
        parse
        方法名字可以很清楚的看出是对哪种类型的解析,具体的过程我们就不再查看了。

2.对IoC容器来说,这个载入过程,相当于把定义的BeanDefinition在IoC容器中转化成一个Spring内部表示的数据结构的过程。

Spring IoC容器的设计

1,例如以下图,IoC容器的接口设计图。

    

图片 3

2,简单介绍

    -1,从BeanFactory到HierarchicalbeanFactory再到ConfigurableBeanFactory是一条基本的BeanFactory设计路径。BeanFactory定义了基本的IoC容器接口。

HierarchicalBeanFactory接口继承了BeanFactory接口,并再其基础上添加了getParentBeanFactory()接口功能,使得BeanFactory具备双亲IoC管理功能。ConfigurableBeanFactory主要定义了对BeanFactory的配置功能。

    -2。以ApplicationContext为核心的接口设计。

这样逐层的解析,我们在 XML 定义的 BeanDefinition 就被整个载入到 IoC
容器中,并在容器中建立了数据映射,即在 IoC
容器创建了对应的数据结构,这些数据结构以 AbstractBeanDefinition
为入口,让 IoC
容器进行索引、查询和操作。但是,重要的依赖注入实际上还没有发生,现在 IoC
容器 BeanDefinition
中存在的还只是一些静态的配置。严格来说,这时候的容器还没有完全起作用,要完全发挥容器的作用,还需要完成数据向容器的注册。

3.IoC容器对Bean的管理和依赖注入功能的实现,是通过对其持有的BeanDefinition进行各种相关操作来完成的。

BeanFactory的应用场景

    BeanFactory是最主要的IoC容器。

    用户在使用容器的时候能够通过&符来获取FactoryBean本身。FactoryBean跟普通Bean不同。通过BeanFactory类的getBean方法直接获取到的并非该FactoryBean的实例,而是
该FactoryBean中方法getObject返回的对象。

但我们能够通过其他途径获取到该FactoryBean的实例。方法就是在通过
getBean方法获取实例时在參数name前面加上“&”符号就可以。

    

String FACTORY_BEAN_PREFIX = "&";

    1。BeanFactory的主要接口,以及其作用例如以下:

    -1。容器推断是否包括指定名字的bean。

boolean containsBean(String name);

    -2,推断指定的bean是否是prototype类型。

boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    -3。推断指定的bean是否是singleton。

boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    -4,推断指定的bean是否与给定类型相匹配。

boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;

    -5,获取指定Bean的类型。

Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    -6。指定bean的全部别名。

String[] getAliases(String name);

2,BeanFactory的容器设计原理。

    BeanFactory接口提供了使用IoC的规范,而且Spring实现了一系列容器的实现供开发者使用。

以XmlBeanFactory为例。例如以下为XmlBeanFactory的继承结构图。

图片 4

下面是XmlBeanFactory的代码,在Spring 4中。该类已经不推荐被使用了。

@Deprecated@SuppressWarnings({"serial", "all"})public class XmlBeanFactory extends DefaultListableBeanFactory {
   private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

   /**    * 通过给定的资源创建一个XmlBeanFactory实例。     */  public XmlBeanFactory(Resource resource) throws BeansException {       this(resource, null);   }
   /**    * Create a new XmlBeanFactory with the given input stream,   * which must be parsable using DOM.  */  public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {       super(parentBeanFactory);        this.reader.loadBeanDefinitions(resource);   }
}

    该类继承了DefaultListableBeanFactory类。DefaultListableBeanFactory该类实现一个最为基础的IoC容器。

    例如以下是一个简单的使用方法举例:

ClassPathResource re = new ClassPathResource("bean.xml");     DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();     XmlBeanDefinitionReader xdr = new XmlBeanDefinitionReader(beanFactory);      xdr.loadBeanDefinitions(re);      System.out.println(xdr.getRegistry());

4.这些BeanDefinition数据在IoC容器中通过一个HashMap来保持和维护。当然这只是一种比较简单的维护方式,如果需要提高IoC容器的性能和容量,完全可以自己做一些扩展。

ApplicationContext的应用场景

   1。 ApplicationContext在BeanFactory的基础上添加了非常多新的特性:

    -1。支持不同的信息源。ApplicationContext扩展了MessageSource接口,这些为国际化提供服务。

    -2,訪问资源。对ResourceLoader和Resource的支持。能够从不同的地方获取到资源。

    -3。支持应用事件。

继承ApplicationEventPublisher,从而引入的事件机制。

与Bean的生命周期结合,方便管理Bean。

    -4,在ApplicationContext添加附加服务。

    2,ApplicationContext设计原理,以FileSystemApplicationContext为例。

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)           throws BeansException {
       super(parent);       setConfigLocations(configLocations);        if (refresh) {          refresh();        } }

    在实例化该应用中,调用了AbstractApplicationContext的refresh方法。该方法是IoC容器启动的主要方法。

    另一个主要方法是:

  @Override protected Resource getResourceByPath(String path) {      if (path != null && path.startsWith("/")) {           path = path.substring(1);       }     return new FileSystemResource(path);    }

该方法通过FileSystemResource获取资源路径。

5.下面,从DefaultListableBeanFactory的设计入手,看看IoC容器是怎样完成BeanDefinition载入的。这个DefaultListableBeanDefinition在前面已经碰到多次,相信大家对它一定不会感到陌生。

IoC容器的初始化过程

    简单来说IoC的初始化是由AbstractApplicationContext的refresh方法实现的。整个启动过程包含三个部分。BeanDefinition的Resource定位、加载和注冊三个基本部分。Spring将三个模块分开。并使用不同的模块完毕。

    第一个过程是Resource定位过程。这个Resource定位是指Spring找到我们定义的Bean配置的xml文件。

    第二步。BeanDefinition的加载。这个过程是把用户定义好的Bean表示成IoC容器内部的数据结构,而这个数据结构就是BeanDefinition。详细说。BeanDefination实际就是POJO在容器中的抽象,通过这个BeanDefinition定义的数据结构,使IoC容器可以方便的对POJO对象。也就是Bean进行管理。

    第三步,是向IoC容器注冊这些BeanDefinition的过程。这个过程通过调用BeanDefinationRegistry接口实现。

这个注冊过程把加载过程(第二步)得到的BeanDefinition向容器注冊。IoC内部,将BeanDefinition注入到一个HashMap中去,IoC容器就是通过HashMap来持有这些BeanDefinition数据的。

    一般,IoC的初始化过程,不包含依赖注入。依赖注入一般发生在应用第一次通过getBean向容器获取Bean的时候。

1,BeanDefinition的Resource定位。

 
在使用DefaultListableBeanFactory的时候,首先须要使用Resource来进行资源定位容器使用的BeanDefinition。

    使用ClassPathResource进行资源定位。

ClassPathResource re = new ClassPathResource("bean.xml");

    在此处定义的资源文件不能被DefaultListableBeanFactory直接使用,通过BeanDefinitionReader来读取。

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();XmlBeanDefinitionReader xdr = new XmlBeanDefinitionReader(beanFactory);xdr.loadBeanDefinitions(re);

在此处我们发现使用比較麻烦。所以使用ApplicationContext,由于在ApplicationContext中。Spring为我们提供了一系列的资源定位,比方FileSystemXmlApplicationContext。

    以FileSystemXmlApplicationContext为例,解说相应的源代码。

    该构造函数通过文件路劲来生成相应的FileSystemXmlApplicationContext

public FileSystemXmlApplicationContext(String configLocation) throws BeansException {       this(new String[] {configLocation}, true, null);    }

通过refresh方法来加载BeanDefinition。

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)           throws BeansException {
       super(parent);       setConfigLocations(configLocations);        if (refresh) {          refresh();        } }

通过文件系统来获取资源。

@Override  protected Resource getResourceByPath(String path) {      if (path != null && path.startsWith("/")) {           path = path.substring(1);       }     return new FileSystemResource(path);    }

2,BeanDefinition的加载和解析。

    对IoC容器来说。加载过程相当于把BeanDefinition在IoC容器中转换成一个Spring内部数据结构的过程。IoC对对象的管理都是通过对其持有的BeanDefination进行相关操作来实现的。

这些BeanDefinition是通过HashMap来维护的。

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)           throws BeansException {      super(parent);       setConfigLocations(configLocations);        if (refresh) {          refresh();        } }

    如上代码,refresh()方法启动了容器初始化。是加载BeanDefination的入口方法。
    refresh()详细的代码结构例如以下:

@Override  public void refresh() throws BeansException, IllegalStateException {     synchronized (this.startupShutdownMonitor) {          // Prepare this context for refreshing.           prepareRefresh();
           // Tell the subclass to refresh the internal bean factory.
//在子类中启动refreshBeanFactory()的地方。            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
           // Prepare the bean factory for use in this context.          prepareBeanFactory(beanFactory);
try {             // Allows post-processing of the bean factory in context subclasses.
//设置BeanFactory的后置处理。
               postProcessBeanFactory(beanFactory);
               // Invoke factory processors registered as beans in the context.
//调用BeanFactory的后置处理器。这些处理器是在Bean定义中向容器注冊的
             invokeBeanFactoryPostProcessors(beanFactory);
               // Register bean processors that intercept bean creation.
//注冊Bean的后处理器。在Bean的创建过程中调用
             registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//对上下文中的消息源初始化
             initMessageSource();
               // Initialize event multicaster for this context.
//初始化上下文中的时间机制                initApplicationEventMulticaster();
               // Initialize other special beans in specific context subclasses.
//初始化其它Bean
             onRefresh();
               // Check for listener beans and register them.
//检查监听bean并注冊
             registerListeners();
               // Instantiate all remaining (non-lazy-init) singletons.
//实例化全部(non-lazy-init) 单例。                finishBeanFactoryInitialization(beanFactory);
               // Last step: publish corresponding event.
//公布容器事件。结束
             finishRefresh();          }
           catch (BeansException ex) {             // Destroy already created singletons to avoid dangling resources.
//防止Bean资源占用,销毁已经创建的单例。                destroyBeans();
               // Reset 'active' flag.
//重置active标志
             cancelRefresh(ex);
               // Propagate exception to caller.             throw ex;           }     } }

-1。prepareRefresh():

/**  * Prepare this context for refreshing, setting its startup date and     * active flag as well as performing any initialization of property sources.     */ protected void prepareRefresh() {      this.startupDate = System.currentTimeMillis();
      synchronized (this.activeMonitor) {          this.active = true;        }
      if (logger.isInfoEnabled()) {            logger.info("Refreshing " + this);       }
      // Initialize any placeholder property sources in the context environment        initPropertySources();
      // Validate that all properties marked as required are resolvable        // see ConfigurablePropertyResolver#setRequiredProperties        getEnvironment().validateRequiredProperties(); }

-2。启动refreshBeanFactory():

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();



/**  * Tell the subclass to refresh the internal bean factory.   * @return the fresh BeanFactory instance    * @see #refreshBeanFactory()    * @see #getBeanFactory()    */ protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {      refreshBeanFactory();        ConfigurableListableBeanFactory beanFactory = getBeanFactory();     if (logger.isDebugEnabled()) {           logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);      }        return beanFactory;    }

终于调用,AbstractRefreshableApplicationContext中的refreshBeanFactory()方法。

  /**   * This implementation performs an actual refresh of this context's underlying   * bean factory, shutting down the previous bean factory (if any) and    * initializing a fresh bean factory for the next phase of the context's lifecycle.  */ @Override    protected final void refreshBeanFactory() throws BeansException {       if (hasBeanFactory()) {//假设已经存在BeanFactory           destroyBeans();//销毁            closeBeanFactory();      }        try { //创建IoC容器            DefaultListableBeanFactory beanFactory = createBeanFactory();           beanFactory.setSerializationId(getId());         customizeBeanFactory(beanFactory);         loadBeanDefinitions(beanFactory);//加载BeanFactory。抽象方法         synchronized (this.beanFactoryMonitor) {             this.beanFactory = beanFactory;           }        }        catch (IOException ex) {           throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);      }    }

这里调用的loadBeanDefinations()是一个抽象方法,详细实如今AbstractXmlApplicationContext。

/**  * Loads the bean definitions via an XmlBeanDefinitionReader.    * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader    * @see #initBeanDefinitionReader    * @see #loadBeanDefinitions     */ @Override    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {       // Create a new XmlBeanDefinitionReader for the given BeanFactory.       XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
      // Configure the bean definition reader with this context's      // resource loading environment.     beanDefinitionReader.setEnvironment(this.getEnvironment());        beanDefinitionReader.setResourceLoader(this);        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
      // Allow a subclass to provide custom initialization of the reader,      // then proceed with actually loading the bean definitions.      initBeanDefinitionReader(beanDefinitionReader);        loadBeanDefinitions(beanDefinitionReader); }

接着就是调用loadBeanDefinations的地方,首先得到BeanDefinition信息的Resource定位,然后调用XmlBeanDefinitionReader来读取,详细过程托付给BeanDefinitionReader来完毕的。

XML文件则是通过XmlBeanDefinitionReader来加载BeanDefination到容器中。

    ​注:在XmlBeanDefinationReader中找到的loadBeanDefination()方法。与书中的代码块不同。

此处可能是Spring版本号的问题。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {      Assert.notNull(encodedResource, "EncodedResource must not be null");        if (logger.isInfoEnabled()) {            logger.info("Loading XML bean definitions from " + encodedResource.getResource());        }
      Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();        if (currentResources == null) {           currentResources = new HashSet<EncodedResource>(4);           this.resourcesCurrentlyBeingLoaded.set(currentResources);       }        if (!currentResources.add(encodedResource)) {          throw new BeanDefinitionStoreException(                  "Detected cyclic loading of " + encodedResource + " - check your import definitions!");     }        try {//输入流读取资源            InputStream inputStream = encodedResource.getResource().getInputStream();           try {              InputSource inputSource = new InputSource(inputStream);             if (encodedResource.getEncoding() != null) {                  inputSource.setEncoding(encodedResource.getEncoding());                }//调用解析XML文件               return doLoadBeanDefinitions(inputSource, encodedResource.getResource());            }            finally {              inputStream.close();           }        }        catch (IOException ex) {           throw new BeanDefinitionStoreException(                  "IOException parsing XML document from " + encodedResource.getResource(), ex);       }        finally {          currentResources.remove(encodedResource);            if (currentResources.isEmpty()) {                this.resourcesCurrentlyBeingLoaded.remove();          }        }    }

doLoadBeanDefinitions()方法:

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)           throws BeanDefinitionStoreException {       try {                    //载入文件         Document doc = doLoadDocument(inputSource, resource);                    //启动具体的解析过程          return registerBeanDefinitions(doc, resource);     }        catch (BeanDefinitionStoreException ex) {          throw ex;      }        catch (SAXParseException ex) {         throw new XmlBeanDefinitionStoreException(resource.getDescription(),                 "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);        }        catch (SAXException ex) {          throw new XmlBeanDefinitionStoreException(resource.getDescription(),                 "XML document from " + resource + " is invalid", ex);     }        catch (ParserConfigurationException ex) {          throw new BeanDefinitionStoreException(resource.getDescription(),                    "Parser configuration exception parsing XML from " + resource, ex);        }        catch (IOException ex) {           throw new BeanDefinitionStoreException(resource.getDescription(),                    "IOException parsing XML document from " + resource, ex);      }        catch (Throwable ex) {         throw new BeanDefinitionStoreException(resource.getDescription(),                    "Unexpected exception parsing XML document from " + resource, ex);     }    }

registerbeanDefinitions()方法代码:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {         //获取XML文档读取        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();     documentReader.setEnvironment(this.getEnvironment());      int countBefore = getRegistry().getBeanDefinitionCount();             //详细解析过程        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));      return getRegistry().getBeanDefinitionCount() - countBefore; }

BeanDefinition加载过程中,首先调用XML解析器,生成XML解析对象。然后再进行详细的解析。

createBeanDefinitionDocumentReader()方法:

    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {     return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); }

获取到详细的解析器。然后托付给BeanDefinitionParserDelegate来完毕详细的解析。例如以下查看DefaultBeanDefinitionDocuementReader中的processBeanDefinition(Element
, BeanDefinitionParserDelegate)方法:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {       BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
//BeanDefinitionHolder是对BeanDefinition的封装。
        if (bdHolder != null) {           bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);         try {                // Register the final decorated instance.
//向IoC容器注冊解析到的BeanDefinition。               BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());            }            catch (BeanDefinitionStoreException ex) {              getReaderContext().error("Failed to register bean definition with name '" +                       bdHolder.getBeanName() + "'", ele, ex);         }            // Send registration event.          getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));      }    }

BeanDefinitionHolder:

public class BeanDefinitionHolder implements BeanMetadataElement {
  private final BeanDefinition beanDefinition;
  private final String beanName;
  private final String[] aliases;
........

在BeanDefinitionParserDelegate类中,定义了对各种SpringBean类的处理。

查看其相应的parseBeanDefinitionElement方法:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {      String id = ele.getAttribute(ID_ATTRIBUTE);//bean元素中的ID      String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//bean元素中的name
      List<String> aliases = new ArrayList<String>();//aliases      if (StringUtils.hasLength(nameAttr)) {            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);          aliases.addAll(Arrays.asList(nameArr));     }
      String beanName = id;       if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {           beanName = aliases.remove(0);          if (logger.isDebugEnabled()) {               logger.debug("No XML 'id' specified - using '" + beanName +                     "' as bean name and " + aliases + " as aliases");           }        }
      if (containingBean == null) {         checkNameUniqueness(beanName, aliases, ele);       }
      AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);//具体解析过程,返回AbstractBeanDefinition对象,该对象定义了Bean的基本属性     if (beanDefinition != null) {         if (!StringUtils.hasText(beanName)) {             try {                  if (containingBean != null) {                     beanName = BeanDefinitionReaderUtils.generateBeanName(                               beanDefinition, this.readerContext.getRegistry(), true);                   }                    else {                     beanName = this.readerContext.generateBeanName(beanDefinition);                       // Register an alias for the plain bean class name, if still possible,                       // if the generator returned the class name plus a suffix.                       // This is expected for Spring 1.2/2.0 backwards compatibility.                      String beanClassName = beanDefinition.getBeanClassName();                     if (beanClassName != null &&                             beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&                             !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {                          aliases.add(beanClassName);                      }                    }                    if (logger.isDebugEnabled()) {                       logger.debug("Neither XML 'id' nor 'name' specified - " +                             "using generated bean name [" + beanName + "]");                    }                }                catch (Exception ex) {                 error(ex.getMessage(), ele);                   return null;                }            }            String[] aliasesArray = StringUtils.toStringArray(aliases);          return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);       }
      return null;    }

查看详细的解析代码,parseBeanDefinitionEleent方法:

public AbstractBeanDefinition parseBeanDefinitionElement(          Element ele, String beanName, BeanDefinition containingBean) {
      this.parseState.push(new BeanEntry(beanName));
      String className = null;     if (ele.hasAttribute(CLASS_ATTRIBUTE)) {           className = ele.getAttribute(CLASS_ATTRIBUTE).trim();        }
      try {          String parent = null;            if (ele.hasAttribute(PARENT_ATTRIBUTE)) {              parent = ele.getAttribute(PARENT_ATTRIBUTE);           }                       //生成BeanDefinition对象          AbstractBeanDefinition bd = createBeanDefinition(className, parent);                   //解析属性,并设置Description信息         parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));                     //解析bean元素信息            parseMetaElements(ele, bd);          parseLookupOverrideSubElements(ele, bd.getMethodOverrides());          parseReplacedMethodSubElements(ele, bd.getMethodOverrides());                   //构造函数          parseConstructorArgElements(ele, bd);                 //成员变量          parsePropertyElements(ele, bd);          parseQualifierElements(ele, bd);                         bd.setResource(this.readerContext.getResource());            bd.setSource(extractSource(ele));
          return bd;     }        catch (ClassNotFoundException ex) {            error("Bean class [" + className + "] not found", ele, ex);      }        catch (NoClassDefFoundError err) {         error("Class that bean class [" + className + "] depends on not found", ele, err);       }        catch (Throwable ex) {         error("Unexpected failure during bean definition parsing", ele, ex);       }        finally {          this.parseState.pop();        }
      return null;    }

当中相应的各种异常信息,可能我们在编程工作中常常遇到。

    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {     NodeList nl = beanEle.getChildNodes();        for (int i = 0; i < nl.getLength(); i++) {          Node node = nl.item(i);         if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {                parsePropertyElement((Element) node, bd);//解析           }        }    }



/**  * Parse a property element.     */ public void parsePropertyElement(Element ele, BeanDefinition bd) {      String propertyName = ele.getAttribute(NAME_ATTRIBUTE);//获取property名字       if (!StringUtils.hasLength(propertyName)) {           error("Tag 'property' must have a 'name' attribute", ele);           return;       }        this.parseState.push(new PropertyEntry(propertyName));     try {          if (bd.getPropertyValues().contains(propertyName)) {//是否包括               error("Multiple 'property' definitions for property '" + propertyName + "'", ele);             return;           }            Object val = parsePropertyValue(ele, bd, propertyName);//解析         PropertyValue pv = new PropertyValue(propertyName, val);//获取值            parseMetaElements(ele, pv);          pv.setSource(extractSource(ele));          bd.getPropertyValues().addPropertyValue(pv);       }        finally {          this.parseState.pop();        }    }

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {      String elementName = (propertyName != null) ?                      "<property> element for property '" + propertyName + "'" :                     "<constructor-arg> element";
      // Should only have one child element: ref, value, list, etc.        NodeList nl = ele.getChildNodes();//xml文档解析       Element subElement = null;       for (int i = 0; i < nl.getLength(); i++) {          Node node = nl.item(i);         if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&                  !nodeNameEquals(node, META_ELEMENT)) {               // Child element is what we're looking for.              if (subElement != null) {                 error(elementName + " must not contain more than one sub-element", ele);                }                else {                 subElement = (Element) node;              }            }        }
      boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);//是否是ref引用      boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);//值引用     if ((hasRefAttribute && hasValueAttribute) ||                ((hasRefAttribute || hasValueAttribute) && subElement != null)) {         error(elementName +                    " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);     }
      if (hasRefAttribute) {//ref引用            String refName = ele.getAttribute(REF_ATTRIBUTE);           if (!StringUtils.hasText(refName)) {              error(elementName + " contains empty 'ref' attribute", ele);            }            RuntimeBeanReference ref = new RuntimeBeanReference(refName);           ref.setSource(extractSource(ele));         return ref;        }//value 引用        else if (hasValueAttribute) {            TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));         valueHolder.setSource(extractSource(ele));         return valueHolder;        }//假设还有子元素。触发对子元素的解析      else if (subElement != null) {          return parsePropertySubElement(subElement, bd);        }        else {         // Neither child element nor "ref" or "value" attribute found.           error(elementName + " must specify a ref or value", ele);           return null;        }    }

3,BeanDefinition在IoC容器中的注冊

BeanDefinition完毕加载和解析过程后。须要对其进行注冊操作。

注冊是在DefaultListableBeanFactory中,通过HashMap来加载Beandefinition的。

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

调用顺序:XmlBeanDefinitionReader调用loadBeanDefinitions(EncodedResource)方法,然后到registerBeanDefinitions()方法。在该方法中registerBeanDefinitions()方法被调用。在DefaultListableBeanFactory中,实现了BeanDefinitionRegistry接口。

@Override   public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)            throws BeanDefinitionStoreException {
      Assert.hasText(beanName, "Bean name must not be empty");        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
      if (beanDefinition instanceof AbstractBeanDefinition) {          try {              ((AbstractBeanDefinition) beanDefinition).validate();         }            catch (BeanDefinitionValidationException ex) {             throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,                      "Validation of bean definition failed", ex);            }        }
      synchronized (this.beanDefinitionMap) {//是否存在同样名字            BeanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName);           if (oldBeanDefinition != null) {              if (!this.allowBeanDefinitionOverriding) {                   throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,                          "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +                         "': There is already [" + oldBeanDefinition + "] bound.");              }                else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {                    // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE                    if (this.logger.isWarnEnabled()) {                     this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +                             " with a framework-generated bean definition ': replacing [" +                             oldBeanDefinition + "] with [" + beanDefinition + "]");                   }                }                else {                 if (this.logger.isInfoEnabled()) {                     this.logger.info("Overriding bean definition for bean '" + beanName +                              "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");                    }                }            }            else {//注冊bean。将bean的name放入List               this.beanDefinitionNames.add(beanName);             this.frozenBeanDefinitionNames = null;           }
//map中增加         this.beanDefinitionMap.put(beanName, beanDefinition);     }
      resetBeanDefinition(beanName); }

完毕了注冊。就完毕了IoC容器的初始化。

在使用的IoC容器的DefaultListableBeanFactory中已经建立了Bean的配置信息,并且这些BeanDefinition已经能够被容器使用,他们都在beanDefinitionMap中被检索和使用。容器的作用就是对这些信息进行维护和处理。

6.在开始分析之前,先回到IoC容器初始化入口,也就是看一下refresh方法。这个方法的最初是在FileSystemXmlApplicationContext的构造函数中被调用的,它的调用标志着容器初始化的开始,这些初始化对象就是BeanDefinition数据,初始化入口如代码清单2-7所示。

IoC容器的依赖注入    ​    ​

    ​依赖注入是用户第一次向Ioc容器索要Bean的时候触发的。除非通过lazy-init控制Bean的记载时机。

    ​从DefaultListableBeanFactory的基类AbstractBeanFactory的getBean方法開始查看实现。

@Override   public Object getBean(String name) throws BeansException {     return doGetBean(name, null, null, false);    }
  @Override    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {        return doGetBean(name, requiredType, null, false);   }
  @Override    public Object getBean(String name, Object... args) throws BeansException {     return doGetBean(name, null, args, false);   }

查看doGetBean方法:

protected <T> T doGetBean(        final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)     throws BeansException {
  final String beanName = transformedBeanName(name);  Object bean;
  // Eagerly check singleton cache for manually registered singletons. //从缓存入手。处理单例bean   Object sharedInstance = getSingleton(beanName);   if (sharedInstance != null && args == null) {       if (logger.isDebugEnabled()) {           if (isSingletonCurrentlyInCreation(beanName)) {              logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +                       "' that is not fully initialized yet - a consequence of a circular reference");           }            else {             logger.debug("Returning cached instance of singleton bean '" + beanName + "'");            }        }        //对FactoryBean的处理,获取FactoryBean的相关实例。     bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  }
  else {     // Fail if we're already creating this bean instance:        // We're assumably within a circular reference.      if (isPrototypeCurrentlyInCreation(beanName)) {          throw new BeanCurrentlyInCreationException(beanName);      }
      // Check if bean definition exists in this factory.      //减产是否已经存在相应的BeanDefinition对象     BeanFactory parentBeanFactory = getParentBeanFactory();     if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {            // Not found -> check parent.         String nameToLookup = originalBeanName(name);         if (args != null) {               // Delegation to parent with explicit args.              return (T) parentBeanFactory.getBean(nameToLookup, args);            }            else {             // No args -> delegate to standard getBean method.                return parentBeanFactory.getBean(nameToLookup, requiredType);            }        }
      if (!typeCheckOnly) {          markBeanAsCreated(beanName);       }
      try {          //依据Bean的名字获取BeanDefinition         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);          checkMergedBeanDefinition(mbd, beanName, args);
          // Guarantee initialization of beans that the current bean depends on.           //获取当前bean的全部依赖bean           String[] dependsOn = mbd.getDependsOn();           if (dependsOn != null) {              for (String dependsOnBean : dependsOn) {                 if (isDependent(beanName, dependsOnBean)) {                        throw new BeanCreationException("Circular depends-on relationship between '" +                              beanName + "' and '" + dependsOnBean + "'");                  }                    registerDependentBean(dependsOnBean, beanName);//注冊依赖bean                 getBean(dependsOnBean);//获取bean的递归调用               }            }
          // Create bean instance.         //创建单例bean           if (mbd.isSingleton()) {             sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {                 @Override                    public Object getObject() throws BeansException {                        try {                          return createBean(beanName, mbd, args);                      }                        catch (BeansException ex) {                            // Explicitly remove instance from singleton cache: It might have been put there                         // eagerly by the creation process, to allow for circular reference resolution.                          // Also remove any beans that received a temporary reference to the bean.                            destroySingleton(beanName);                            throw ex;                      }                    }                });              bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);          }
          else if (mbd.isPrototype()) {// property bean               // It's a prototype -> create a new instance.             Object prototypeInstance = null;             try {                  beforePrototypeCreation(beanName);                 prototypeInstance = createBean(beanName, mbd, args);             }                finally {                  afterPrototypeCreation(beanName);              }                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);           }
          else {             String scopeName = mbd.getScope();//其它scope              final Scope scope = this.scopes.get(scopeName);              if (scope == null) {                  throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");                }                try {                  Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {                        @Override                        public Object getObject() throws BeansException {                            beforePrototypeCreation(beanName);                         try {                              return createBean(beanName, mbd, args);                          }                            finally {                              afterPrototypeCreation(beanName);                          }                        }                    });                  bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);              }                catch (IllegalStateException ex) {                 throw new BeanCreationException(beanName,                          "Scope '" + scopeName + "' is not active for the current thread; " +                         "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",                           ex);             }            }        }        catch (BeansException ex) {            cleanupAfterBeanCreationFailure(beanName);         throw ex;      }    }
  // Check if required type matches the type of the actual bean instance.  //检查bean的类型。   if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {     try {          return getTypeConverter().convertIfNecessary(bean, requiredType);        }        catch (TypeMismatchException ex) {         if (logger.isDebugEnabled()) {               logger.debug("Failed to convert bean '" + name + "' to required type [" +                       ClassUtils.getQualifiedName(requiredType) + "]", ex);           }            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());       }    }    return (T) bean;}

这种方法就是依赖注入的入口,由于他触发了依赖注入。

虽然能够以最简单的方法来描写叙述Spring
IoC容器,即Spring容器就是一个HashMap,通过HashMap来管理BeanDefinition对象。

在getBean()的时候,会触发createBean()来进创建须要的Bean对象。

    ​终于的调用,到AbstractAutowireCapableBeanFactory的createBean()方法,代码例如以下:

/**  * Central method of this class: creates a bean instance,    * populates the bean instance, applies post-processors, etc.    * @see #doCreateBean    */ @Override    protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)          throws BeanCreationException {
      if (logger.isDebugEnabled()) {           logger.debug("Creating instance of bean '" + beanName + "'");      }      // Make sure bean class is actually resolved at this point.
//推断须要创建的Bean是否可实例化,这个类是否可通过类装载器来加载        resolveBeanClass(mbd, beanName);
      // Prepare method overrides.     try {          mbd.prepareMethodOverrides();      }        catch (BeanDefinitionValidationException ex) {         throw new BeanDefinitionStoreException(mbd.getResourceDescription(),                 beanName, "Validation of method overrides failed", ex);       }
      try {            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
//假设Bean配置了BeanPostProcessors,则返回代理对象          Object bean = resolveBeforeInstantiation(beanName, mbd);            if (bean != null) {               return bean;           }        }        catch (Throwable ex) {         throw new BeanCreationException(mbd.getResourceDescription(), beanName,                    "BeanPostProcessor before instantiation of bean failed", ex);     }
//创建bean

      Object beanInstance = doCreateBean(beanName, mbd, args);      if (logger.isDebugEnabled()) {           logger.debug("Finished creating instance of bean '" + beanName + "'");     }        return beanInstance;   }

再查看doCreateBean()方法:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {       // Instantiate the bean.     BeanWrapper instanceWrapper = null;        if (mbd.isSingleton()) {//假设是单例的。则移除缓存中的同name bean          instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);     }        if (instanceWrapper == null) {//创建Bean          instanceWrapper = createBeanInstance(beanName, mbd, args);       }        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);     Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
      // Allow post-processors to modify the merged bean definition.       synchronized (mbd.postProcessingLock) {          if (!mbd.postProcessed) {                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);              mbd.postProcessed = true;         }        }
      // Eagerly cache singletons to be able to resolve circular references        // even when triggered by lifecycle interfaces like BeanFactoryAware.        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&              isSingletonCurrentlyInCreation(beanName));     if (earlySingletonExposure) {          if (logger.isDebugEnabled()) {               logger.debug("Eagerly caching bean '" + beanName +                      "' to allow for resolving potential circular references");            }            addSingletonFactory(beanName, new ObjectFactory<Object>() {             @Override                public Object getObject() throws BeansException {                    return getEarlyBeanReference(beanName, mbd, bean);               }            });      }
      // Initialize the bean instance.初始化bean。通常在此处发生依赖注入     Object exposedObject = bean;        try {          populateBean(beanName, mbd, instanceWrapper);          if (exposedObject != null) {              exposedObject = initializeBean(beanName, exposedObject, mbd);            }        }        catch (Throwable ex) {         if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {              throw (BeanCreationException) ex;         }            else {             throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);           }        }
      if (earlySingletonExposure) {          Object earlySingletonReference = getSingleton(beanName, false);          if (earlySingletonReference != null) {                if (exposedObject == bean) {                 exposedObject = earlySingletonReference;               }                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {                   String[] dependentBeans = getDependentBeans(beanName);                 Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);                 for (String dependentBean : dependentBeans) {                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {                          actualDependentBeans.add(dependentBean);                     }                    }                    if (!actualDependentBeans.isEmpty()) {                       throw new BeanCurrentlyInCreationException(beanName,                               "Bean with name '" + beanName + "' has been injected into other beans [" +                               StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +                               "] in its raw version as part of a circular reference, but has eventually been " +                             "wrapped. This means that said other beans do not use the final version of the " +                             "bean. This is often the result of over-eager type matching - consider using " +                               "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");                  }                }            }        }
      // Register bean as disposable.      try {          registerDisposableBeanIfNecessary(beanName, bean, mbd);        }        catch (BeanDefinitionValidationException ex) {         throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);       }
      return exposedObject;  }

与依赖注入相关的两个方法:createBeanInstance和populateBean。

 

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {      // Make sure bean class is actually resolved at this point.
//确认须要创建实例的类能够实例化        Class<?> beanClass = resolveBeanClass(mbd, beanName);
      if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {         throw new BeanCreationException(mbd.getResourceDescription(), beanName,                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());       }
//工厂方法实例化     if (mbd.getFactoryMethodName() != null)  {return instantiateUsingFactoryMethod(beanName, mbd, args);      }
      // Shortcut when re-creating the same bean...        boolean resolved = false;     boolean autowireNecessary = false;        if (args == null) {           synchronized (mbd.constructorArgumentLock) {             if (mbd.resolvedConstructorOrFactoryMethod != null) {                   resolved = true;                    autowireNecessary = mbd.constructorArgumentsResolved;                }            }        }        if (resolved) {            if (autowireNecessary) {               return autowireConstructor(beanName, mbd, null, null);           }            else {             return instantiateBean(beanName, mbd);         }        }
      //构造函数实例化       Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);     if (ctors != null ||             mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||              mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {          return autowireConstructor(beanName, mbd, ctors, args);        }
      // 使用无參构造函数      return instantiateBean(beanName, mbd); }

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
//使用CGLIB对bean进行实例化。
      try {          Object beanInstance;          final BeanFactory parent = this;           if (System.getSecurityManager() != null) {               beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {                    @Override                    public Object run() {                     return getInstantiationStrategy().instantiate(mbd, beanName, parent);                  }                }, getAccessControlContext());         }            else {             beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);          }            BeanWrapper bw = new BeanWrapperImpl(beanInstance);         initBeanWrapper(bw);           return bw;     }        catch (Throwable ex) {         throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);        }    }

在Bean实例化后,就是相关的依赖关系。

    ​依赖注入的发生是在BeanWrapper的setPropertyValues中实现。详细实现是在BeanWrapper的子类,BeanWrapperImpl中实现。

以上便是整个IoC过程创建Bean的总体思路。与书中相比,省略了部分代码。

代码清单2-7
启动BeanDefinition的载入

ApplicationContext和Bean的初始化及销毁

    ​ApplicationContext的启动是在AbstractApplicationContext中实现。

    ​相同的销毁操作是在doClose()方法中完毕。

protected void doClose() {        boolean actuallyClose;     synchronized (this.activeMonitor) {          actuallyClose = this.active && !this.closed;            this.closed = true;        }
      if (actuallyClose) {           if (logger.isInfoEnabled()) {                logger.info("Closing " + this);          }
          LiveBeansView.unregisterApplicationContext(this);
          try {              // Publish shutdown event.               publishEvent(new ContextClosedEvent(this));           }            catch (Throwable ex) {             logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);          }
          // Stop all Lifecycle beans, to avoid delays during individual destruction.          try {              getLifecycleProcessor().onClose();         }            catch (Throwable ex) {             logger.warn("Exception thrown from LifecycleProcessor on context close", ex);          }
          // Destroy all cached singletons in the context's BeanFactory.           destroyBeans();
          // Close the state of this context itself.           closeBeanFactory();
          // Let subclasses do some final clean-up if they wish...         onClose();
          synchronized (this.activeMonitor) {              this.active = false;           }        }    }

    ​Bean的销毁和创建,Spring通过IoC管理Bean的生命周期来实现。

Spring中Bean的生命周期包括:

    ​    ​-1。Bean实例的创建。

    ​    ​-2,为Bean实例设置属性。

    ​    ​-3。调用Bean的初始化方法。

    ​    ​-4,通过IoC获取Bean。

    ​    ​-5,当容器关闭的时候调用bean的销毁方法。

图片 5图片 6

总结

    ​BeanDefinition的定位。对IoC容器来说,它为管理POJO直接的关系提供了帮助,但也要依据Spring的定义规则提供Bean定义信息。在Bean定义方面,Spring为用户提供了非常大的灵活性。在初始化过程中,首先须要定义到这些有效地Bean定义信息。这里Spring使用Resource接口来统一这些信息。而定位由ResourceLoader完毕。

    ​容器的初始化。容器的初始化过程是在refresh()方法中完毕的。这个refresh()相当于容器的初始化函数。在初始化中,比較重要的就是对Bean信息的加载和注冊功能。

 1 public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
 2             throws BeansException {
 3 
 4         super(parent);
 5         setConfigLocations(configLocations);
 6         // 这里调用容器的refresh,是载入BeanDefinition的入口
 7         if (refresh) {
 8             refresh();
 9         }
10     }

启动BeanDefinition的载入

 7.对容器的启动来说,refresh是一个很重要的方法,下面介绍一下他的实现。

8.该方法在AbstractApplicationContext类(它是FileSystemXmlApplicationContext的基类)中找到,它详细地描述了整个ApplicationContext的初始化过程,比如BeanFactory的更新,MessageSource和PostProcessor的注册,等等。

9.这里看起来更像是对ApplicationContext进行初始化的模块或执行提纲,这个执行过程为Bean的生命周期管理提供了条件。

10.熟悉IoC容器使用的读者,从这一系列调用的名字就能大致了解应用上下文初始化的主要内容。这里就直接列出代码,不做太多的解释了。这个IoC容器的refresh过程如代码清单2-8所示。

代码清单2-8
 对IoC容器执行refresh的过程

图片 7图片 8

 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             // 这里是在子类中启动refreshBeanFactory()的地方
 8             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 9 
10             // Prepare the bean factory for use in this context.
11             prepareBeanFactory(beanFactory);
12 
13             try {
14                 // 设置BeanFactory的后置处理
15                 // Allows post-processing of the bean factory in context subclasses.
16                 postProcessBeanFactory(beanFactory);
17                 
18                 // 调用BeanFactory的后处理器,这些后处理器是在Bean定义中向容器注册的
19                 // Invoke factory processors registered as beans in the context.
20                 invokeBeanFactoryPostProcessors(beanFactory);
21                 
22                 // 注册Bean的后处理器,在Bean创建过程中调用
23                 // Register bean processors that intercept bean creation.
24                 registerBeanPostProcessors(beanFactory);
25                 
26                 // 对上下文中的消息源进行初始化
27                 // Initialize message source for this context.
28                 initMessageSource();
29                 
30                 // 初始化上下文中的事件机制
31                 // Initialize event multicaster for this context.
32                 initApplicationEventMulticaster();
33                 
34                 // 初始化其他的特殊Bean
35                 // Initialize other special beans in specific context subclasses.
36                 onRefresh();
37                 
38                 // 检查监听Bean并且将这些Bean向容器注册
39                 // Check for listener beans and register them.
40                 registerListeners();
41                 
42                 // 实例化所有的(non-lazy-init)单件
43                 // Instantiate all remaining (non-lazy-init) singletons.
44                 finishBeanFactoryInitialization(beanFactory);
45                 
46                 // 发布容器事件,结束Refresh过程
47                 // Last step: publish corresponding event.
48                 finishRefresh();
49             }
50 
51             catch (BeansException ex) {
52                 logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
53                 
54                 // 为防止Bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件Bean
55                 // Destroy already created singletons to avoid dangling resources.
56                 destroyBeans();
57                 
58                 // 重置 'active'标志
59                 // Reset 'active' flag.
60                 cancelRefresh(ex);
61 
62                 // Propagate exception to caller.
63                 throw ex;
64             }
65         }
66     }

相关文章

No Comments, Be The First!
近期评论
    功能
    网站地图xml地图