三.Spring源码剖析-IOC启动流程

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 这篇文章是接上一篇文章《IOC启动流程(二)》,上一章节我们见到了Spring IOC容器的容器创建和配置加载两个大的流程,接来下分析Bean的解析以及Bean的注册流程。这里我终于可以把IOC启动流程的大图放上来了,你可以根据该图来看我接下来的流程分析

前言

这篇文章是接上一篇文章《IOC启动流程(二)》,上一章节我们见到了Spring IOC容器的容器创建和配置加载两个大的流程,接来下分析Bean的解析以及Bean的注册流程。这里我终于可以把IOC启动流程的大图放上来了,你可以根据该图来看我接下来的流程分析
在这里插入图片描述

Bean的解析:XmlBeanDefinitionReader

Spring IOC启动创建完容器之后,最终委托XmlBeanDefinitionReader#loadBeanDefinitions加载Bean。

XmlBeanDefinitionReader通过 ResourcePatternResolver 加载配置XML转换为 Resource对象并封装成InputSource 文档解析源,然后XmlBeanDefinitionReader通过DocumentLoader.loadDocument 把InputSource(XML配置文件)解析成Document。最后调用registerBeanDefinitions方法解析和注册Bean :见XmlBeanDefinitionReader#loadBeanDefinitions源码如下:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
   
   

        try {
   
   
            //将 XML 文件转换为 Document 对象,通过 documentLoader来解析
            Document doc = doLoadDocument(inputSource, resource);
            //【重要】解析和注册Bean的消息流程
            int count = registerBeanDefinitions(doc, resource);
            if (logger.isDebugEnabled()) {
   
   
                logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        }
        ...省略...

下面是:DefaultDocumentLoader#loadDocument 加载文档源码:

//XML解析成Document,调用documentLoader.loadDocument完成
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
   
   
        return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                getValidationModeForResource(resource), isNamespaceAware());
}

public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
            ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
   
   
        //创建文档解析工厂
        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isTraceEnabled()) {
   
   
            logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        //创建文档解析器
        DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
        //执行解析了
        return builder.parse(inputSource);
    }

下面是registerBeanDefinitions方法,即:Bean的解析和注册流程:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   
   
        //Bean的文档解析器,由 DefaultBeanDefinitionDocumentReader 实现
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        //容器中Bean的数量
        int countBefore = getRegistry().getBeanDefinitionCount();
        //通过 DefaultBeanDefinitionDocumentReader .registerBeanDefinitions 注册Bean
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        //统计解析的Bean的个数
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

这里创建了DefaultBeanDefinitionDocumentReaderBean的文档解析器,调用其registerBeanDefinitions方法来注册Bean,见:DefaultBeanDefinitionDocumentReader#registerBeanDefinitions

DefaultBeanDefinitionDocumentReader#registerBeanDefinitions

DefaultBeanDefinitionDocumentReader委派BeanDefinitionParserDelegate进行Document的解析工作

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   
   
    this.readerContext = readerContext;
    //获取根元素,调用doRegisterBeanDefinitions方法
    doRegisterBeanDefinitions(doc.getDocumentElement());
}

protected void doRegisterBeanDefinitions(Element root) {
   
   
        //创建BeanDefinitionParserDelegate,它是Bean解析委派器,定义了XML的各种元素的解析
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
   
   
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
   
   
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
   
   
                    if (logger.isDebugEnabled()) {
   
   
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }
        //解析之前的动作,空方法,可以通过复写该方法做扩展
        preProcessXml(root);
        //解析Document,从root开始,委派给BeanDefinitionParserDelegate来解析
        parseBeanDefinitions(root, this.delegate);
        //解析之后的动作,空方法,可以通过复写该方法做扩展
        postProcessXml(root);

        this.delegate = parent;
    }

