菜鸟学习 Spring 之注册 BeanDefinition

BeanFactory

BeanFactory 是 Spring IoC 容器的具体实现,是 Spring 容器的核心接口。

DefaultListableBeanFactory

XmlBeanFactory 继承自 DefaultListableBeanFactory 而 DefaultListableBeanFactory 是整个 bean 加载的核心部分。是 Spring 注册及加载的默认实现。

类层级结构图

在这里插入图片描述

  1. AliasRegistry:定义对 alias 的简单增删改查等操作。
  2. SimpleAliasRegistry:主要使用 map 作为 alias 的缓存,并对接口 AliasRegistry 进行实现。
  3. BeanDefinitionRegistry:定义对 BeanDefinition 的各种增删改查。
  4. SingletonBeanRegistry:定义对单例的注册及获取。
  5. DefaultSingletonBeanRegistry:对接口 SingletonBeanRegistry 各函数的实现。
  6. FactoryBeanRegistrySupport:在 DefaultSingletonBeanRegistry 的基础上增加了对 FactoryBean 的特殊处理功能。
  7. BeanFactory:定义获取 bean 及 bean 的各种属性。
  8. HierarchicalBeanFactory:继承 BeanFactory 在 BeanFactory 定义功能的基础上增加了对 parentFactory 的支持。
  9. ConfigurableBeanFactory:提供配置 Factory 的各种方法。
  10. ListableBeanFactory:根据各种条件获取 bean 的配置菜单。
  11. AbstractBeanFactory:综合 FactoryBeanRegistrySupport 并对接口 AutowireCapableBeanFactory 进行实现。
  12. ConfigurableListableBeanFactory:BeanFactory 配置清单,指定忽略类型及接口等。
  13. DefaultListableBeanFactory:综合上面所述功能,主要是对 Bean 注册后的处理。
  14. XmlBeanFactory:对 DefaultListableBeanFactory 进行了扩展,主要用于从 XML 文档读取 BeanDefinition,对于注册和获取 Bean 都是使用从父类 DefaultListableBeanFactory 继承的方法去实现,在 XmlBeanFactory 中主要使用 reader 属性对资源文件进行读取和注册。

好了,看官看到这里已经对 Spring 的容器功能有了一个大致的了解。我本地的 Spring 版本是 5.1.3.RELEASE 下面我们要就开始探索之路了!

首先第一步先初始化一个具体实现类型是 XmlBeanFactory 的 BeanFactory。

ClassPathResource resource = new ClassPathResource("conf/spring/applicationContext.xml");
BeanFactory factory = new XmlBeanFactory(resource);

对配置文件封装返回了一个 ClassPathResource 后调用了 XmlBeanFactory 构造方法,代码如下。

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);
    }

XmlBeanDefinitionReader 是读取 Spring 中重要的功能,因为 Spring 的大部分功能都是以配置作为切入点,下面 XmlBeanDefinitionReader.loadBeanDefinitions(resource); 是资源加载的真正实现,也是我们重点分析之一。

继续跟踪代码:

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return this.loadBeanDefinitions(new EncodedResource(resource));
    }

发现用 EncodedResource 封装了 resource,EncodedResource 通过名称,我们可以大致推断出对资源文件进行编码处理的。

public EncodedResource(Resource resource) {
		// 内部再次调用构造函数 
        this(resource, (String)null, (Charset)null);
    }

private EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset) {
		// 判断资源是否合法
        Assert.notNull(resource, "Resource must not be null");
        this.resource = resource;
        this.encoding = encoding;
        this.charset = charset;
    }

