BeanDefinition的载入分析-下篇

标签: 读书笔记

继续前面中篇所说的那样就是对xml文件中数据进行解析时的一个流程,以下就是解析BeanDefiniton对象并且存储进BeanDefinitonHolder中去的
在这里插入图片描述

@Nullable
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        //这里取得bean标签中的id
        String id = ele.getAttribute("id");
        // 取得bean标签中的name
        String nameAttr = ele.getAttribute("name");
        //自定义一个list数组用来接收解析的数据
        List<String> aliases = new ArrayList();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
            beanName = (String)aliases.remove(0);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
            }
        }

        if (containingBean == null) {
            this.checkNameUniqueness(beanName, aliases, ele);
        }
        
        //在这里主要是对bean标签进行详细的解析
        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                    } else {
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }

                    if (this.logger.isTraceEnabled()) {
                        this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }

            String[] aliasesArray = StringUtils.toStringArray(aliases);
            
            //可以看见这个结果BeanDefinitionHolder对象是一个封装的对象
            //其中的beanDefinition就是前面已经详细解析过的一个结果,以及获取解析过的一大串数据
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }

其中的AbstractBeanDefiniton对象是对xml中的封装以及抽象,可以看见这个类中都有哪些方法以及属性

public static final String SCOPE_DEFAULT = "";
    public static final int AUTOWIRE_NO = 0;
    public static final int AUTOWIRE_BY_NAME = 1;
    public static final int AUTOWIRE_BY_TYPE = 2;
    public static final int AUTOWIRE_CONSTRUCTOR = 3;
    /** @deprecated */
    @Deprecated
    public static final int AUTOWIRE_AUTODETECT = 4;
    public static final int DEPENDENCY_CHECK_NONE = 0;
    public static final int DEPENDENCY_CHECK_OBJECTS = 1;
    public static final int DEPENDENCY_CHECK_SIMPLE = 2;
    public static final int DEPENDENCY_CHECK_ALL = 3;
    public static final String INFER_METHOD = "(inferred)";
    @Nullable
    private volatile Object beanClass;
    @Nullable
    private String scope;
    private boolean abstractFlag;
    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 Supplier<?> instanceSupplier;
    private boolean nonPublicAccessAllowed;
    private boolean lenientConstructorResolution;
    @Nullable
    private String factoryBeanName;
    @Nullable
    private String factoryMethodName;
    @Nullable
    private ConstructorArgumentValues constructorArgumentValues;
    @Nullable
    private MutablePropertyValues propertyValues;
    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;

scope, description , initMethodName, destroyMethodName , beanClass , propertyValues 等这些属性可以在xml中的bean中可以看见
下面主要解析parseBeanDefinitionElement这个方法的源码

@Nullable
    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        String className = null;
        if (ele.hasAttribute("class")) {
            className = ele.getAttribute("class").trim();
        }

        String parent = null;
        if (ele.hasAttribute("parent")) {
            parent = ele.getAttribute("parent");
        }

        try {
            //根据className,parent这两个来确定beanDefinition
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            
            //从下面这些方法的名字我们能够看见解析方法主要的作用是什么
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            this.parseMetaElements(ele, bd);
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //是对构造解析
            this.parseConstructorArgElements(ele, bd);
            //是对property进行解析
            this.parsePropertyElements(ele, bd);
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
            
            //下面的这些异常都是在解析经常碰见的,比如有class没有找到,class未被定义异常 
        } catch (ClassNotFoundException var13) {
            this.error("Bean class [" + className + "] not found", ele, var13);
        } catch (NoClassDefFoundError var14) {
            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
        } catch (Throwable var15) {
            this.error("Unexpected failure during bean definition parsing", ele, var15);
        } finally {
            this.parseState.pop();
        }

这个方法主要的作用就是生成一个具体的BeanDefiniton对象

前面是this.parsePropertyElements(ele, bd)这个方法进行详细的解析过程源码

下面分析具体的property源码解析过程,在解析完这些属性值之后会被封装到PropertyValue对象中去,并且会被设置到BeanDedfinition对象中去

//首先是调用了parsepropertyElements这个方法
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    //获取elements下面的所有节点
        NodeList nl = beanEle.getChildNodes();

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            //判断是否是elements节点,如果是就继续进行解析
            if (this.isCandidateElement(node) && this.nodeNameEquals(node, "property")) {
                this.parsePropertyElement((Element)node, bd);
            }
        }

    }