该方法中创建了BeanDefinitionParserDelegate,它定义了Spirng的xml中的所有的元素,然后委派它来对Document进行解析,继续跟 BeanDefinitionParserDelegate.parseBeanDefinitions 方法

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   
   
        //判断是否使用默认的Spring的xml默认的命名空间
        if (delegate.isDefaultNamespace(root)) {
   
   
            //获取根元素下的所有元素
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
   
   
                Node node = nl.item(i);
                //判断节点是XML的节点
                if (node instanceof Element) {
   
   

                    Element ele = (Element) node;
                    //判断命名空间
                    if (delegate.isDefaultNamespace(ele)) {
   
   
                        //按照Spring默认的命名空间解析元素
                        parseDefaultElement(ele, delegate);
                    }
                    else {
   
   
                        //使用自定义的规则解析
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
   
   
            //使用自定义的规则解析
            delegate.parseCustomElement(root);
        }
    }

这里判断了命名空间之后,调用 parseDefaultElement方法进行解析文档

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   
   
        //如果Element是 <import> 元素,就执行 importBeanDefinitionResource 导入其他配置文件
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
   
   
            importBeanDefinitionResource(ele);
        }
        //如果是 <alias> 就调用processAliasRegistration 注册 alias别名
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
   
   
            processAliasRegistration(ele);
        }
        //如果是 <bean> 元素就走 processBeanDefinition,解析Bean
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
   
   
            processBeanDefinition(ele, delegate);
        }
        //如果是 <beans> 就走 doRegisterBeanDefinitions 注册多个Bean
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
   
   
            // recurse
            doRegisterBeanDefinitions(ele);
        }
    }

这里判断了 import ,alias ,bean ,beans几种元素,分别走不同的方法进行解析。

Import 解析

下面是对 importBeanDefinitionResource 方法的分析 ,该方法的主要作用是解析<import 导入的配置文件,然后把其中的Bean的解析出来注册到Spring容器中,还是调用的是 XmlBeanDefinitionReader#loadBeanDefinitions方法来完成Bean的加载的。

/**
     * Parse an "import" element and load the bean definitions
     * from the given resource into the bean factory.
     */
    protected void importBeanDefinitionResource(Element ele) {
   
   
        //得到<import resource="配置路径"  resouce即:导入的配置路径
        String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
        if (!StringUtils.hasText(location)) {
   
   
            //没导入任何文件,直接返回
            getReaderContext().error("Resource location must not be empty", ele);
            return;
        }
        //解析系统属性,解析占位符
        // Resolve system properties: e.g. "${user.dir}"
        location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

        Set<Resource> actualResources = new LinkedHashSet<>(4);
        //给定导入的文件的位置是绝对URI还是相对URI
        // Discover whether the location is an absolute or relative URI
        boolean absoluteLocation = false;
        try {
   
   
            absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
        }
        catch (URISyntaxException ex) {
   
   
            // cannot convert to an URI, considering the location relative
            // unless it is the well-known Spring prefix "classpath*:"
        }

        //绝对路径
        // Absolute or relative?
        if (absoluteLocation) {
   
   
            try {
   
   
                //使用XmlBeanDefinitionReader加载导入的配置文件
                int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
                if (logger.isTraceEnabled()) {
   
   
                    logger.trace("Imported " + importCount + " bean definitions from URL location [" + location + "]");
                }
            }
            catch (BeanDefinitionStoreException ex) {
   
   
                getReaderContext().error(
                        "Failed to import bean definitions from URL location [" + location + "]", ele, ex);
            }
        }
        else {
   
   
            //相对路径
            // No URL -> considering resource location as relative to the current file.
            try {
   
   
                int importCount;
                //把配置文件加载成相对路径的Resource对象 ,就是要找到导入读文件,然后返回它的Resource对象
                Resource relativeResource = getReaderContext().getResource().createRelative(location);
                if (relativeResource.exists()) {
   
   
                    //如果文件存在,使用XmlBeanDefinitionReader加载导入的配置文件
                    importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                    actualResources.add(relativeResource);
                }
                else {
   
   
                    //如果不存在,使用资源加载器的相对路径来拼接文件地址,然后使用XmlBeanDefinitionReader加载导入的配置文件
                    String baseLocation = getReaderContext().getResource().getURL().toString();
                    importCount = getReaderContext().getReader().loadBeanDefinitions(
                            StringUtils.applyRelativePath(baseLocation, location), actualResources);
                }
                if (logger.isTraceEnabled()) {
   
   
                    logger.trace("Imported " + importCount + " bean definitions from relative location [" + location + "]");
                }
            }
            catch (IOException ex) {
   
   
                getReaderContext().error("Failed to resolve current resource location", ele, ex);
            }
            catch (BeanDefinitionStoreException ex) {
   
   
                getReaderContext().error(
                        "Failed to import bean definitions from relative location [" + location + "]", ele, ex);
            }
        }
        Resource[] actResArray = actualResources.toArray(new Resource[0]);
        //发布一个import成功的事件
        getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
    }

alias 别名注册

下面是对 processAliasRegistration 方法的解析,方法的作用是 解析<alias 给定的别名元素,向注册表注册别名。

