The spring loaded container resources to achieve

In the previous section to achieve a spring container Detailed We've done some preparation work before loading resources, such as: will configure our xml turn into spring accredited Resource, as well as the required load, etc. Next we look Yes. how to load and look at the code:

 XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

The code we have completed half of the operation, when the conditions of the new XmlBeanFactory, then look XmlBeanFactory do what operating code into the following:

public class XmlBeanFactory extends DefaultListableBeanFactory {
//很重要的一个属性,实质上所有的加载读取操作都在XmlBeanDefinitionReader中完成
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);


/**
 * Create a new XmlBeanFactory with the given resource,
 * which must be parsable using DOM.
 * @param resource the XML resource to load bean definitions from
 * @throws BeansException in case of loading or parsing errors
 */

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

/**
 * Create a new XmlBeanFactory with the given input stream,
 * which must be parsable using DOM.
 * @param resource the XML resource to load bean definitions from
 * @param parentBeanFactory parent bean factory
 * @throws BeansException in case of loading or parsing errors
 */
/**parentBeanFactory为父BeanFactory,一般用于factory的合并,所以可以为null*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
    super(parentBeanFactory);
    //该方法是加载资源的真正入口
    this.reader.loadBeanDefinitions(resource);
  }

}

In the above code, the method used to initialize the two operations, but the first call, and the required parameters inside is not the same, the other is nonsense, this.reader.loadBeanDefinitions (resource) is loaded resources truly, look at it before we start to understand it calls the parent class's method did what in the end, as follows:

/**
 * Create a new DefaultListableBeanFactory with the given parent.
 * @param parentBeanFactory the parent BeanFactory
 */
public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
    super(parentBeanFactory);
}

Dbug DefaultListableBeanFactory came to his father, originally a XmlBeanFactory is to expand the bean factory DefaultListableBeanFactory for implementation bean in xml configuration, pull away, and here we did not want to see, and then go down, high-energy front:

/**
 * Create a new AbstractAutowireCapableBeanFactory with the given parent.
 * @param parentBeanFactory parent bean factory, or {@code null} if none
 */
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
    this();
    setParentBeanFactory(parentBeanFactory);
}

We came to the initialization method AbstractAutowireCapableBeanFactory, watching a hanging thing is, here calls the no-argument constructor interior # this (), we look at:

  /**
 * Create a new AbstractAutowireCapableBeanFactory.
 */
public AbstractAutowireCapableBeanFactory() {
    super();
    ignoreDependencyInterface(BeanNameAware.class);
    ignoreDependencyInterface(BeanFactoryAware.class);
    ignoreDependencyInterface(BeanClassLoaderAware.class);
}
  • IgnoreDependencyInterface main role is negligible for automatic assembly function for a given interface.

Simple cite cases:
When A owns a property B, if Spring in getting A, if the property B has not been initialized, at the moment spring automatically initializes B, this feature is also spring a very important characteristic of course, there are advantages and b.
there is a possibility attribute B is not initialized, B BeanNameAware achieved when the interface.

That constructor above also call the parent class, and we may very curious, well, to satisfy my curiosity, I also was curious, direct look at the code:

/**
 * Create a new AbstractBeanFactory.
 */
public AbstractBeanFactory() {
}

This is the right method to achieve top-level parent class AbstractBeanFactory, is this a bird stuff. Hey, we are in a way also saw a AbstractAutowireCapableBeanFactory # setParentBeanFactory () method, you need a factory as a parameter, the method used to doing view :

public void setParentBeanFactory(@Nullable BeanFactory parentBeanFactory) {
    if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) {
        throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory);
    }
    this.parentBeanFactory = parentBeanFactory;
}

This method is a method of setting attribute values ​​AbstractBeanFactory # setParentBeanFactory (), because he has such a property inside:

/** Parent bean factory, for bean inheritance support. */
@Nullable
private BeanFactory parentBeanFactory;

We can finally return to normal, and to see this.reader.loadBeanDefinitions (resource) which in the end did what, direct look at the code:

/**
 * 该方法主要是从xml中加载bean的定义
 * @param resource 对我们xml文件的封装和描述
 * @return 返回 bean definition的个数
 * @throws BeanDefinitionStoreException
 */
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    return loadBeanDefinitions(new EncodedResource(resource));
}
  • This method is XmlBeanDefinitionReader # loadBeanDefinitions, the main role is the number of load bean definitions.
  • Second, the method also calls #loadBeanDefinitions internal () method.
  • More important is that this method requires EncodedResource class or method of its implementation as a parameter

We can infer from substantially the EncodedResource class code resource for our encapsulation encoding aspect, there is only speculation, and then look at how particular:

  public EncodedResource(Resource resource, @Nullable String encoding) {
    this(resource, encoding, null);
}

The method described above is EncodedResource class initialization method called here an internal point of view:

 * Create a new {@code EncodedResource} for the given {@code Resource},
 * using the specified {@code encoding}.
 * @param resource the {@code Resource} to hold (never {@code null})
 * @param encoding the encoding to use for reading from the resource
 */
public EncodedResource(Resource resource, @Nullable String encoding) {
    this(resource, encoding, null);
}

L method is simple, a look clear, but there is a modulation method of initialization parameters here three, look:

  /**
 * Create a new {@code EncodedResource} for the given {@code Resource},
 * using the specified {@code Charset}.
 * @param resource the {@code Resource} to hold (never {@code null})
 * @param charset the {@code Charset} to use for reading from the resource
 */
public EncodedResource(Resource resource, @Nullable Charset charset) {
    this(resource, null, charset);
}

private EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset) {
    super();
    Assert.notNull(resource, "Resource must not be null");
    this.resource = resource;
    this.encoding = encoding;
    this.charset = charset;
}

Here is the real initialization operation, the associated assignment, look at the way EncodedResource important properties and methods:

Attributes
public class EncodedResource implements InputStreamSource {

private final Resource resource; //资源(封装我们自己的xml之后的抽象类)

@Nullable
private final String encoding;//resource中的编码

@Nullable
private final Charset charset;//也是从resource读取到的字符集如:utf-8等一般是是他

This is EncodedResource property, we see that it also implements this interface InputStreamSource, remember this interface is a very important way InputStream #getInputStream (), this method is to read the contents of our package resources

method
public Reader getReader() throws IOException {
    if (this.charset != null) {
        return new InputStreamReader(this.resource.getInputStream(), this.charset);
    }
    else if (this.encoding != null) {
        return new InputStreamReader(this.resource.getInputStream(), this.encoding);
    }
    else {
        return new InputStreamReader(this.resource.getInputStream());
    }
}
  1. The method described above is mainly constructed of a coding InputStreamReader.
  2. When you create a EncodedResource object that came to our core method
  3. loadBeanDefinitions((new EncodedResource(resource))
  4. That is, all before the operation is to pave the way to this method, which means that we are in front of the high-energy, see:
/***
 * 该方法还是返回解析后的bean definition的个数,不同的是用指定的编码去解析
 * @param encodedResource
 * @return
 * @throws BeanDefinitionStoreException
 */
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if (logger.isTraceEnabled()) {
        logger.trace("Loading XML bean definitions from " + encodedResource);
    }
    //获取已经加载过的资源
    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    if (currentResources == null) {
        currentResources = new HashSet<>(4);
        this.resourcesCurrentlyBeingLoaded.set(currentResources);
    }
    //将当前资源加载进去,如果当前资源在currentResources存在,就抛出如下异常
    if (!currentResources.add(encodedResource)) {
        throw new BeanDefinitionStoreException(
                "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    }
    try {
        //这里分了二步走:
        //1.首先调用EncodedResource#getResource去获取封装的资源resource,这里拿到的是classPathResource对象
        //1.1. 然后在调用Resource#getInputStream获取一个inputStream
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            //1.通过获取到的inputStream构建一个InputSource对象
            //2.其中inputStream为BufferedInputStream 为字节流
            //3.主要调用InputSource#setByteStream(byteStream);进行保存
            InputSource inputSource = new InputSource(inputStream);
            //保存对应的编码
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            //这里才是加载资源的真正的核心逻辑处理操作
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        }
        finally {
            //关闭输入流
            inputStream.close();
        }
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException(
                "IOException parsing XML document from " + encodedResource.getResource(), ex);
    }
    finally {
        //从currentResources移除encodedResource
        currentResources.remove(encodedResource);
        if (currentResources.isEmpty()) {
            this.resourcesCurrentlyBeingLoaded.remove();
        }
    }
}

The above method is the primary role XmlBeanDefinitionReader # loadBeanDefinitions (), simply summarize the process:

  • The first is our xml file is packaged into a resource resources, and then set its encoding
  • Came to this method, resourcesCurrentlyBeingLoaded acquired all of the resources, and its main purpose is to contrast with our current resources.
  • If our current resources exist in currentResources in to throw an exception, otherwise save
  • Then to acquire a byte stream inputStream, detailed process has been described in the above code
  • Provided corresponding coding
  • Then call the real core and methods doLoadBeanDefinitions load resources ().
  • Close to this input stream
  • Finally encodedResource removed from currentResources

Next we look at the real core of the process of loading resources

/**
 * Actually load bean definitions from the specified XML file.
 * @param inputSource the SAX InputSource to read from
 * @param resource the resource descriptor for the XML file
 * @return the number of bean definitions found
 * @throws BeanDefinitionStoreException in case of loading or parsing errors
 * @see #doLoadDocument
 * @see #registerBeanDefinitions
 */
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
        throws BeanDefinitionStoreException {

    try {
        //获取一个Document实例对象
        Document doc = doLoadDocument(inputSource, resource);
        //根据我们获取到的Document实例注册bean信息
        int count = registerBeanDefinitions(doc, resource);
        if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + count + " bean definitions from " + resource);
        }
        return count;
    }
    catch (BeanDefinitionStoreException ex) {
        throw ex;
    }
    catch (SAXParseException ex) {
        throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
    }
    catch (SAXException ex) {
        throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                "XML document from " + resource + " is invalid", ex);
    }
    catch (ParserConfigurationException ex) {
        throw new BeanDefinitionStoreException(resource.getDescription(),
                "Parser configuration exception parsing XML from " + resource, ex);
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException(resource.getDescription(),
                "IOException parsing XML document from " + resource, ex);
    }
    catch (Throwable ex) {
        throw new BeanDefinitionStoreException(resource.getDescription(),
                "Unexpected exception parsing XML document from " + resource, ex);
    }
}
  1. The code appears to be very long, we actually did get a Document instance, and registration information bean to the registrar in accordance with Document instances we get.
  2. We have seen instances when obtaining Document, called xmlBeanDefinitionReader # doLoadDocument way we look at this method:
  /***
 * 该方法的主要作用是使用默认的documentLoader去加载文档
 * @param inputSource 是一个SAX 格式的xml InputSource从这里读取
 * @param resource 我们设置了的有编码的资源文件
 * @return Document实例
 * @throws Exception
 */
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
    return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
            getValidationModeForResource(resource), isNamespaceAware());
}

The above is xmlBeanDefinitionReader # doLoadDocument method, we see this method:
1. Call #getValidationModeForResource (Resource resource) method gets the specified resource (xml) authentication mode.

  1. 调用 DocumentLoader#loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) 方法,获取 XML Document 实例.

According to our information Decument instance to register the bean, called xmlBeanDefinitionReader # registerBeanDefinitions () method, the process continues on the above analysis the following article will finally share a timing diagram painted by:

3711017-867408af4d3da779.png
xmlBeanFactory initialization sequence of FIG .png

Reproduced in: https: //www.jianshu.com/p/908a89cb5f21

Guess you like

Origin blog.csdn.net/weixin_34088583/article/details/91252280