Spring源码解读 --- 加载bean.xml

Spring源码解读

一、Spring 加载bean.xml的过程

Spring源码解读 --- 加载bean.xml_第1张图片

1. 代码入口

public class DemoApplication {

	public static void main(String[] args) {
        // 通过XmlBeanFactory加载bean.xml文件。
		BeanFactory factory = new XmlBeanFactory(new ClassPathResource("BeanFactoryTest.xml"));
        // 读取bean的对象。
		Person person = (Person) factory.getBean("person");
		System.out.println(person);
	}
}

2. 封装配置文件

上面时序图的第2步就是完成将配置文件BeanFactoryTest.xml封装为Resource的实例。

Resource接口抽象了所有Spring内部使用到的底层资源:File、URL、ClassPath等。

下面是Resource接口的实现类。

ContextResource (org.springframework.core.io)
HeadMethodResource in ResourceHandlerFunction (org.springframework.web.servlet.function)
HttpResource (org.springframework.web.servlet.resource)
WritableResource (org.springframework.core.io)
AbstractResource (org.springframework.core.io)

3. 初始化XmlBeanFactory

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);// 初始化1
        this.reader = new XmlBeanDefinitionReader(this);//初始化2
        this.reader.loadBeanDefinitions(resource); 
    }
  • 初始化1主要初始化其继承的DefaultListableBeanFactory,父类中的操作主要是初始化一些后面加载bean所用到的容器。
SimpleAliasRegistry (org.springframework.core)
    DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
        FactoryBeanRegistrySupport (org.springframework.beans.factory.support)
            AbstractBeanFactory (org.springframework.beans.factory.support)
                AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
                    DefaultListableBeanFactory (org.springframework.beans.factory.support)
                        XmlBeanFactory (org.springframework.beans.factoy.xml)

此处的beanDefinitionMap就是存放bena的容器。

public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
        super(parentBeanFactory);
        this.autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;
        this.resolvableDependencies = new ConcurrentHashMap(16);
        this.beanDefinitionMap = new ConcurrentHashMap(256);
        this.mergedBeanDefinitionHolders = new ConcurrentHashMap(256);
        this.allBeanNamesByType = new ConcurrentHashMap(64);
        this.singletonBeanNamesByType = new ConcurrentHashMap(64);
        this.beanDefinitionNames = new ArrayList(256);
        this.manualSingletonNames = new LinkedHashSet(16);
    }
  • 初始化2 就是new 一个处理加载bean的对象。其loadBeanDefinitions(resource); 方法就是加载bean的核心方法,具体加载的逻辑都封装在该方法中。

4. 加载操作的切入点

(简单点:doLoadBeanDefinitions(inputSource, encodedResource.getResource());方法进行加载操作。)

此处进行的操作主要有三个:

  • 封装资源文件
  • 获取输入流。
  • 使用前两步准备的数据作为参数调用doLoadBeanDefinitions。该步骤之前的所有操作都是为了准备需要的InputResource对象和Resource对象。

Spring源码解读 --- 加载bean.xml_第2张图片

// 1.封装资源文件。 此处将Resource实现进行再次封装为EncodedResource实现,进行编码设置。   
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);
        }
        // 将当前加载的所有Resource实现都放到一个Set容器中。并且该Set是一个ThreadLocal对象。
        // private final ThreadLocal> resourcesCurrentlyBeingLoaded;
        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if (!currentResources.add(encodedResource)) {//当该set中以存在该encodedResource,则说明其已被加载,存在循环加载的错误。
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var6;
            try {
                // 2. 获取输入流。从EncodedResource中获取封装的Resource对象得到输入流,构造下面的InputSource。
                InputStream inputStream = encodedResource.getResource().getInputStream();
                Throwable var4 = null;

                try {
                    doLoadBeanDefinitions inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
					//3. 此处是加载Bean的真正的方法。
                    var6 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } catch (Throwable var24) {
                    var4 = var24;
                    throw var24;
                } finally {
                    if (inputStream != null) {
                        if (var4 != null) {
                            try {
                                inputStream.close();
                            } catch (Throwable var23) {
                                var4.addSuppressed(var23);
                            }
                        } else {
                            inputStream.close();
                        }
                    }

                }
            } catch (IOException var26) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var26);
            } finally {
                currentResources.remove(encodedResource);
                if (currentResources.isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }

            }

            return var6;
        }
    }

5. doLoadBeanDefinitions方法的加载分析(加载XML文件的核心)

Spring源码解读 --- 加载bean.xml_第3张图片

主要操作步骤:

  • 获取XML文件的验证模式。
  • 加载XML文件得到将其封装的Document对象。
  • 根据其返回的Document对象注册Bean信息到上面一开始初始化的beanDefinitionMap中。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
            // 1. 验证并获取Document对象
            Document doc = this.doLoadDocument(inputSource, resource);
            // 2. 注册xml对象到BeanDefinitionMap容器中。
            int count = this.registerBeanDefinitions(doc, resource);
            return count;
    }
(1)获取验证模式,并封装返回Doc

xml的验证模式分为DTD和XSD。

