欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

BeanDefinition的载入分析-下篇

程序员文章站 2022-05-07 18:30:07
...

继续前面中篇所说的那样就是对xml文件中数据进行解析时的一个流程,以下就是解析BeanDefiniton对象并且存储进BeanDefinitonHolder中去的
BeanDefinition的载入分析-下篇

@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容器执行索引,查询,操作等

相关标签: 读书笔记