MyBatis 源码篇-资源加载

Posted 殷建卫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis 源码篇-资源加载相关的知识,希望对你有一定的参考价值。

本章主要描述 MyBatis 资源加载模块中的 ClassLoaderWrapper 类和 Java 加载配置文件的三种方式。

ClassLoaderWrapper

上一章的案例,使用 org.apache.ibatis.io.Resources#getResourceAsStream(java.lang.String) 方法加载 MyBatis 的配置文件。Resources 是一个提供了多个静态方法的工具类,内部封装了 ClassLoaderWrapper 类的静态字段,Resources 提供的方法都是在 ClassLoaderWrapper 对象中实现的。

ClassLoaderWrapper 主要提供了三类方法:classForName() 方法、getResourceAsStream() 方法、getResourceAsURL() 方法,这三个方法都有多个重载。这里以 getResourceAsStream() 方法为例进行介绍。

org.apache.ibatis.io.ClassLoaderWrapper#getResourceAsStream(java.lang.String, java.lang.ClassLoader[]) 方法源码如下:

public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
  return getResourceAsStream(resource, getClassLoaders(classLoader));
}

// 该方法返回ClassLoader[]数组,该数组指明了类加载器的使用顺序
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
  return new ClassLoader[]{
      classLoader,// 参数指定的类加载器
      defaultClassLoader,// 类中指定的默认类加载器
      Thread.currentThread().getContextClassLoader(),// 当前线程绑定的类加载器
      getClass().getClassLoader(),// 加载当前类所使用的类加载器
      systemClassLoader};// 系统类加载器
}

InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
  // 遍历ClassLoader数组
  for (ClassLoader cl : classLoader) {
    if (null != cl) {
      // 调用ClassLoader.getResourceAsStream方法加载指定的资源
      InputStream returnValue = cl.getResourceAsStream(resource);
      // 尝试以“/”开头,再次查找
      if (null == returnValue) {
        returnValue = cl.getResourceAsStream("/" + resource);
      }
      if (null != returnValue) {
        return returnValue;
      }
    }
  }
  return null;
}

getResourceAsStream() 方法本质还是使用 Java 类加载器的方式加载配置文件。

Java 加载配置文件的三种方式

项目结构是普通的 Java 项目,非 Maven 项目。如果是 Maven 项目,配置文件会放在 resources 目录下,打成 jar 文件后,配置文件会存在 classpath 根目录下,所以一般使用类加载器的方式加载配置文件。

以下内容转载自:《Java中加载配置文件的三种方式》

配置文件放置位置如下图所示:

技术图片

1. 通过文件路径加载

/**
 * 通过文件路径加载
 *
 * @throws Exception
 */
public static void loadByFilePath() {
    InputStream in = null;
    try {
        in = new FileInputStream(
                "E:/project/test/src/com/resource/config.properties");
        Properties props = new Properties();
        props.load(in);
        String host = props.getProperty("host");
        System.out.println(host);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

FileInputStream 中的参数是配置文件的真实路径。

2. 通过的 Class 的 getResourceAsStream 进行加载

采用相对路径的方式:

/**
 * 通过的 Class 的 getResourceAsStream 进行加载,相对路径
 */
public static void loadByClassRelativePath() {
    InputStream in = null;
    try {
        in = ResourceLoader.class.getResourceAsStream("config.properties");
        Properties props = new Properties();
        props.load(in);
        String host = props.getProperty("host");
        System.out.println(host);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

采用绝对路径的方式:

/**
 * 通过的 Class 的 getResourceAsStream 进行加载,绝对路径
 */
public static void loadByClassAbsolutePath() {
    InputStream in = null;
    try {
        in = ResourceLoader.class.getResourceAsStream("/com/resource/config.properties");
        Properties props = new Properties();
        props.load(in);
        String host = props.getProperty("host");
        System.out.println(host);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3. 通过类加载器的方式进行加载

/**
 * 通过类加载器的方式进行加载
 */
public static void loadByClassLoader() {
    InputStream in = null;
    try {
        // ClassLoader会在classpath所在的根目录下查找文件
        // 注意:目录最前面不要加 /
        in = ResourceLoader.class.getClassLoader().getResourceAsStream("com/resource/config.properties");
        Properties props = new Properties();
        props.load(in);
        String host = props.getProperty("host");
        System.out.println(host);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

MyBatis 源码篇

 

以上是关于MyBatis 源码篇-资源加载的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis 源码学习(12)-资源加载

MyBatis 源码篇-插件模块

# Mybatis源码解析之配置加载

mybatis源码解析之Configuration加载

Android 逆向类加载器 ClassLoader ( 类加载器源码简介 | BaseDexClassLoader | DexClassLoader | PathClassLoader )(代码片段

Mybatis 源码学习(13)-DataSource