那么这样就初始化了一个 EncodedResource 作为参数传入 return this.loadBeanDefinitions(new EncodedResource(resource)); 继续往下看由于代码过长删除了部分不重要的:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		// 判断参数是否合法
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if(this.logger.isTraceEnabled()) {
            this.logger.trace("Loading XML bean definitions from " + encodedResource);
        }
		
		// 通过内部属性来记录已经加载的资源
        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if(currentResources == null) {
        	// 如果获取不到则初始化一个 HashSet
            currentResources = new HashSet(4);
			// 将 currentResources  放入属性中,这个属性是线程安全的因为它是
			// private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded;
            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 {
            	// 从 encodedResource 中获取 resource.getInputStream() 获取到输入流
                InputStream inputStream = encodedResource.getResource().getInputStream();

                try {
                	// 将输入流传入到 InputSource 中从包名中能看出是解析 xml 用的 org.xml.sax.InputSource
                    InputSource inputSource = new InputSource(inputStream);
					// 如果编码设置不为 null 则设置对应的编码
                    if(encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
					// 划重点进度到了逻辑核心部分
                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {
                }
            } catch (IOException var15) {
            } finally {
            }
            return var5;
        }
    }

我们来看一看 doLoadBeanDefinitions 的代码实现:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
        	// 通过 SAX 解析 XML 获取 document
            Document doc = this.doLoadDocument(inputSource, resource);
            // 真正核心处理部分
            int count = this.registerBeanDefinitions(doc, resource);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        } catch (BeanDefinitionStoreException var5) {
        } catch (SAXParseException var6) {
        } catch (SAXException var7) {
        } catch (ParserConfigurationException var8) {
        } catch (IOException var9) {
        } catch (Throwable var10) {
        }
    }

继续跟踪 this.registerBeanDefinitions(doc, resource);

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// 使用 DefaultBeanDefinitionDocumentReader.class 实例化 BeanDefinitionDocumentReader
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
        // 统计当前 beanDefinition 的加载个数 this.beanDefinitionMap.size();
        int countBefore = this.getRegistry().getBeanDefinitionCount();
        // 划重点加载及注册类
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        // 统计本地需要加载的 beanDefinition 个数
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }

现在体会到什么叫山路十八弯了,竟然还没有到关键代码,我们来继续跟踪 documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		// 将传过来的参数赋值成员属性
        this.readerContext = readerContext;
        // 划重点
        this.doRegisterBeanDefinitions(doc.getDocumentElement());
    }
 
 protected void doRegisterBeanDefinitions(Element root) {
 		// 创建专门处理解析的 BeanDefinitionParserDelegate
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
        // 判断 xml 的 namespace 是否符合 http://www.springframework.org/schema/beans
        if(this.delegate.isDefaultNamespace(root)) {
        	// 处理 profile 属性
            String profileSpec = root.getAttribute("profile");
            if(StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
                if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
                    }

                    return;
                }
            }
        }
		// 空函数解析前置处理给子类实现
        this.preProcessXml(root);
        // 划重点核心逻辑
        this.parseBeanDefinitions(root, this.delegate);
        // 空函数解析后置处理留给子类实现
        this.postProcessXml(root);
        this.delegate = parent;
    }

经历艰难险阻,终于看到了希望处理了 profile 后可以进行 xml 的读取了,跟踪代码进入 this.parseBeanDefinitions(root, this.delegate);

protected 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);
        }
    }

我们只需要看对默认标签的 bean 处理就可以了继续跟踪代码

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if(delegate.nodeNameEquals(ele, "import")) {
        	// 对 import 标签的处理
            this.importBeanDefinitionResource(ele);
        } else if(delegate.nodeNameEquals(ele, "alias")) {
        	// 对 alias 标签的处理
            this.processAliasRegistration(ele);
        } else if(delegate.nodeNameEquals(ele, "bean")) {
        	// 对 bean 标签的处理
            this.processBeanDefinition(ele, delegate);
        } else if(delegate.nodeNameEquals(ele, "beans")) {
        	// 对 beans 标签的处理
            this.doRegisterBeanDefinitions(ele);
        }
    }

