zoukankan      html  css  js  c++  java
  • 1.2 XmlBeanFactory的实例化

      源代码分析,是一件既痛苦又快乐的事情,看别人写的代码是通过的,但当你能够看明白的时候,相信快乐也会随之而来,为了减少痛苦,更快的带来快乐,

      本文以spring框架的XmlBeanFactory为入手点进行分析

     首先来打开该类的代码,我们将看到如下代码:

     1 public class XmlBeanFactory extends DefaultListableBeanFactory {
     2 
     3    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
     4 
     5    public XmlBeanFactory(Resource resource) throws BeansException {
     6        this(resource, null);
     7    }
     8 
     9    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
    10        super(parentBeanFactory);
    11        this.reader.loadBeanDefinitions(resource);
    12    }
    13 
    14 }

      这个类的代码很简单,一个成员对象加两个构造函数,从这里我们可以看出,最重要的地方在于最后一个构造函数:

    1 public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
    2         super(parentBeanFactory);
    3         this.reader.loadBeanDefinitions(resource);
    4     }

    第一句就是将父亲工厂交给父类的构造函数,

      实际上最后也就是把父工厂保存到类的parentBeanFactory成员对象中,这个对象是在AbstractBeanFactory抽象类中定义的,而这个父工厂也会一直传递到该抽象类进行保存。

      第二句就是整个类中最重要的地方了,顾名思义,它的目的是通过XmlBeanDefinitionReader这个XML的Reader从资源resource中(也就是你的配置文件)读取bean的定义。

      接下来我们打开XmlBeanDefinitionReader的loadBeanDefinitions方法,我们可看到在这个方法里代码就一行,调用了一个同名不同参的方法,而参数是EncodedResource的一个实例,这个类实际上是Resource的一个包装类,用来保存资源的Encode的,

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

    那接下来我们再看被调用的loadBeanDefinitions方法,

     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     try {
     2             InputStream inputStream = encodedResource.getResource().getInputStream();
     3             try {
     4                 InputSource inputSource = new InputSource(inputStream);
     5                 if (encodedResource.getEncoding() != null) {
     6                     inputSource.setEncoding(encodedResource.getEncoding());
     7                 }
     8                 return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
     9             }
    10             finally {
    11                 inputStream.close();
    12             }
    13         }

    这里的目的是将资源包装成一个InputSource,连同Resource作为参数传递到doLoadBeanDefinitions方法

     1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
     2             throws BeanDefinitionStoreException {
     3         try {
     4             Document doc = doLoadDocument(inputSource, resource);
     5             return registerBeanDefinitions(doc, resource);
     6         }
     7         catch (BeanDefinitionStoreException ex) {
     8             throw ex;
     9         }
    10         catch (SAXParseException ex) {
    11             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    12                     "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
    13         }
    14         catch (SAXException ex) {
    15             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    16                     "XML document from " + resource + " is invalid", ex);
    17         }
    18         catch (ParserConfigurationException ex) {
    19             throw new BeanDefinitionStoreException(resource.getDescription(),
    20                     "Parser configuration exception parsing XML from " + resource, ex);
    21         }
    22         catch (IOException ex) {
    23             throw new BeanDefinitionStoreException(resource.getDescription(),
    24                     "IOException parsing XML document from " + resource, ex);
    25         }
    26         catch (Throwable ex) {
    27             throw new BeanDefinitionStoreException(resource.getDescription(),
    28                     "Unexpected exception parsing XML document from " + resource, ex);
    29         }
    30     }

      很遗憾,这个类没有什么实际作为,只有一些对异常的处理.把解析的逻辑委托给了doLoadDocument这个方法

    然后调用registerBeanDefinitions方法,注册Bean的信息

    1     protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
    2         return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
    3                 getValidationModeForResource(resource), isNamespaceAware());
    4     }

    就是为了将资源解释成为Document对象,这里不做详细解释,不了解的话请去看看关于JAXP的介绍。

     1 public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
     2             ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
     3 
     4         DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
     5         if (logger.isDebugEnabled()) {
     6             logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
     7         }
     8         DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
     9         return builder.parse(inputSource);
    10     }
    来看看registerBeanDefinitions的实现 
     
    1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    2         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    3         documentReader.setEnvironment(this.getEnvironment());
    4         int countBefore = getRegistry().getBeanDefinitionCount();
    5         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    6         return getRegistry().getBeanDefinitionCount() - countBefore;
    7     }

      在这里, 有一个BeanDefinitionDocumentReader接口, 实际上Spring对它有一个默认的实现类叫DefaultBeanDefinitionDocumentReader, 来看看它的家族 

    BeanDefinitionDocumentReader只有2个方法 ,

    registerBeanDefinitions就是其中一个
     1 public interface BeanDefinitionDocumentReader {
     2 
     3     /**
     4      * Set the Environment to use when reading bean definitions.
     5      * <p>Used for evaluating profile information to determine whether a
     6      * {@code <beans/>} document/element should be included or ignored.
     7      */
     8     void setEnvironment(Environment environment);
     9 
    10     /**
    11      * Read bean definitions from the given DOM document and
    12      * register them with the registry in the given reader context.
    13      * @param doc the DOM document
    14      * @param readerContext the current context of the reader
    15      * (includes the target registry and the resource being parsed)
    16      * @throws BeanDefinitionStoreException in case of parsing errors
    17      */
    18     void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
    19             throws BeanDefinitionStoreException;
    20 
    21 }

      该方法需要两个参数, 一个是Document模型,这个应该是我们读取配置文件获取到的, 另一个是XmlReaderContext对象, 我们在上面方法中看到是通过createReaderContext(resource)得到的, 那就看看具体如何得到 

    1 public XmlReaderContext createReaderContext(Resource resource) {
    2         return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
    3                 this.sourceExtractor, this, getNamespaceHandlerResolver());
    4     }

      能过构造函数new出来的, 且有一个重要参数resource 
    再继续来看DefaultBeanDefinitionDocumentReader对BeanDefinitionDocumentReader的registerBeanDefinitions方法实现 

    1 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    2         this.readerContext = readerContext;
    3         logger.debug("Loading bean definitions");
    4         Element root = doc.getDocumentElement();
    5         doRegisterBeanDefinitions(root);
    6     }

     是的

     1     protected void doRegisterBeanDefinitions(Element root) {
     2         String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
     3         if (StringUtils.hasText(profileSpec)) {
     4             Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
     5             String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
     6                     profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
     7             if (!this.environment.acceptsProfiles(specifiedProfiles)) {
     8                 return;
     9             }
    10         }
    11 
    12         // Any nested <beans> elements will cause recursion in this method. In
    13         // order to propagate and preserve <beans> default-* attributes correctly,
    14         // keep track of the current (parent) delegate, which may be null. Create
    15         // the new (child) delegate with a reference to the parent for fallback purposes,
    16         // then ultimately reset this.delegate back to its original (parent) reference.
    17         // this behavior emulates a stack of delegates without actually necessitating one.
    18         BeanDefinitionParserDelegate parent = this.delegate;
    19         this.delegate = createDelegate(this.readerContext, root, parent);
    20 
    21         preProcessXml(root);
    22         parseBeanDefinitions(root, this.delegate);
    23         postProcessXml(root);
    24 
    25         this.delegate = parent;
    26     }

    嘿嘿, 开始解析Dom了哦, 其中主要是parseBeanDefinitions方法, 来看看具体是如何解析的 

    这里创建了一个XmlBeanDefinitionParser接口的实现,这个接口的具体类是DefaultXmlBeanDefinitionParser,这个接口很简单,只有registerBeanDefinitions一个方法,这个方法的作用也很明了,就是用来注册Bean的定义的,所以说类和方法的名字一定要起得有意义,这样可以让人一看就大概了解其作用,减少了很多阅读代码的痛苦。废话不多说,我们打开DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,这个类就是解释XML配置文件的核心类了,打开registerBeanDefinitions方法后我们看到如下代码:

     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     }

      看到了吧, 循环解析Domcument节点 
    parseDefaultElement方法和delegate的parseCustomElement方法 
    先来看parseDefaultElement方法 

     1 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
     2         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
     3             importBeanDefinitionResource(ele);
     4         }
     5         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
     6             processAliasRegistration(ele);
     7         }
     8         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
     9             processBeanDefinition(ele, delegate);
    10         }
    11         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    12             // recurse
    13             doRegisterBeanDefinitions(ele);
    14         }
    15     }

    看到这就很清楚了, 就是根据节点的名称作不同解析, 如我们Spring配置文件中常有以下几种配置 

     
    <import resource="classpath:xxx" /> 
    <bean id="car" class="entity.CarFactoryBean">
            <property name="carInfo" value="超级跑车,400,2000000" />
        </bean>

    对<import>节点, 调用importBeanDefinitionResource方法解析, 此方法中, 又回到第一步读取配置文件并解析. 如此递归循环. 

    ...
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
              importBeanDefinitionResource(ele);
    }
    ...

    对<alias>节点, 调用processAliasRegistration进行别名解析 

    ...
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
                processAliasRegistration(ele);
            }
    ...

    我们主要看对<bean>节点调用processBeanDefinition进行解析 

     
    ...
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
                processBeanDefinition(ele, delegate);
            }
    ...
    processBeanDefinition:
     1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
     2         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
     3         if (bdHolder != null) {
     4             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
     5             try {
     6                 // Register the final decorated instance.
     7                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
     8             }
     9             catch (BeanDefinitionStoreException ex) {
    10                 getReaderContext().error("Failed to register bean definition with name '" +
    11                         bdHolder.getBeanName() + "'", ele, ex);
    12             }
    13             // Send registration event.
    14             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    15         }
    16     }

      嘿嘿, 又用到delegate对象了, 且调用它的parseBeanDefinitionElement方法, 返回一个BeanDefinitionHolder, 进去看它的parseBeanDefinitionElement方法 

    1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    2         return parseBeanDefinitionElement(ele, null);
    3     }

    parseBeanDefinitionElement

     1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
     2         String id = ele.getAttribute(ID_ATTRIBUTE);
     3         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
     4         //解析id, name等属性, 
     5         List<String> aliases = new ArrayList<String>();
     6         if (StringUtils.hasLength(nameAttr)) {
     7             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
     8             aliases.addAll(Arrays.asList(nameArr));
     9         }
    10 
    11         String beanName = id;
    12         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
    13             beanName = aliases.remove(0);
    14             if (logger.isDebugEnabled()) {
    15                 logger.debug("No XML 'id' specified - using '" + beanName +
    16                         "' as bean name and " + aliases + " as aliases");
    17             }
    18         }
    19         //并验证beanName是否唯一, 并将beanName保存在aliases中 
    20         if (containingBean == null) {
    21             checkNameUniqueness(beanName, aliases, ele);
    22         }
    23         //解析bean定义本身,而不考虑名称或别名。可能返回null,如果bean定义的解析过程中出现的问题
    24         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    25         if (beanDefinition != null) {
    26             if (!StringUtils.hasText(beanName)) {
    27                 try {
    28                     if (containingBean != null) {
    29                         beanName = BeanDefinitionReaderUtils.generateBeanName(
    30                                 beanDefinition, this.readerContext.getRegistry(), true);
    31                     }
    32                     else {
    33                         beanName = this.readerContext.generateBeanName(beanDefinition);
    34                         // Register an alias for the plain bean class name, if still possible,
    35                         // if the generator returned the class name plus a suffix.
    36                         // This is expected for Spring 1.2/2.0 backwards compatibility.
    37                         String beanClassName = beanDefinition.getBeanClassName();
    38                         if (beanClassName != null &&
    39                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
    40                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
    41                             aliases.add(beanClassName);
    42                         }
    43                     }
    44                     if (logger.isDebugEnabled()) {
    45                         logger.debug("Neither XML 'id' nor 'name' specified - " +
    46                                 "using generated bean name [" + beanName + "]");
    47                     }
    48                 }
    49                 catch (Exception ex) {
    50                     error(ex.getMessage(), ele);
    51                     return null;
    52                 }
    53             }
    54             String[] aliasesArray = StringUtils.toStringArray(aliases);
    55             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    56         }
    57 
    58         return null;
    59     }

      可以看到, 在BeanDefinitionHolder中保存了BeanDefinition的定义 
    OK, 重头戏开始, 最经典的部分出现了, 请看parseBeanDefinitionElement方法 

     1 public AbstractBeanDefinition parseBeanDefinitionElement(
     2             Element ele, String beanName, BeanDefinition containingBean) {
     3 
     4         this.parseState.push(new BeanEntry(beanName));
     5 
     6         String className = null;
     7         if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
     8             className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
     9         }
    10 
    11         try {
    12             String parent = null;
    13             if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
    14                 parent = ele.getAttribute(PARENT_ATTRIBUTE);
    15             }
    16             AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    17 
    18             parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
    19             bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    20 
    21             parseMetaElements(ele, bd);
    22             parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
    23             parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    24 
    25             parseConstructorArgElements(ele, bd);
    26             parsePropertyElements(ele, bd);
    27             parseQualifierElements(ele, bd);
    28 
    29             bd.setResource(this.readerContext.getResource());
    30             bd.setSource(extractSource(ele));
    31 
    32             return bd;
    33         }
    34         catch (ClassNotFoundException ex) {
    35             error("Bean class [" + className + "] not found", ele, ex);
    36         }
    37         catch (NoClassDefFoundError err) {
    38             error("Class that bean class [" + className + "] depends on not found", ele, err);
    39         }
    40         catch (Throwable ex) {
    41             error("Unexpected failure during bean definition parsing", ele, ex);
    42         }
    43         finally {
    44             this.parseState.pop();
    45         }
    46 
    47         return null;
    48     }

      在这个方法中, 解析了bean的所有属性, 有最常用的class, scope, lazy-init等等. 并返回一个AbstractBeanDefinition实例. 至于具体怎么解析, 就只能进一步跟踪了, 不过既然到了这一步, 已经明白了它的基本原理, 具体实现就不作介绍 

     1 public static AbstractBeanDefinition createBeanDefinition(
     2             String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
     3 
     4         GenericBeanDefinition bd = new GenericBeanDefinition();
     5         bd.setParentName(parentName);
     6         if (className != null) {
     7             if (classLoader != null) {
     8                 bd.setBeanClass(ClassUtils.forName(className, classLoader));
     9             }
    10             else {
    11                 bd.setBeanClassName(className);
    12             }
    13         }
    14         return bd;
    15     }

      这一步将节点解析成BeanDefinitionHolder对象, 再看看如何注册, 回到DefaultBeanDefinitionDocumentReader的processBeanDefinition方法 
    看到对解析到的bdHolder对象又做了decorateBeanDefinitionIfRequired操作, 来看看实现

    1 public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
    2         return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
    3     }
    decorateBeanDefinitionIfRequired 
     1 public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
     2             Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {
     3 
     4         BeanDefinitionHolder finalDefinition = definitionHolder;
     5 
     6         // Decorate based on custom attributes first.
     7         NamedNodeMap attributes = ele.getAttributes();
     8         for (int i = 0; i < attributes.getLength(); i++) {
     9             Node node = attributes.item(i);
    10             finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
    11         }
    12 
    13         // Decorate based on custom nested elements.
    14         NodeList children = ele.getChildNodes();
    15         for (int i = 0; i < children.getLength(); i++) {
    16             Node node = children.item(i);
    17             if (node.getNodeType() == Node.ELEMENT_NODE) {
    18                 finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
    19             }
    20         }
    21         return finalDefinition;
    22     }

    这里关键就2行代码,主要是做一些合法性验证,比如 文件头,语法,属性的合法性,由于代码过长不一一解释,代码如下

     1 public BeanDefinitionHolder decorateIfRequired(
     2             Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {
     3 
     4         String namespaceUri = getNamespaceURI(node);
     5         if (!isDefaultNamespace(namespaceUri)) {
     6             NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
     7             if (handler != null) {
     8                 return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
     9             }
    10             else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) {
    11                 error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
    12             }
    13             else {
    14                 // A custom namespace, not to be handled by Spring - maybe "xml:...".
    15                 if (logger.isDebugEnabled()) {
    16                     logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
    17                 }
    18             }
    19         }
    20         return originalDef;
    21     }

    回到DefaultBeanDefinitionDocumentReade.processBeanDefinition这个方法 只行完delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);之后

    接着调用了BeanDefinitionReaderUtils的registerBeanDefinition方法注册bdHolder, 来看看如何实现的 

     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     }
       看吧, 又调用了BeanDefinitionRegistry的registerBeanDefinition方法, 跟踪之 (这个要看DefaultListableBeanFactory的实现) 
     
     
     1 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
     2             throws BeanDefinitionStoreException {
     3 
     4         Assert.hasText(beanName, "Bean name must not be empty");
     5         Assert.notNull(beanDefinition, "BeanDefinition must not be null");
     6 
     7         if (beanDefinition instanceof AbstractBeanDefinition) {
     8             try {
     9                 ((AbstractBeanDefinition) beanDefinition).validate();
    10             }
    11             catch (BeanDefinitionValidationException ex) {
    12                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    13                         "Validation of bean definition failed", ex);
    14             }
    15         }
    16 
    17         synchronized (this.beanDefinitionMap) {
    18             BeanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    19             if (oldBeanDefinition != null) {
    20                 if (!this.allowBeanDefinitionOverriding) {
    21                     throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    22                             "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
    23                             "': There is already [" + oldBeanDefinition + "] bound.");
    24                 }
    25                 else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
    26                     // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
    27                     if (this.logger.isWarnEnabled()) {
    28                         this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
    29                                 " with a framework-generated bean definition ': replacing [" +
    30                                 oldBeanDefinition + "] with [" + beanDefinition + "]");
    31                     }
    32                 }
    33                 else {
    34                     if (this.logger.isInfoEnabled()) {
    35                         this.logger.info("Overriding bean definition for bean '" + beanName +
    36                                 "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
    37                     }
    38                 }
    39             }
    40             else {
    41                 this.beanDefinitionNames.add(beanName);
    42                 this.frozenBeanDefinitionNames = null;
    43             }
    44             this.beanDefinitionMap.put(beanName, beanDefinition);
    45         }
    46 
    47         resetBeanDefinition(beanName);
    48     }

      这里, 看到了一个最最重要的对象就是beanDefinitionMap, 这个map存放了所有的bean对象, 和我们通常讲的容器概念最为接近, getBean时实际是也是从这里领取对象, 相同的还有一个beanDefinitionNames, 但这个只保存bean的名称 
    完成上面之后, 还有一步操作beanFactory.registerAlias(beanName, aliases[i]); 
    这个实现实际是上AbstractBeanFactory抽象类所定义的 

    是不是特兴奋, 已经揭开它神秘的面纱了 
    定义 -> 定位 -> 装载 -> 注册 这几步已经完成了, 以后继续看Spring是如何创建bean及实例化的

    多数内容来自:http://leayer.iteye.com/blog/806016

     
  • 相关阅读:
    css实现垂直居中
    js验证输入框
    textarea统计字数
    ajax提交form表单
    JS中的正则表达式
    《遮蔽层的隐藏块》
    2016各大互联网公司前端面试题汇总
    JQ 添加节点和插入节点的方法总结
    [原]CentOS7部署osm2pgsql
    [原]CentOS7部署PostGis
  • 原文地址:https://www.cnblogs.com/mjorcen/p/3631239.html
Copyright © 2011-2022 走看看