BeanDefinition the Spring Ioc of the load

In this paper, the Spring configuration file parsing to process registration.

We write to debug demo

 XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("iocbeans.xml"));
复制代码

The first step in obtaining the XML resource.

The second step is to load resources.

 public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, (BeanFactory)null);
    }

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader = new XmlBeanDefinitionReader(this);
        //这里才是资源加载的真正实现
        this.reader.loadBeanDefinitions(resource);
    }
      public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return this.loadBeanDefinitions(new EncodedResource(resource));
    }

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
       //...省略部分代码
    //通过属性记录当前已经加载的资源
        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if(currentResources == null) {
            currentResources = new HashSet(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }

        if(!((Set)currentResources).add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var5;
            try {
                //获取inputStream
                InputStream inputStream = encodedResource.getResource().getInputStream();

                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if(encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
				//核心逻辑部分
         var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {//关闭流
                    inputStream.close();
                }
            } catch (IOException var15) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
            } finally {
                ((Set)currentResources).remove(encodedResource);
                if(((Set)currentResources).isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }

            }

            return var5;
        }
    }
复制代码

The above summarizes the logic code:

First, as incoming resource package parameters, there may be the case because of coding. Then prepare inputSource objects, easy to read the back. The last incoming doLoadBeanDefinitions method.

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
            //1.加载xml文件,转化为doc格式
            Document doc = this.doLoadDocument(inputSource, resource);
            //2.根据返回的doc,注册bean信息
            return this.registerBeanDefinitions(doc, resource);
        } catch (BeanDefinitionStoreException var4) {
            throw var4;
        }
复制代码

In 1 above, it involves the validation of XML, here ignored.

Analysis and registration BeanDefinitions

Through the above 1, we've got the Document entered registerBeanDefinitions (doc, resource).;

public int registerBeanDefinitions(Document doc, Resource resource)  {
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
    //记录统计前的bean个数
        int countBefore = this.getRegistry().getBeanDefinitionCount();
    //加载及注册bean
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
    //记录本次加载bean的个数
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }
复制代码

Doc is the parameter by which the load converting section loadDocument out. In this method, a very good application of the principles of object-oriented single duties, will be entrusted to a single logic processing classes are processed, and this class is the logical processing BeanDefinitionDocumentReader. BeanDefinitionDocumentReader is an interface, and examples of the work is done () in the createBeanDefinitionDocumentReader, and by this method BeanDefinitionDocumentReader real type is DefaultBeanDefinitionDocumentReader, and after entering, found that one of the important purpose of this method is to extract the root, in order to once again root as the argument continued registration of BeanDefiniton.

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

protected void doRegisterBeanDefinitions(Element root) {
//专门处理解析
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
    if(this.delegate.isDefaultNamespace(root)) {
        String profileSpec = root.getAttribute("profile");
        if(StringUtils.hasText(profileSpec)) {
       String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
            if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                return;
            }
        }
    }
		//protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
        if(this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute("profile");
            if(StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
                if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    return;
                }
            }
        }
	//	解析前处理,留给子类实现
        this.preProcessXml(root);
        
        this.parseBeanDefinitions(root, this.delegate);
        //解析后处理,子类实现
        this.postProcessXml(root);
        this.delegate = parent;
    }
}
复制代码

Enter this.preProcessXml (root) and this.postProcessXml (root) method will find that they are empty method. Since it is a method that empty what use is it? We can quickly reflect this is the template design pattern. Either a class designed for inheritance, or to use modified final. Both of these methods is to subclass design.

Here we began reading the XML.

   void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
       //对beans读取
        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)) {
                        //对bean的处理
                        this.parseDefaultElement(ele, delegate);
                    } else {
                        //对bean的处理
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);
        }

    }
复制代码

Parsing the default label

The default tag is resolved in parseDefaultElement processing function, the function of the functions at a glance. Each of four different labels for different treatment.

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if(delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
        } else if(delegate.nodeNameEquals(ele, "alias")) {
            this.processAliasRegistration(ele);
        } else if(delegate.nodeNameEquals(ele, "bean")) {
            this.processBeanDefinition(ele, delegate);
        } else if(delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);
        }

    }
复制代码

Analysis and registration bean tag

Of the four tag resolution above, parsing bean tag of the most important and the most complex, we get to know her approach, the other tag resolution will be solved. We look into the Code

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //1.委托该方法进行元素解析。经过该方法,bdHolder中拥有配置文件的各种属性了。(class,name,id,alias)
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {//对解析后的bdHolder进行注册
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }
//发出响应事件,通知相关的监听器,这个bean已经加载完成了
   this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }
复制代码

Parsing BeanDefinition