/**
     * Process the given alias element, registering the alias with the registry.
     */
    protected void processAliasRegistration(Element ele) {
   
   
        //获取 元素的name属性
        String name = ele.getAttribute(NAME_ATTRIBUTE);
        //获取元素的alias属性
        String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
        //做了一下判断,name和alias是否为空
        boolean valid = true;
        if (!StringUtils.hasText(name)) {
   
   
            getReaderContext().error("Name must not be empty", ele);
            valid = false;
        }
        if (!StringUtils.hasText(alias)) {
   
   
            getReaderContext().error("Alias must not be empty", ele);
            valid = false;
        }
        if (valid) {
   
   
            //如果定义了name或者alis
            try {
   
   
                //注册alias ,调用 AliasRegistry 的 registerAlias 来注册
                //默认实现 .SimpleAliasRegistry#registerAlias
                 getReaderContext().getRegistry().registerAlias(name, alias);
            }
            catch (Exception ex) {
   
   
                getReaderContext().error("Failed to register alias '" + alias +
                        "' for bean with name '" + name + "'", ele, ex);
            }
            //alias注册完之后,发布一个事件
            getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
        }
    }

上面方法 获取到元素的name和alias属性后,调用 SimpleAliasRegistry#registerAlias 来注册Bean的名字,其实就是使用一个ConcurrentHashMap来存储。

public class SimpleAliasRegistry implements AliasRegistry {
   
   

    /** Logger available to subclasses. */
    protected final Log logger = LogFactory.getLog(getClass());

    /** Map from alias to canonical name. */
    private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
    ...省略...

    @Override
    public void registerAlias(String name, String alias) {
   
   
        Assert.hasText(name, "'name' must not be empty");
        Assert.hasText(alias, "'alias' must not be empty");
        //加锁
        synchronized (this.aliasMap) {
   
   
            if (alias.equals(name)) {
   
   
                //如果name和alias相同,从map中移除
                this.aliasMap.remove(alias);
                if (logger.isDebugEnabled()) {
   
   
                    logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
                }
            }
            else {
   
   
                //通过alias获取map中的值
                String registeredName = this.aliasMap.get(alias);
                if (registeredName != null) {
   
   
                    if (registeredName.equals(name)) {
   
   
                        // An existing alias - no need to re-register
                        return;
                    }
                    if (!allowAliasOverriding()) {
   
   
                        throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
                                name + "': It is already registered for name '" + registeredName + "'.");
                    }
                    if (logger.isDebugEnabled()) {
   
   
                        logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
                                registeredName + "' with new target name '" + name + "'");
                    }
                }
                //判断名字循环引用问题
                checkForAliasCircle(name, alias);
                //以alias为key name为值保持到ma
                this.aliasMap.put(alias, name);
                if (logger.isTraceEnabled()) {
   
   
                    logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
                }
            }
        }
    }

bean 的解析

下面是对 processBeanDefinition方法的解析,将解析的工作委托给BeanDefinitionParserDelegate,然后通过BeanDefinitionReaderUtils调用BeanDefinitionRegistry进行Bean的注册

    /**
     * Process the given bean element, parsing the bean definition
     * and registering it with the registry.
     */
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   
   
        //委托为BeanDefinitionParserDelegate 解析 Bean , BeanDefinitionHolder是对 BeanDefinition 的封装
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
   
   
            //如果需要,装饰 Bean 定义
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
   
   
                // Register the final decorated instance.
                //注册Bean
                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));
        }
    }

跟一下 BeanDefinitionParserDelegate#parseBeanDefinitionElement(BeanDefinition) 方法

