美文网首页java所有基础知识javaweb收藏
spring源码探索(2)-IOC容器-BeanDefiniti

spring源码探索(2)-IOC容器-BeanDefiniti

作者: 青芒v5 | 来源:发表于2018-07-20 23:16 被阅读201次

    一、BeanDefinition介绍

    BeanDefinition包含了spring应用中各对象属性以及对象间的相互依赖关系,Bean对象的创建与依赖注入都是依照BeanDefinition来进行初始化、注入等,就好比Bean创建的配方。


    通过上面的属性可以看到,基本和我们xml里的配置一一对应的,它就是我们xml里bean配置的载体。

    二、BeanDefinition的装载

    主链路

    主入口DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions

    protected void doRegisterBeanDefinitions(Element root) {
        //...............................................................
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(this.readerContext, root, parent);
    
        preProcessXml(root);
        //开始解析document
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);
    
        this.delegate = parent;
    }
    

    DefaultBeanDefinitionDocumentReader.parseBeanDefinitions

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //判断是否是spring 默认的 namespace
        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);
        }
    }
    

    判断是否是spring默认的配置文件,具体逻辑见代码截图


    BeanDefinitionParserDelegate.isDefaultNamespace

    2.1 spring默认的解析策略

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

    DefaultBeanDefinitionDocumentReader.processBeanDefinition

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //配置文件解析完毕后放到 BeanDefinitionHolder
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                //将BeanDefinition注册到容器中,也就是我们所说的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

    public AbstractBeanDefinition parseBeanDefinitionElement(
                Element ele, String beanName, BeanDefinition containingBean) {
    
        //parseState 是一个解析栈,在异常时候方便记录
        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,将name和class属性注入, class是使用XmlReaderContext的classloader,根据配置加载
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    
            //解析bean 属性配置 如 initMethod 这些
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    
            parseMetaElements(ele, bd);
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    
            //解析构造方法注入配置
            parseConstructorArgElements(ele, bd);
            //解析 bean property配置
            parsePropertyElements(ele, bd);
            //解析 bean qualifier配置
            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);
            //省略若干代码
        finally {
            //成功解析后,移除该 BeanEntry
            this.parseState.pop();
        }
    
        return null;
    }
    

    创建beandefinition实现代码BeanDefinitionReaderUtils.createBeanDefinition

    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) {
                //设置class对象
                bd.setBeanClass(ClassUtils.forName(className, classLoader));
            }
            else {
                //如果classloader为空则设置className
                bd.setBeanClassName(className);
            }
        }
        return bd;
    }
    

    解析 bean property配置parsePropertyElements具体执行单元parsePropertyElement,当然如果bean配置没有property,自然也不会走到parsePropertyElement逻辑

    public void parsePropertyElement(Element ele, BeanDefinition bd) {
            //..................
    
            //解析property value
            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) {
        //...................................
    
        //属性是否是 ref
        boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
        //属性是否是 value
        boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
        //...................................
    
        if (hasRefAttribute) {
            String refName = ele.getAttribute(REF_ATTRIBUTE);
            if (!StringUtils.hasText(refName)) {
                error(elementName + " contains empty 'ref' attribute", ele);
            }
            //RuntimeBeanReference ref的载体
            RuntimeBeanReference ref = new RuntimeBeanReference(refName);
            ref.setSource(extractSource(ele));
            return ref;
        }
        else if (hasValueAttribute) {
            //TypedStringValue 普通value的载体
            TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
            valueHolder.setSource(extractSource(ele));
            return valueHolder;
        }
        //是否还有有子节点 比如 list,map这些就有子节点
        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;
        }
    }
    
    public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
        //如果不是spring默认解析继续走自定义handler解析
        if (!isDefaultNamespace(ele)) {
            return parseNestedCustomElement(ele, bd);
        }
        //如果节点是 bean
        else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
            BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
            if (nestedBd != null) {
                nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
            }
            return nestedBd;
        }
        //如果节点是 ref
        else if (nodeNameEquals(ele, REF_ELEMENT)) {
            // ......................
            RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
            ref.setSource(extractSource(ele));
            return ref;
        }
        else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
            return parseIdRefElement(ele);
        }
        //如果节点是 value
        else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
            return parseValueElement(ele, defaultValueType);
        }
        //如果节点是 null
        else if (nodeNameEquals(ele, NULL_ELEMENT)) {
            // ......................
            TypedStringValue nullHolder = new TypedStringValue(null);
            nullHolder.setSource(extractSource(ele));
            return nullHolder;
        }
        //如果节点是 array
        else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
            return parseArrayElement(ele, bd);
        }
        else if (nodeNameEquals(ele, LIST_ELEMENT)) {
            return parseListElement(ele, bd);
        }
        else if (nodeNameEquals(ele, SET_ELEMENT)) {
            return parseSetElement(ele, bd);
        }
        else if (nodeNameEquals(ele, MAP_ELEMENT)) {
            return parseMapElement(ele, bd);
        }
        else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
            return parsePropsElement(ele);
        }
        else {
            error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
            return null;
        }
    }
    

    parsePropertySubElement,解析代码就不贴了,篇幅有限,我们可以看里面list节点的解析链路
    parsePropertySubElement() -> parseListElement() -> parseCollectionElements() -> parsePropertySubElement(),对没有看错,最后又回到了 parsePropertySubElement(),不过逻辑分支自然是不同的

    public List parseListElement(Element collectionEle, BeanDefinition bd) {
        String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
        NodeList nl = collectionEle.getChildNodes();
        //整体被包装成ManagedList类型
        ManagedList<Object> target = new ManagedList<Object>(nl.getLength());
        target.setSource(extractSource(collectionEle));
        target.setElementTypeName(defaultElementType);
        target.setMergeEnabled(parseMergeAttribute(collectionEle));
        //解析list 子节点值, 集合类的都用该方法进行解析
        parseCollectionElements(nl, target, bd, defaultElementType);
        return target;
    }
    

    其它类型的节点解析就不一一贴代码了,只要调用链路清晰后,顺着代码也基本就看明白了

    2.2 自定义的解析

    如果不是spring默认解析的则有自定的handler进行解析

    //BeanDefinitionParserDelegate
    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        String namespaceUri = getNamespaceURI(ele);
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }
    

    this.readerContext.getNamespaceHandlerResolver()也就是XmlReaderContext.namespaceHandlerResolver,这是什么东西呢?我们回到 XmlReaderContext创建的代码

    //XmlBeanDefinitionReader.registerBeanDefinitions
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        documentReader.setEnvironment(getEnvironment());
        int countBefore = getRegistry().getBeanDefinitionCount();
        //createReaderContext(resource) 创建XmlReaderContext
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    
    protected XmlReaderContext createReaderContext(Resource resource) {
        if (this.namespaceHandlerResolver == null) {
            //这里创建了默认的 NamespaceHandlerResolver
            this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
        }
        return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
                this.sourceExtractor, this, this.namespaceHandlerResolver);
    }
    

    如何根据xml的namespace获取对应的handler?

    //DefaultNamespaceHandlerResolver
    public NamespaceHandler resolve(String namespaceUri) {
        Map<String, Object> handlerMappings = getHandlerMappings();
        //根据namespace获取对应的handler
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        }
        //判断handler是否实现接口NamespaceHandler
        else if (handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler) handlerOrClassName;
        }
        else {
            //如果handler首次加载,那么此时value只是个className
            String className = (String) handlerOrClassName;
            try {
                Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
                //.........?????
                if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                    throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                            "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
                }
                NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
                namespaceHandler.init();
                handlerMappings.put(namespaceUri, namespaceHandler);
                return namespaceHandler;
            }
            //..............................
        }
    }
    

    DefaultNamespaceHandlerResolver.getHandlerMappings

    Properties mappings =
    PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);

    这行代码会将classLoader classpath下的所有META-INF/spring.handlers给加载并存放在 handlerMappings, nameSpaceUri作为key,handler class作为value

    以dubbo的spring.handlers为例

    http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
    

    自定义解析,通过nameSpace找到对应的handler,然后由对应的handler来解析对应的xml,这么一个解析的方式。

    三 BeanDefinition 注册到容器

    DefaultBeanDefinitionDocumentReader.parseBeanDefinitions
    解析

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //解析后的bean,BeanDefinitionHolder
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // 将解析后的bean,BeanDefinitionHolder注册到容器
                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.registerBeanDefinition -> DefaultListableBeanFactory.registerBeanDefinition

    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);
            }
        }
    
        BeanDefinition oldBeanDefinition;
    
        //注册到beanDefinitionMap ,启用synchronized保证整个操作是原子性的,达到数据一致性
        synchronized (this.beanDefinitionMap) {
    
            //检查是否已经有同名的注册进来了,如果有则判断是否允许覆盖,若不允许则抛异常
            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 (this.logger.isInfoEnabled()) {
                        this.logger.info("Overriding bean definition for bean '" + beanName +
                                "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }
            }
            else {
                this.beanDefinitionNames.add(beanName);
                this.frozenBeanDefinitionNames = null;
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
    
        //覆盖掉beanName对应的原BeanDefinition,当然不仅仅是简单的覆盖,还需要将已经实例化的bean对象销毁、父类同名的覆盖等
        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }
    

    整个过程,所谓的容器注册,就是以 beanName为key, BeanDefinition为value,存放到beanDefinitionMap

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

    PS. ConcurrentHashMap已经是线程安全了为什么还加synchronized?
    注意观察synchronized,锁的块,spring要保证读写一致。ConcurrentHashMap只能保证单个操作的线程安全。

    四 结语

    至此,beanDefinition信息已经注册到spring容器中,接下来就可以被容器使用,都在beanDefinitionMap进行检索,这些信息是容器建议依赖反转的基础。

    源码版本:3.2.18.RELEASE


    系列文章
    spring源码探索(0)-IOC容器-架构设计
    spring源码探索(1)-IOC容器-Resource
    spring源码探索(2)-IOC容器-BeanDefinition加载与注册
    spring源码探索(3)-IOC容器-Bean的一生
    spring源码探索(4)-AOP实现原理

    相关文章

      网友评论

      本文标题:spring源码探索(2)-IOC容器-BeanDefiniti

      本文链接:https://www.haomeiwen.com/subject/laclpftx.html