First, we start element analysis and information extraction from, BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement (ele), enter parseBeanDefinitionElement method BeanDefinitionParserDelegate class.

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
        return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
    }

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        String id = ele.getAttribute("id");//对id解析
        String nameAttr = ele.getAttribute("name");//对name解析
        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(containingBean == null) {
            this.checkNameUniqueness(beanName, aliases, ele);
        }
	//	对标签其他属性的解析
        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);
                        }
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }

            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }

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

        try {//解析parent属性
            String parent = null;
            if(ele.hasAttribute("parent")) {
                parent = ele.getAttribute("parent");
            }
			//创建用于承载属性的GenericBeanDefinition
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            //硬编码解析默认bean的各种属性
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            //提取description
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
           //解析元数据
            this.parseMetaElements(ele, bd);
            //解析lookup-method
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //解析replaced-method
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //解析构造函数
            this.parseConstructorArgElements(ele, bd);
            //解析proterty子元素
            this.parsePropertyElements(ele, bd);
            //解析qualifier子元素
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
        } catch (ClassNotFoundException var13) {
        } finally {
            this.parseState.pop();
        }
        return null;
    }
复制代码

Finally, all the attributes bean tags, we have seen how the resolution.

  1. BeanDefinition BeanDefiniton for creating bearer is a property of the interface, there are three implemented in Spring: RootBeanDefiniton, ChildBeanDefinitio and GenericBeanDefinition. Three implementations are inherited AbstractBeanDefinition, which BeanDefiniton profile element is represented in the container label. They correspondence. RootBeanDefinition which is the most common implementation class, which corresponds to a general element tags, GenericBeanDefinition bean file is newly added configuration attributes defined class, one-stop service class. Parent and child can be defined in the configuration file, represented by the parent RootBeanDefiniton, and the child is represented by the ChildBeanDefinition, but no parent would use RootBeanDefiniton FIG. Spring by BeanDefinition profile information into an internal representation of the container, and to register these BeanDefinition in BeanDefinitionRegistry. BeanDefinitionRegistry is spring-memory database, mainly in the form of a map to save the follow-up configuration information directly BeanDefinitionRegistry. It can be seen, to be parsed to create first instance sub-attributes for carrying property, i.e. GenericBeanDefinition create an instance of the type. The role of createBeanDefinition (className, parent) is to implement this feature. public static AbstractBeanDefinition createBeanDefinition (String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {GenericBeanDefinition bd = new GenericBeanDefinition (); bd.

            return bd;
        }
    复制代码

    Various attributes resolve various property when we created the instance of the bean carrying information, the information can be bean resolved. parseBeanDefinitionAttributes element of all elements is parsed attributes: public AbstractBeanDefinition parseBeanDefinitionAttributes (Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) {// parse the scope attribute if (ele.hasAttribute ( "singleton")) {this.error ( "Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration ", ele);} else if (ele.hasAttribute (" scope ")) {bd.setScope (ele.getAttribute (" scope "));} else if (containingBean = null!) {bd.setScope (containingBean.getScope ());} // parse abstract attribute if (ele.hasAttribute ( "abstract")) {bd.setAbstract ( "true" .equals (ele. getAttribute ( "abstract")));} // parse lazy-init attribute String lazyInit = ele.getAttribute ( "lazy-init"); if ( "default".

            bd.setLazyInit("true".equals(lazyInit));
        //解析autowire属性
            String autowire = ele.getAttribute("autowire");
            bd.setAutowireMode(this.getAutowireMode(autowire));
        //解析dependency-check属性
            String dependencyCheck = ele.getAttribute("dependency-check");
            bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck));
            String autowireCandidate;
       //解析depends-on属性
            if(ele.hasAttribute("depends-on")) {
                autowireCandidate = ele.getAttribute("depends-on");
                bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
            }
    //解析autowire-candidate属性
            autowireCandidate = ele.getAttribute("autowire-candidate");
            String destroyMethodName;
            if(!"".equals(autowireCandidate) && !"default".equals(autowireCandidate)) {
                bd.setAutowireCandidate("true".equals(autowireCandidate));
            } else {
                destroyMethodName = this.defaults.getAutowireCandidates();
                if(destroyMethodName != null) {
                    String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
                    bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
                }
            }
    //解析primary属性
            if(ele.hasAttribute("primary")) {
                bd.setPrimary("true".equals(ele.getAttribute("primary")));
            }
    //解析init-method属性
            if(ele.hasAttribute("init-method")) {
                destroyMethodName = ele.getAttribute("init-method");
                if(!"".equals(destroyMethodName)) {
                    bd.setInitMethodName(destroyMethodName);
                }
            } else if(this.defaults.getInitMethod() != null) {
                bd.setInitMethodName(this.defaults.getInitMethod());
                bd.setEnforceInitMethod(false);
            }
    		//解析destroy-method属性
            if(ele.hasAttribute("destroy-method")) {
                destroyMethodName = ele.getAttribute("destroy-method");
                bd.setDestroyMethodName(destroyMethodName);
            } else if(this.defaults.getDestroyMethod() != null) {
                bd.setDestroyMethodName(this.defaults.getDestroyMethod());
                bd.setEnforceDestroyMethod(false);
            }
    		//解析factory-method属性
            if(ele.hasAttribute("factory-method")) {
                bd.setFactoryMethodName(ele.getAttribute("factory-method"));
            }
    			//解析factory-bean属性
            if(ele.hasAttribute("factory-bean")) {
                bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
            }
    
            return bd;
        }
    复制代码