//解析提供的<bean>元素
    @Nullable
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
   
   
        //获取id属性
        String id = ele.getAttribute(ID_ATTRIBUTE);
        //获取name属性
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        List<String> aliases = new ArrayList<>();
        if (StringUtils.hasLength(nameAttr)) {
   
   
            //处理名字,添加到aliases集合中
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        //如果ID为空,把第一个name赋值被 beanName
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
   
   
            beanName = aliases.remove(0);
            if (logger.isTraceEnabled()) {
   
   
                //未指定ID,使用beanName 作为 name
                logger.trace("No XML 'id' specified - using '" + beanName +
                        "' as bean name and " + aliases + " as aliases");
            }
        }

        if (containingBean == null) {
   
   
            //检查id,name,aliases的唯一性
            checkNameUniqueness(beanName, aliases, ele);
        }
        //解析Bean元素 , 得到beanDefinition
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
   
   
            if (!StringUtils.hasText(beanName)) {
   
   
                try {
   
   
                    if (containingBean != null) {
   
   
                        //为给定的Bean生成一个唯一的名字
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {
   
   
                        //为解析的 Bean 使用别名向 IOC 容器注册
                        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.
                        //为解析的 Bean 使用别名注册时,为了向后兼容
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
   
   
                            aliases.add(beanClassName);
                        }
                    }
                    if (logger.isTraceEnabled()) {
   
   
                        logger.trace("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);
            //把beanDefinition封装成BeanDefinitionHolder
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }

这里调用了

AbstractBeanDefinition parseBeanDefinitionElement方法 讲 Element 元素(Bean) 解析成 BeanDefinition ,然后封装成 BeanDefinitionHolder返回,下面是parseBeanDefinitionElement方法的源码:

@Nullable
    public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, @Nullable BeanDefinition containingBean) {
   
   

        this.parseState.push(new BeanEntry(beanName));

        String className = null;
        //获取到Bean的class属性
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
   
   
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }
        String parent = null;
        //获取parent属性,如果有的话
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
   
   
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        try {
   
   
            //为给定的类名和父名创建一个 bean 定义,new 了一个GenericBeanDefinition
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            //解析Bean的属性配置,全都设置到BeanDefinition对象中
            //比如:scope,abstract,lazy-init,autowire,depends-on,primary,
            //init-method,destroy-method,factory-method,factory-bean
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            //设置Bean的Description属性
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            //对Bean的 的 元信息(meta) 属性做解析
            parseMetaElements(ele, bd);
            //对lookup-Method属性做解析
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //对replaced-Method属性做解析
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //对构造方法 constructor-arg 做解析,把构造器参数会保存到BeanDefinition.
            parseConstructorArgElements(ele, bd);
            //对 property属性做解析,把property封装成 MutablePropertyValues保存到BeanDefinition
            parsePropertyElements(ele, bd);
            //对Qualifier属性做解析
            parseQualifierElements(ele, bd);
            //为bean设置资源,就是配置文件的Resource对象
            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;
    }

上面对一个<bean />的所有的属性,及子元素都做了解析,相关属性和依赖关系都封装到了BeanDefinition对象中具体的细节就不进去展开了,你可以自己断点进去看。我们可以看下BeanDefinition这个类

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {
   
   
       ...省略部分代码...
       //bean的class
    @Nullable
    private volatile Object beanClass;
    //bean的scope
    @Nullable
    private String scope;
    private boolean abstractFlag;
    //是否是lazyInit懒加载
    private boolean lazyInit;
    private int autowireMode;
    private int dependencyCheck;
    @Nullable
    private String[] dependsOn;
    private boolean autowireCandidate;
    private boolean primary;
    private final Map<String, AutowireCandidateQualifier> qualifiers;

    //工厂名
    @Nullable
    private String factoryBeanName;
    //工厂方法
    @Nullable
    private String factoryMethodName;
    //构造器参数
    @Nullable
    private ConstructorArgumentValues constructorArgumentValues;
    //property注入
    @Nullable
    private MutablePropertyValues propertyValues;
    @Nullable
    private MethodOverrides methodOverrides;
    //初始方法
    @Nullable
    private String initMethodName;
    //销毁方法
    @Nullable
    private String destroyMethodName;
    private boolean enforceInitMethod;
    private boolean enforceDestroyMethod;
    private boolean synthetic;
    private int role;
    //描述
    @Nullable
    private String description;
    //配置文件资源
    @Nullable
    private Resource resource;

Bean的注册

到这里Bean的解析就告一段落,代码回到 DefaultBeanDefinitionDocumentReader#processBeanDefinition


    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   
   
        //委托为BeanDefinitionParserDelegate 解析 Bean , BeanDefinitionHolder是对 BeanDefinition 的封装
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
   
   
            //如果需要,装饰 Bean 定义,只有命名空间不是默认的时候才会走这
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
   
   
                // Register the final decorated instance.
                //注册Bean
                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));
        }
    }

BeanDefinitionReaderUtils

我们已经走完了 BeanDefinitionParserDelegate .parseBeanDefinitionElement 解析Bean的方法,接下来该走 BeanDefinitionReaderUtils#registerBeanDefinition 注册Bean的方法了

    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {
   
   

        // Register bean definition under primary name.
        //获取Bean的名字
        String beanName = definitionHolder.getBeanName();
        //调用BeanDefinitionRegistry 注册器注册BeanDefinition
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // Register aliases for bean name, if any.
        //注册别名,如果BeanDefinition有
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
   
   
            for (String alias : aliases) {
   
   
                registry.registerAlias(beanName, alias);
            }
        }
    }