对 bean 标签的处理是最复杂的所以我们来看 this.processBeanDefinition(ele, delegate); 其他的感兴趣的可以自己去研究。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// 划重点委托 BeanDefinitionParserDelegate 解析元素这时 BeanDefinitionHolder 已经有基本的 bean 信息了
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null) {
        	// 当 BeanDefinitionHolder 不为空的情况下若存在默认标签的子节点下再有自定义属性再次解析
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
            	// 对解析后的 BeanDefinitionHolder 进行注册
                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));
        }
    }

继续跟踪 delegate.parseBeanDefinitionElement(ele);

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

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		// 取出 id 属性
        String id = ele.getAttribute("id");
        // 取出 name 属性
        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));
        }
        // 如果 id 为空并且 name 不为空则取第一个 name
        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);
        }
        
        // 划重点将信息封装到 AbstractBeanDefinition 中其实际类型是 GenericBeanDefinition
        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
        if(beanDefinition != null) {
            if(!StringUtils.hasText(beanName)) {
                try {
                    if(containingBean != null) {
                    	// 如果发现没有指定 name 则按规则生成
                        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 返回
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }

我们继续跟踪 this.parseBeanDefinitionElement(ele, beanName, containingBean); 胜利就在前方!

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
		// 加个解析标识
        this.parseState.push(new BeanEntry(beanName));
        // 取出 className
        String className = null;
        if(ele.hasAttribute("class")) {
            className = ele.getAttribute("class").trim();
        }

		// 解析 parent 属性
        String parent = null;
        if(ele.hasAttribute("parent")) {
            parent = ele.getAttribute("parent");
        }

        try {
        	// 创建用户保存 bean 属性的 AbstractBeanDefinition 实际类型是 GenericBeanDefinition 将 bean 的 Class 对象赋值进去
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            // 解析 bean 标签内的各种属性 scope、lazy-init、init-method 等等
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            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);
            // 解析 property 属性
            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) {
        } catch (NoClassDefFoundError var14) {
        } catch (Throwable var15) {
        } finally {
            this.parseState.pop();
        }
        return null;
    }

BeanDefinition 是一个接口,在 spring 中也有三种实现 RootBeanDefinition、ChildBeanDefinition 以及 GenericBeanDefinition。均继承了 AbstractBeanDefinition,BeanDefinition 是配置文件 元素在容器中的表现形式。 元素拥有的属性 BeanDefinition 都提供了对应的属性。

终于看到了所有解析的函数,对于配置文件解析也解析完了,装饰也装饰完了对于得到的 BeanDefinition 可以满足后续的使用要求了。唯一还剩下的工作就是注册了,也就是 DefaultBeanDefinitionDocumentReader 中的 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry()); 函数了。

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        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);
            }
        }
    }

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 {
            	// 最后在做一次 methodOverrides 校验
                ((AbstractBeanDefinition)beanDefinition).validate();
            } catch (BeanDefinitionValidationException var9) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9);
            }
        }

        BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        if(existingDefinition != null) {
        	// 如果对应的 beanName 已经注册并且不允许覆盖则抛出异常
            if(!this.isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            if(existingDefinition.getRole() < beanDefinition.getRole()) {
                if(this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
                }
            } else if(!beanDefinition.equals(existingDefinition)) {
                if(this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
                }
            } else if(this.logger.isTraceEnabled()) {
                this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
            }

            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            if(this.hasBeanCreationStarted()) {
                Map var4 = this.beanDefinitionMap;
                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 {
            	// 注册到 beanDefinitionMap 中 key 是 beanName,value 是 beanDefinition
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }
        if(existingDefinition != null || this.containsSingleton(beanName)) {
        	// 重置 beanName 对应的缓存
            this.resetBeanDefinition(beanName);
        }
    }

最后通知监听器解析及注册完成 DefaultBeanDefinitionDocumentReader 中的 this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 完成此工作!

到最后发现写了好长一篇,帮助了自己巩固记忆,如果写的不足之处望指出谢谢各位观看!

猜你喜欢

转载自blog.csdn.net/qq_16830879/article/details/88029703