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 源码篇-SQL 执行的流程

MyBatis 源码篇-资源加载

MyBatis 源码篇-日志模块1

MyBatis 源码篇-日志模块2

MyBatis 源码篇-插件模块

MyBatis 源码篇-DataSource

MyBatis 源码篇-Transaction

MyBatis 源码篇-MyBatis-Spring 剖析

原文地址:https://www.cnblogs.com/yinjw/p/11757421.html

时间: 2025-01-23 07:25:03

MyBatis 源码篇-资源加载的相关文章

MyBatis 源码篇-日志模块2

上一章的案例,配置日志级别为 debug,执行一个简单的查询操作,会将 JDBC 操作打印出来.本章通过 MyBatis 日志部分源码分析它是如何实现日志打印的. 在 MyBatis 的日志模块中有一个 jdbc package,package 中的内容如下图所示: BaseJdbcLogger 是一个抽象类,它是 jdbc package 下其他类的父类,类继承关系如下图所示: BaseJdbcLogger 类中定义了一些公共集合和简单的工具方法,提供给子类使用. BaseJdbcLogger

MyBatis 源码篇-日志模块1

在 Java 开发中常用的日志框架有 Log4j.Log4j2.Apache Common Log.java.util.logging.slf4j 等,这些日志框架对外提供的接口各不相同.本章详细描述 MyBatis 是如何通过适配器的方式集成和复用这些第三方框架的. 日志适配器 MyBatis 的日志模块位于 org.apache.ibatis.logging 包中,该模块中 Log 接口定义了日志模块的功能,然后分别为不同的日志框架定义不同的日志适配器,这些日志适配器都继承 Log 接口,L

MyBatis 源码篇-DataSource

本章介绍 MyBatis 提供的数据源模块,为后面与 Spring 集成做铺垫,从以下三点出发: 描述 MyBatis 数据源模块的类图结构: MyBatis 是如何集成第三方数据源组件的: PooledConnection 设计初衷猜想: 类图结构 MyBatis 数据源部分的代码在 datasource 目录下. 提供了三种类型的数据源实现:unpooled(没有连接池).pooled(MyBatis 自身实现的连接池).jndi(依赖 JNDI 服务) MyBatis 提供了两个 java

MyBatis 源码篇-MyBatis-Spring 剖析

本章通过分析 mybatis-spring-x.x.x.jar Jar 包中的源码,了解 MyBatis 是如何与 Spring 进行集成的. Spring 配置文件 MyBatis 与 Spring 集成,在 Spring 配置文件中配置了数据源.SqlSessionFactory.自动扫描 MyBatis 中的 Mapper 接口.事务管理等,这部分内容都交由 Spring 管理.部分配置内容如下所示: <?xml version="1.0" encoding="U

MyBatis 源码篇-插件模块

本章主要描述 MyBatis 插件模块的原理,从以下两点出发: MyBatis 是如何加载插件配置的? MyBatis 是如何实现用户使用自定义拦截器对 SQL 语句执行过程中的某一点进行拦截的? 示例准备 首先准备两个拦截器示例,代码如下. @Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.cl

MyBatis 源码篇-Transaction

本章简单介绍一下 MyBatis 的事务模块,这块内容比较简单,主要为后面介绍 mybatis-spring-1.**.jar(MyBatis 与 Spring 集成)中的事务模块做准备. 类图结构 MyBatis 事务模块的代码在 transaction 包下: 根据包的分类,提供了两种事务实现:jdbc.managed. 我们还是先来看下事务模块整体的类图结构: MyBatis 的事务模块和事务模块一样,使用的也是工厂方法设计模式.那么它扩展的方式肯定也是提供相应的事务工厂实现类和事务实现类

Prism 源码解读3-Modules加载

原文:Prism 源码解读3-Modules加载 目录 介绍 0.Modules加载 1.通过AppSetting加载 2.通过代码加载 3.通过目录加载 4.通过手动方式加载 总结 回到顶部 介绍 在软件开发过程中,总想组件式的开发方式,各个组件之间最好互不影响,独立测试.Prism的Modules很好的满足了这一点. 这个架构图很好了讲解了Prism的Modules的概念 Prism支持通过配置文件,文件夹,手动载入Module的方式,并且对Module的载入进行验证,包括重复和循环依赖验证

深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)[转]

上篇文章<深入浅出Mybatis系列(二)---配置简介(mybatis源码篇)>我们通过对mybatis源码的简单分析,可看出,在mybatis配置文件中,在configuration根节点下面,可配置properties.typeAliases.plugins.objectFactory.objectWrapperFactory.settings.environments.databaseIdProvider.typeHandlers.mappers这些节点.那么本次,就会先介绍prope

深入浅出Mybatis系列(四)---配置详解之typeAliases别名(mybatis源码篇)[转]

上篇文章<深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)> 介绍了properties与environments, 本篇继续讲剩下的配置节点之一:typeAliases. typeAliases节点主要用来设置别名,其实这是挺好用的一个功能, 通过配置别名,我们不用再指定完整的包名,并且还能取别名. 例如: 我们在使用 com.demo.entity. UserEntity 的时候,我们可以直接配置一个别名user, 这样