这里调用了 BeanDefinitionRegistry 注册器 的registerBeanDefinition方法注册bean,然后还会调用registerAlias注册别名,先看一下registerBeanDefinition方法,这里走的是GenericApplicationContext#registerBeanDefinition

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
   
   
        //调用工厂的注册Bean方法
        this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
    }

调用 this.beanFactory.registerBeanDefinition 方法,代码来到DefaultListableBeanFactory#registerBeanDefinition

DefaultListableBeanFactory#registerBeanDefinition

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
   
   
    //用来存储BeanDefinition
    /** Map of bean definition objects, keyed by bean name. */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

@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");
        //验证 beanDefinition
        if (beanDefinition instanceof AbstractBeanDefinition) {
   
   
            try {
   
   
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
   
   
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }
        //根据Bean的名字从 beanDefinitionMap 缓存中获取 BeanDefinition ,
        // 也就是说BeanDefinitionMap是存放在一个ConcurrentHashMap中
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
   
   
            //如果已经存在这个Bean , 是允许 Bean 定义覆盖
            if (!isAllowBeanDefinitionOverriding()) {
   
   
                //如果不允许覆盖,抛出异常
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            ...省略...
            //把beanDefinition 存放到 一个 ConcurrentHashMap中 ,覆盖掉以前的Bean
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
   
   
            //如果Map中没有这个Bean,检查这个工厂的 bean 创建阶段是否已经开始
            if (hasBeanCreationStarted()) {
   
   
                //默认不会走这
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
   
   
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                }
            }
            else {
   
   
                //默认走这里,,把beanDefinition 存放到 一个 ConcurrentHashMap中
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                //把bean的name保存到  List<String> beanDefinitionNames = new ArrayList<> 集合中
                this.beanDefinitionNames.add(beanName);
                removeManualSingletonName(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }
        //如果 Map中已经存在这个Bean, 或者单利缓存 : singletonObjects = new ConcurrentHashMap 中包含这个Bean
        if (existingDefinition != null || containsSingleton(beanName)) {
   
   
            //重置给定 bean 的所有 bean 定义缓存
            resetBeanDefinition(beanName);
        }
        else if (isConfigurationFrozen()) {
   
   
            clearByTypeCache();
        }
    }

这里我们看到,BeanDefinition是存储到一个ConcurrentHashMap中的,代码首先中Map中获取该Bean,如果存在该Bean,且设置了允许Bean的覆盖,就会把BeanDefinition存储到Map中覆盖之前的Map中的BeanDefinition。

如果Map中没有这个Bean就会以name为key把BeanDefinition存储到ConcurrentHashMap中,bean的name也会保存到一个beanDefinitionNames = new ArrayList(256)中。

总结

到这里文章就结束了,本章内容是基于XML的IOC启动流程源码分析,下面做个总结

  1. 我们最开始分析了IOC容器常见工厂,及相关的核心类
  2. IOC入口从ClasspathXmlApplicationContext开始,通过父类创建ResourcePatternResolver用来加载Bean的资源文件
  3. 保存资源文件的location
  4. 调用父类AbstractApplicationContext的refresh方法刷新容器,方法通过子类AbstractRefreshableApplicationContext创建容器工厂(创建的是DefaultListableBeanFactory),以及加载Bean。
  5. 加载Bean的工作最终委托给XmlBeandifinetionReader,它通过ResourcePatternResolver加载资源文件Resource,调用DefualtDocumentLoader将Resource转为Document对象,然后委派BeanDefinitionParserDelegate去解析Bean
  6. BeanDefinitionParserDelegate解析完Bean之后,把Bean的属性,构造器参数,依赖关系等全都封装成BeanDefinition对象。
  7. 然后BeanDefinitionParserDelegate调用BeanDefinitionReaderUtils注册Bean
  8. BeanDefinitionReaderUtils最终调用BeanDefinitionRegister来注册BeanDefinition,然后把BeanDefinition注册到DefaultListableBeanFactory的一个ConcurrentHashMap中。
相关文章
|
4天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
20天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
10天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
36 9
|
19天前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
10天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
23 0
|
1月前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
65 0
|
Java 数据库连接 应用服务中间件
Spring源码剖析8:Spring事务概述
原文出处: 张开涛 9.1  数据库事务概述 事务首先是一系列操作组成的工作单元,该工作单元内的操作是不可分割的,即要么所有操作都做,要么所有操作都不做,这就是事务。
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
163 2
|
9天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
20 2
 SpringBoot入门(7)- 配置热部署devtools工具