Analysis of default tags and registration of Beans in Spring source code analysis

In front of us the read and create XML Spring source container parsing of the configuration , create Spring IOC container is DefaultListableBeanFactory created, load the configuration file is eventually resolved to Document instance, this article, we introduce analytical and Bean Configuration tab In the previous article, we finally saw that the label resolution and Bean registration were completed in the registerBeanDefinitions( doc , resource ) method of XmlBeanDefinitionReader . Let’s check the source code of this method:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //标签的解析最终是通过BeanDefinitionDocumentReader 解析的,本行代码创建了一个  BeanDefinitionDocumentReader 实例
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    //调用registerBeanDefinitions方法解析
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

From the above code, you can see that the resolution of the label is finally completed by the BeanDefinitionDocumentReader instance. Here we focus on createReaderContext( resource ) , which returns an XmlReaderContext instance. Because this method will pass in our DefaultListableBeanFactory instance. code show as below:

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

As shown in the above method, createReaderContext(Resource resource ) passes in a this object, which is an instance of XmlBeanDefinitionReader . It is clear that it is passed in XmlBeanDefinitionReader. Why does it say that a DefaultListableBeanFactory instance is passed in? In the previous explanation of loading configuration, we used the XmlBeanDefinitionReader construction method to pass in a DefaultListableBeanFactory instance. Therefore, we will use the XmlReaderContext instance created by createReaderContext(Resource resource ) to obtain our IOC container, which is the DefaultListableBeanFactory instance. Next, we then cut how BeanDefinitionDocumentReader parses the configuration.

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

The above code is relatively simple, get the root element of the configuration, and then parse the root element, we continue to look at the doRegisterBeanDefinitions (Element root) method, the analysis of the element is finally delegated to the BeanDefinitionParserDelegate instance to complete.

protected void doRegisterBeanDefinitions(Element root){
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);
    .....//这部分代码省略,判断是否是profile指定的配置,如果不是则返回
    preProcessXml(root);
    //解析配置
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);
    this.delegate = parent;
}

The following code is the logic of createDelegate(getReaderContext(), root , parent ) to create an instance of BeanDefinitionParserDelegate :

protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
    //创建BeanDefinitionParserDelegate 实例
    BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
    //做一些初始化工作
    delegate.initDefaults(root, parentDelegate);
    return delegate;
}

The source code analysis says here, the follow-up is to use BeanDefinitionParserDelegate to parse the label to register the Bean. Let’s continue to look at the method parseBeanDefinitions( root , this . delegate ); this part of the code is relatively simple, judging whether the label is a default label or a custom label, according to Node’s getNamespaceURI( ) Is http://www.springframework.org/schema/beans or null to determine whether it is the default space.

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    //如果是默认命名空间解析默认的标签
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                    if (node instanceof Element) {
                        Element ele = (Element) node;
			if (delegate.isDefaultNamespace(ele)) {
                            //解析默认标签
			    parseDefaultElement(ele, delegate);
			} else {
                            //解析自定义标签
			    delegate.parseCustomElement(ele);
			}
		    }
		}
	} else {
    //否则解析自定义标签
    delegate.parseCustomElement(root);
    }
}

The above method uses different methods to parse tags according to whether the node's namespace is the default namespace. In this article, we mainly introduce the parseDefaultElement( ele , delegate ) method. The source code is as follows:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
       //import标签
        importBeanDefinitionResource(ele);
    } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
       //alias标签
        processAliasRegistration(ele);
    } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        //Bean标签
        processBeanDefinition(ele, delegate);
    } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // beans标签
        doRegisterBeanDefinitions(ele);
    }
}

The import tag is used to parse the imported resource and finally encapsulated as a Resource instance. The alias is to register the alias for the Bean, which will eventually be stored in the Map variable of the SimpleAliasRegistry. DefaultListableBeanFactory inherits the SimpleAliasRegistry class. What we want to focus on is the analysis of bean tags. That is, the processBeanDefinition method: the code is as follows:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //这里会解析bean标签并且将Bean标签包装为BeanDefinitionHolder 实例
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            //注册Bean
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
	} ......//异常以及其他逻辑
    }
}

