框架学习系列《Mybatis》-系统读取Mybatis-config.xml核心配置文件流程【第一篇】

一.前言

本人是一个java后端开发新手,由于近期的项目中添加了mybatis技术,虽然技术会使用,但是不太了解配置文件是如何加载读取到的,所以按照自己的理解整理出一份说明。
<如有不足之处,麻烦指出>

二.底层代码解析

框架学习系列《Mybatis》-系统读取Mybatis-config.xml核心配置文件流程【第一篇】_第1张图片


图上时序图步骤解析说明<附上代码块,序号和图中序号对应>:
1.一般代码中加载配置只需要一行代码搞定,如下

   //代码中从类路径中加载核心配置文件resource = "mybatis-comfig.xml "
   InputStream inputStream = Resources.getResourceAsStream(resource);

2.重载的方法中创建一个类加载器ClassLoader实例对象loader,并调用类加载器包装类classLoaderWrapper的方法
getResourceAsStream(resource, loader)

/*
   * 以流对象的形式返回类路径上的资源
   *
   * @param resource The resource to find
   * @return The resource
   * @throws java.io.IOException If the resource cannot be found or read
   */
  public static InputStream getResourceAsStream(String resource) throws IOException {
    return getResourceAsStream(null, resource); //调用Resources内部重载方法,参数为路径名
  }

/*
   * 以流对象的形式返回类路径上的资源
   *
   * @param loader   The classloader used to fetch the resource
   * @param resource The resource to find
   * @return The resource
   * @throws java.io.IOException If the resource cannot be found or read
   */
  public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
    InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader); //返回IO流对象InputStream
    if (in == null) throw new IOException("Could not find resource " + resource);
    return in;
  }

3 && 4.classLoaderWrapper来加载器包装类的getResourceAsStream(resource, loader)方法

/*
   * Get a resource from the classpath, starting with a specific class loader
   *
   * @param resource    - the resource to find
   * @param classLoader - the first class loader to try
   * @return the stream or null
   */
  public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
    //getClassLoaders(classLoader)为获取所有类型的类加载器
    return getResourceAsStream(resource, getClassLoaders(classLoader)); 
  }

//4.自调getClassLoaders(classLoader)方法,返回一个类加载器数组,内部包含5类加载器
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
        return new ClassLoader[]{  
            classLoader,   //由参数指定的默认类加载器
            defaultClassLoader, //系统指定的类加载器
            Thread.currentThread().getContextClassLoader(), //当前线程绑定的类加载器
            getClass().getClassLoader(), //加载当前类所使用的类加载器
            systemClassLoader}; //系统类加载器
      }

5 && 6.循环使用每一个类加载器去加载配置路径资源,每个类最多加载两次,第一次直接以配置文件名作为路径加载,如果没有加载到资源,则拼接一个"/"形成一个新的路径名再次加载

 /*
   * Try to get a resource from a group of classloaders
   * 尝试循环使用每一个类加载器去加载资源
   *
   * @param resource    - the resource to get
   * @param classLoader - the classloaders to examine
   * @return the resource or null
   */
  InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
    for (ClassLoader cl : classLoader) {
      if (null != cl) {
        // try to find the resource as passed
        InputStream returnValue = cl.getResourceAsStream(resource);  //第一次加载
        // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
        //如果第一次未加载到,拼接地址再次加载(第二次加载)
        if (null == returnValue) returnValue = cl.getResourceAsStream("/" + resource); 
        if (null != returnValue) return returnValue;
      }
    }
    //两次都没加载到,返回null,下一个类加载器classLoader继续重复上面操作
    return null;
  }

//6.每个类加载器classLoader去调用方法getResourceAsStream(resource)方法,内部自调方法getResource(name)
   /**
     * Returns an input stream for reading the specified resource.
     * 返回用于读取指定资源的输入流
     * 

The search order is described in the documentation for {@link * #getResource(String)}.

* * @param name * The resource name * * @return An input stream for reading the resource, or null * if the resource could not be found * * @since 1.1 */
public InputStream getResourceAsStream(String name) { URL url = getResource(name); //自调 try { return url != null ? url.openStream() : null; } catch (IOException e) { return null; } } //内部自调方法getResource(name) /** * Finds the resource with the given name. A resource is some data * (images, audio, text, etc) that can be accessed by class code in a way * 查找具有给定名称的资源。资源是一些数据(图像、音频、文本等),可以通过类代码以某种方式访问 * that is independent of the location of the code. * *

The name of a resource is a '/'-separated path name that * identifies the resource. * *

This method will first search the parent class loader for the * resource; if the parent is null the path of the class loader * built-in to the virtual machine is searched. That failing, this method * will invoke {@link #findResource(String)} to find the resource.

* * @param name * The resource name * * @return A URL object for reading the resource, or * null if the resource could not be found or the invoker * doesn't have adequate privileges to get the resource. * * @since 1.1 */
public URL getResource(String name) { URL url; if (parent != null) { //parent 为此类ClassLoader类加载器中初始化委托的父类装入器 //private final ClassLoader parent; url = parent.getResource(name); } else { url = getBootstrapResource(name); //自调getBootstrapClassPath方法返回一个URLClassPath实例对象 } if (url == null) { url = findResource(name); } return url; }

7 && 8 && 9.自调getBootstrapClassPath方法返回一个URLClassPath实例对象

    /**
    * Find resources from the VM's built-in classloader.
    * 从VM的内置类加载器中查找资源。
    */
   private static URL getBootstrapResource(String name) {
       URLClassPath ucp = getBootstrapClassPath();  
       //8.调用URLClassPath类中getResource(name)返回Resource实例对象
       Resource res = ucp.getResource(name); 
       return res != null ? res.getURL() : null;
   }

   //A:返回用于查找系统资源的URLClassPath。
   static URLClassPath getBootstrapClassPath() {
       return sun.misc.Launcher.getBootstrapClassPath();
   }

10.classLoaderWrapper将最终获取的IO流InputStream对象加载的配置资源返还给Resource

/*
   * 以流对象的形式返回类路径上的资源
   *
   * @param loader   The classloader used to fetch the resource
   * @param resource The resource to find
   * @return The resource
   * @throws java.io.IOException If the resource cannot be found or read
   */
  public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
    InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader); //返回IO流对象InputStream
    if (in == null) throw new IOException("Could not find resource " + resource);
    return in;
  }
    //获取到的inputStream流对象返回Resource<逆向反推到最开始的那段代码>
    //代码中从类路径中加载核心配置文件mybatis-comfig.xml 
    InputStream inputStream = Resources.getResourceAsStream(resource);

你可能感兴趣的:(Mybatis)