//下面是使用parsePropertyElement方法来对节点进行解析
//这个方法就是解析后的数据结果全部存储进BeanDefinition对象中去
    public void parsePropertyElement(Element ele, BeanDefinition bd) {
        //获取到节点名称
        String propertyName = ele.getAttribute("name");
        if (!StringUtils.hasLength(propertyName)) {
            this.error("Tag 'property' must have a 'name' attribute", ele);
        } else {
            this.parseState.push(new PropertyEntry(propertyName));

            try {
                if (!bd.getPropertyValues().contains(propertyName)) {
                    //解析property值得地方
                    Object val = this.parsePropertyValue(ele, bd, propertyName);
                    //新建一个propertyValue对象进行数据的封装
                    PropertyValue pv = new PropertyValue(propertyName, val);
                    this.parseMetaElements(ele, pv);
                    pv.setSource(this.extractSource(ele));
                    //封装进BeanDefintiion对象中去
                    bd.getPropertyValues().addPropertyValue(pv);
                    return;
                }

                this.error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            } finally {
                this.parseState.pop();
            }

        }
    }


//下面主要是来看下真正解析property值的方法中具体的源码
//这个方法主要就是判断property是否为ref或者是value类型的源码解析
@Nullable
    public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
        String elementName = propertyName != null ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element";
        //获取到所有的子节点
        NodeList nl = ele.getChildNodes();
        Element subElement = null;

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            //判断是否是属性Element
            if (node instanceof Element && !this.nodeNameEquals(node, "description") && !this.nodeNameEquals(node, "meta")) {
                
                if (subElement != null) {
                    this.error(elementName + " must not contain more than one sub-element", ele);
                } else {
                    subElement = (Element)node;
                }
            }
        }

        //这里主要就是判断是否为ref或者是value类型的属性
        boolean hasRefAttribute = ele.hasAttribute("ref");
        boolean hasValueAttribute = ele.hasAttribute("value");
        if (hasRefAttribute && hasValueAttribute || (hasRefAttribute || hasValueAttribute) && subElement != null) {
            this.error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
        }

        if (hasRefAttribute) {
            String refName = ele.getAttribute("ref");
            if (!StringUtils.hasText(refName)) {
                this.error(elementName + " contains empty 'ref' attribute", ele);
            }
            
            //在这个地方主要就是定义一个RuntimeBeanReference对象
            RuntimeBeanReference ref = new RuntimeBeanReference(refName);
            ref.setSource(this.extractSource(ele));
            return ref;
        } else if (hasValueAttribute) {
            TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value"));
            
            //不是的话就会创建一个valueHolder对象去接收数据
            valueHolder.setSource(this.extractSource(ele));
            return valueHolder;
        } else if (subElement != null) {
            return this.parsePropertySubElement(subElement, bd);
        } else {
            this.error(elementName + " must specify a ref or value", ele);
            return null;
        }
    }

下面主要是对parseListElement解析list集合中的元素进行的方法,结果

//manageList是spring中对BeanDefinition中的list集合的封装对象
public List<Object> parseListElement(Element collectionEle, @Nullable BeanDefinition bd) {
        String defaultElementType = collectionEle.getAttribute("value-type");
        //获取到所有的子节点元素
        NodeList nl = collectionEle.getChildNodes();
        ManagedList<Object> target = new ManagedList(nl.getLength());
        target.setSource(this.extractSource(collectionEle));
        target.setElementTypeName(defaultElementType);
        //添加进到manageList集合中去
        target.setMergeEnabled(this.parseMergeAttribute(collectionEle));
        this.parseCollectionElements(nl, target, bd, defaultElementType);
        return target;
    }

//下面是对集合元素的解析过程的源码分析
protected void parseCollectionElements(NodeList elementNodes, Collection<Object> target, @Nullable BeanDefinition bd, String defaultElementType) {
        for(int i = 0; i < elementNodes.getLength(); ++i) {
            Node node = elementNodes.item(i);
            //判断是否是elements元素,如果是就调用递归添加的方法添加进去
            if (node instanceof Element && !this.nodeNameEquals(node, "description")) {
                target.add(this.parsePropertySubElement((Element)node, bd, defaultElementType));
            }
        }

    }

经过前面的源码分析,我们能够将自定义的bean转换成spring中内部数据结构,或者说可以看成是POJO对象在IOC容器中的抽象,这些数据结构可以以AbstractBeanDefinition为入口,让ioc容器执行索引,查询,操作等

版权声明:本文为a_liuren原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/a_liuren/article/details/103791121