In the above method, there are two parts. One is the final encapsulation of the analysis element as a BeanDefinitionHolder , and the Bean is registered in the container. We first look at how to register the Bean in the container, and then look at the label analysis. Registered Bean is the BeanDefinitionReaderUtils. registerBeanDefinition ( bdHolder ,getReaderContext().getRegistry()) one line of code, we view the source code:

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {
    //获取Bean的名称
    String beanName = definitionHolder.getBeanName();
    //注册Bean
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    //为bean 注册别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

The above code by calling BeanDefinitionRegistry of registerBeanDefinition registered Bean, BeanDefinitionRegistry (...) method is DefaultListableBeanFactory interface, as follows BeanDefinitionRegistry implementation:

 The above is only a partial implementation, of which DefaultListableBeanFactory , GenericApplicationContext and SimpleBeanDefinitionRegistry all implement the registerBeanDefinition (...) method, SimpleBeanDefinitionRegistry is just a simple container, nothing is done, there is a map to store the relationship between the Bean name and the Bean, GenericApplicationContext finally The method of DefaultListableBeanFactory is called , so we only need to pay attention to DefaultListableBeanFactory . The code is as follows:

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代码
    //声明一个BeanDefiinition实例
    BeanDefinition oldBeanDefinition;
    //从缓存中取出一个BeanDefinition实例
    oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    if (oldBeanDefinition != null) {
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
    }
    //缓存BeanDefinition
    this.beanDefinitionMap.put(beanName, beanDefinition);
    } else {
        //如果BeanDefinition没有找到,但是已经有Bean创建//即容器已经启动
        if (hasBeanCreationStarted()) {
            synchronized (this.beanDefinitionMap) {
                  //缓存实例
                this.beanDefinitionMap.put(beanName, beanDefinition);
		List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
		updatedDefinitions.addAll(this.beanDefinitionNames);
		updatedDefinitions.add(beanName);
		this.beanDefinitionNames = updatedDefinitions;
	if (this.manualSingletonNames.contains(beanName)) {
	    Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
	    updatedSingletons.remove(beanName);
	    this.manualSingletonNames = updatedSingletons;
	    }
	}
    } else {
    //容器没有启动。缓存Bean
    this.beanDefinitionMap.put(beanName, beanDefinition);
    //添加BeanName
    this.beanDefinitionNames.add(beanName);
    this.manualSingletonNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }
    if (oldBeanDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

I think the above code is very long, but the main logic is to store the BeanDefinition in the Map field of the DefaultListableBeanFactory , which is declared as follows:

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

 After the above code, we know that the final form of Bean registration is BeanDefinition, which is stored in the Map instance of DefaultListableBeanFactory, which means that the final form of our XML-configured Bean or annotated Bean is BeanDefinition. Let’s look at the BeanDefinition hierarchy first. Figure, and then look at how tags are resolved into BeanDefinition.

The above is all the implementation of BeanDefinition, below we look at how the label parses the BeanDefinition, in the previous BeanDefinitionHolder bdHolder  = delegate .parseBeanDefinitionElement( ele ) , through the BeanDefinitionParserDelegate to parse the label, we view the source code of the final parsing part

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    //获取Bean标签的id或者name属性
    String id = ele.getAttribute(ID_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    List<String> aliases = new ArrayList<String>();
    //获取Bean的别名
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr =  StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }
    String beanName = id;
    //如果id属性为空,并且name属性不为空,从name属性的值中取出第一个当作Bean名称
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        beanName = aliases.remove(0);
    }
    //如果containingBean ==null,检测Name的唯一性
    if (containingBean == null) {
        checkNameUniqueness(beanName, aliases, ele);
    }
    //将标签解析为BeanDefinition实例
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    //如果beanDefinition 不为空封装为BeanDefinitionHolder实例
    if (beanDefinition != null) {
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }
    return null;
}

In the above method,  parseBeanDefinitionElement( ele , beanName , containingBean ) is finally called ; the code for parsing Bean tags is as follows:

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);
        //解析Bean标签的其他属性,比如scope,autowire等
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
        ......//解析Bean标签的其他内容meta  properties,constructor等
        return bd;
    }......//catch代码
    return null
}

In the above code, an instance of BeanDefinition is created by createBeanDefinition( className , parent ) , and finally the following method is called . An instance is created using the implementation class GenericBeanDefinition of BeanDefinition , and the name and Class name are set for it

public static AbstractBeanDefinition createBeanDefinition(String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
    GenericBeanDefinition bd = new GenericBeanDefinition();
    bd.setParentName(parentName);
    if (className != null) {
        if (classLoader != null) {
            bd.setBeanClass(ClassUtils.forName(className, classLoader));
        }else {
            bd.setBeanClassName(className);
        }
    }
    return bd;
}

At this point , the source code analysis of our Bean registration is complete. In summary: First, the Bean is finally parsed into a BeanDefinition instance and stored in the Map instance of DefaultListableBeanFactory . The analysis is completed by the entrusted BeanDefinitionParserDelegate . During the Bean parsing process, no instance was created for the Bean. Bean instance is created when it is acquired.

Guess you like

Origin blog.csdn.net/wk19920726/article/details/108829905