After the above processing, Spring completed the parsing of all the bean properties. In other words, XML configuration can be found in all the corresponding configuration in GenericBeanDefinition instances of the class. GenericBeanDefinition just subclass implementation, and most of the common attributes are stored in AbstractBeanDefinition in. We look at this class

//...省略静态变量以及final常量
private volatile Object beanClass;
    private String scope;
    private boolean abstractFlag;
    private boolean lazyInit;
    private int autowireMode;
    private int dependencyCheck;
    private String[] dependsOn;
    private boolean autowireCandidate;
    private boolean primary;
    private final Map<String, AutowireCandidateQualifier> qualifiers;
    private boolean nonPublicAccessAllowed;
    private boolean lenientConstructorResolution;
    private ConstructorArgumentValues constructorArgumentValues;
    private MutablePropertyValues propertyValues;
    private MethodOverrides methodOverrides;
    private String factoryBeanName;
    private String factoryMethodName;
    private String initMethodName;
    private String destroyMethodName;
    private boolean enforceInitMethod;
    private boolean enforceDestroyMethod;
    private boolean synthetic;
    private int role;
    private String description;
    private Resource resource;
复制代码

Sign resolved BeanDefinition

We parsed the configuration file, for beanDefinition get has to meet subsequent use, and the only remaining work is registered. We entered into

#DefaultBeanDefinitionDocumentReader
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)  {
    //使用beanName做唯一标识注册
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    //注册所有别名
        String[] aliases = definitionHolder.getAliases();
        if(aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;
            for(int var6 = 0; var6 < var5; ++var6) {
                String alias = var4[var6];
                registry.registerAlias(beanName, alias);
            }
        }

    }
复制代码

As can be seen from the above code will be parsed beanDefinition BeanDefinitioinRegistry type registered in the registry, and for registration beanDefinition into two parts: registration and registration beanName alias.

  1. By registering beanName BeanDefinition for beanDefinition registration, essentially beanName as a key, into the map. public void registerBeanDefinition (String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {

            if(beanDefinition instanceof AbstractBeanDefinition) {
                try {//最后一次校验
                    ((AbstractBeanDefinition)beanDefinition).validate();
                } catch (BeanDefinitionValidationException var9) 
                }
            }
    
            BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
            if(oldBeanDefinition != null) {
            //...省略 如果beanName 存在,且不允许覆盖,就抛出异常
                if(!this.isAllowBeanDefinitionOverriding()) {
                   
                }
                this.beanDefinitionMap.put(beanName, beanDefinition);
            } else {
                if(this.hasBeanCreationStarted()) {
                    Map var4 = this.beanDefinitionMap;
                    //加锁 放进map
                    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;
                        if(this.manualSingletonNames.contains(beanName)) {
                            Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
                            updatedSingletons.remove(beanName);
                            this.manualSingletonNames = updatedSingletons;
                        }
                    }
                } else {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    this.beanDefinitionNames.add(beanName);
                    this.manualSingletonNames.remove(beanName);
                }
    
                this.frozenBeanDefinitionNames = null;
            }
    
            if(oldBeanDefinition != null || this.containsSingleton(beanName)) {
                this.resetBeanDefinition(beanName);//重置所有beanName缓存
            }
    
        }
    复制代码
    1. Alias ​​registered BeanDefinition public void registerAlias ​​(String name, String alias) {// if beanName with the same alias if not recorded alias, and delete the corresponding alias if (alias.equals (name)) {this.aliasMap.remove (alias) ;} else {String registeredName = (String) this.aliasMap.get (alias); if (registeredName = null!) {if (registeredName.equals (name)) {return;}

                      if(!this.allowAliasOverriding()) {
                  }
      
                  this.checkForAliasCircle(name, alias);
                  //注册
                  this.aliasMap.put(alias, name);
              }
      
          }
      复制代码

Guess you like

Origin juejin.im/post/5bc051d7e51d450e63226636