DTD主要校验文档的格式,使用规则,标签,元素使用是否正确。XSD主要校验文档的内容和结果是否正确。


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">


protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, this.getValidationModeForResource(resource), this.isNamespaceAware());
    }
	// 获取资源的验证模式
    protected int getValidationModeForResource(Resource resource) {
        int validationModeToUse = this.getValidationMode();
        if (validationModeToUse != 1) {// 检测是否手动指定了验证模式
            return validationModeToUse;
        } else {
            int detectedMode = this.detectValidationMode(resource);
            return detectedMode != 1 ? detectedMode : 3;
        }
    }
    // Spring默认的验证模式。
    protected int detectValidationMode(Resource resource) {
        if (resource.isOpen()) {
            throw new BeanDefinitionStoreException("Passed-in Resource [" + resource + "] contains an open stream: cannot determine validation mode automatically. Either pass in a Resource that is able to create fresh streams, or explicitly specify the validationMode on your XmlBeanDefinitionReader instance.");
        } else {
            InputStream inputStream;
            try {
                inputStream = resource.getInputStream();
            } catch (IOException var5) {
                throw new BeanDefinitionStoreException("Unable to determine validation mode for [" + resource + "]: cannot open InputStream. Did you attempt to load directly from a SAX InputSource without specifying the validationMode on your XmlBeanDefinitionReader instance?", var5);
            }

            try {
                //该方法会获xml文件的头部进行校验。
                return this.validationModeDetector.detectValidationMode(inputStream);
            } catch (IOException var4) {
                throw new BeanDefinitionStoreException("Unable to determine validation mode for [" + resource + "]: an error occurred whilst reading from the InputStream.", var4);
            }
        }
    }

获取XML文档的校验模式,包含DOCTYPE就是DTD,不包含就是XSD.

// 返回 3 代表XSD模式,2代表DTD模式。
public int detectValidationMode(InputStream inputStream) throws IOException {
        // 读取xml文档的读取器。
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        byte var4;
        try {
            boolean isDtdValidated = false;

            while(true) {
                String content;
                // 读取一行文本=》 
                if ((content = reader.readLine()) != null) {
                    content = this.consumeCommentTokens(content);
                    if (this.inComment || !StringUtils.hasText(content)) {//如果读取的行是注释或空则跳过。
                        continue;
                    }
				   // 对比是否包含校验字符。
                    if (this.hasDoctype(content)) {
                        isDtdValidated = true;
                    } else if (!this.hasOpeningTag(content)) {
                        continue;
                    }
                }
				
                int var5 = isDtdValidated ? 2 : 3;
                return var5;
            }
        } catch (CharConversionException var9) {
            var4 = 1;
        } finally {
            reader.close();
        }

        return var4;
    }
// 对比是否包含校验字符。
  private boolean hasDoctype(String content) {
        return content.contains("DOCTYPE");
    }
                     
(2)注册bean
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
        int countBefore = this.getRegistry().getBeanDefinitionCount();
        // 注册bean
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
    	// 注册bean的具体方法
        this.doRegisterBeanDefinitions(doc.getDocumentElement());
    }

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)) {
                    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);
        // 解析当前bean对象的方法。
        this.parseBeanDefinitions(root, this.delegate);
        // 解析后处理,留给子类实现 
        this.postProcessXml(root);
        this.delegate = parent;
    }
[1]解析bean
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // Spring默认命名空间的xml进行解析。对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 {
                        delegate.parseCustomElement(ele);//对自定义命名空间进行解析
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);
        }

    }

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);// 主要看对bean的解析
        } else if (delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);
        }

    }
//解析bean标签
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
                // 将注册bean的任务委托给BeanDefinitionReaderUtils。
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }

            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }

[2] 封装BeanDefinition对象

BeanDefinitionHolder创建的BeanDefinition是xml中标签属性对象。

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        String beanName = definitionHolder.getBeanName();
        // 执行注册的方法 将bean封装为可以
        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);
            }
        }

    }
[3] 将BeanDefinition装入Spring的beanDefinitionMap容器中。
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 var8) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
            }
        }

        BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            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 + "]");
            }
            // 终点:将bean放入Spring容器中。此处
            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            if (this.hasBeanCreationStarted()) {
                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;
                    this.removeManualSingletonName(beanName);
                }
            } else {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.removeManualSingletonName(beanName);
            }

            this.frozenBeanDefinitionNames = null;
        }

        if (existingDefinition == null && !this.containsSingleton(beanName)) {
            if (this.isConfigurationFrozen()) {
                this.clearByTypeCache();
            }
        } else {
            this.resetBeanDefinition(beanName);
        }

    }

6 总结


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.mt.domain.Person">
    <property name="name" value="毛桃"/>
    <property name="age" value="18"/>
bean>
beans>

Spring加载xml文件就通过一系列的准备工作,将xml中个标签对象封装为一个BeanDefinition对象,以beanName为key放入到Spring的beanDefinitionMap容器中。
BeanDefinition对象具有id、class等属性。

你可能感兴趣的:(框架技术)