MyBatis源码剖析(1)配置文件的加载

自此开启MyBatis源码分析,理解大神的架构,写在开头,以此纪念,2020年9月12日08:53:34

一、MyBatis的简单使用

1. 配置文件

主配置文件mybatis_config.xml以及从配置文件db.properties,其中db.properties为数据连接的一些信息。

mybatis_config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <!-- 加载类路径下的属性文件 -->
    <properties resource="db.properties"/>
    
    <settings>
        <!--关闭一级缓存 -->
        <setting name="cacheEnabled" value="false"/>
    </settings>

    <!-- 设置一个默认的连接环境信息 -->
    <environments default="mysql_developer">
        <!-- 连接环境信息,取一个任意唯一的名字 -->
        <environment id="mysql_developer">
            <!-- mybatis使用jdbc事务管理方式 -->
            <transactionManager type="jdbc"/>
            <!-- mybatis使用连接池方式来获取连接 -->
            <dataSource type="pooled">
                <!-- 配置与数据库交互的4个必要属性 -->
                <property name="driver" value="${mysql.driver}"/>
                <property name="url" value="${mysql.url}"/>
                <property name="username" value="${mysql.username}"/>
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>

        <!-- 连接环境信息,取一个任意唯一的名字 -->
        <environment id="mysql_developer">
            <!-- mybatis使用jdbc事务管理方式 -->
            <transactionManager type="jdbc"/>
            <!-- mybatis使用连接池方式来获取连接 -->
            <dataSource type="pooled">
                <!-- 配置与数据库交互的4个必要属性,对应db.properties中的数据库连接信息 -->
                <property name="driver" value="${mysql.driver}"/>
                <property name="url" value="${mysql.url}"/>
                <property name="username" value="${mysql.username}"/>
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- *mapper.xml文件对应的信息 -->
        <mapper resource="IPersonMapper.xml" />
    </mappers>

</configuration>

db.properties:

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mybatis_analyze
mysql.username=root
mysql.password=123456

2.创建核心启动信息

在创建好数据表和实体类之后,紧接着创建*mapper.xml文件,此文件对应mapper接口的查询配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace属性是名称空间,必须唯一,此处为Mapper文件全限定类名 -->
<mapper namespace="com.lightingsui.mapper.IPersonMapper">

    <!-- resultMap标签:映射实体与表
         type属性:表示实体全路径名
         id属性:为实体与表的映射取一个任意的唯一的名字
    -->
    <resultMap type="com.lightingsui.pojo.Person" id="studentMap">
        <!-- id标签:映射主键属性
             result标签:映射非主键属性
             property属性:实体的属性名
             column属性:表的字段名
        -->
        <id property="id" column="id"/>
        <result property="pName" column="p_name"/>
        <result property="sex" column="sex"/>
        <result property="address" column="address"/>
    </resultMap>

    <select id="selectAll" resultMap="studentMap">
        select * from person
    </select>

</mapper>

3.启动类

// 此处填写的名称应该为配置文件的名称
Reader reader = Resources.getResourceAsReader("mybatis_config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

SqlSession sqlSession = sqlSessionFactory.openSession();

List<Person> persons = sqlSession.selectList("com.lightingsui.mapper.IPersonMapper.selectAll");

二、配置文件加载源码分析

1.概述

Reader reader = Resources.getResourceAsReader("mybatis_config.xml");

通过加载配置文件,返回了字符流Reader,透过Resources源码,发现Resources可以返回多种格式的IO

  • URL**(getResourceURL)**
  • InputStream (getResourceAsStream)
  • Properties (getResourceAsProperties)
  • Reader (getResourceAsReader)
  • File (getResourceAsFile)

现在Resources类的大概作用应该有所了解了,通过输入配置文件名称,从而将配置文件加载为Java中的IO,而加载之后的流供给下一步进行解析

2. Resources解析

在Resources中,共有两个属性,其中一个特别重要的属性就是classLoaderWrapper。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Y6N3RKK-1599884242202)(https://raw.githubusercontent.com/lightingsui/Pic/master/img/20200912091806.png)]

关于charset,它的作用就是在将配置文件转换为Reader(getResourceAsReader)时生效的,将配置文件转化为指定字符编码的字符,如果不进行设定,那么将使用系统默认的。

charset只在转化为Reader时生效,其它无效

Resources中的所有方法,内部都是调用了ClassLoaderWrapper实现的。

3.ClassLoaderWrapper解析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lJ02xCH5-1599884242204)(https://raw.githubusercontent.com/lightingsui/Pic/master/img/20200912093419.png)]

作用

ClassLoaderWrapper的作用就是选择合适的类加载器,将配置文件加载为二进制流,返回给Resources,这就是ClassLoaderWrapper的使命。

字段

defaultClassLoader将为自定义的默认类加载器,如果不进行设定,那么为null

systemClassloader为系统加载器,在初始化的过程中通过

systemClassLoader = ClassLoader.getSystemClassLoader();

赋值为ApplicationClassLoader,即系统加载器,主要就是加载classpath下的类

方法

其中一个最重要的方法就是getClassLoaders

ClassLoader[] getClassLoaders(ClassLoader classLoader) {
    return new ClassLoader[]{
        classLoader,  // 参数传递的类加载器
        defaultClassLoader,   // 默认类加载器
        Thread.currentThread().getContextClassLoader(), // 当前线程的类加载器
        getClass().getClassLoader(),  // 当前类的类加载器
        systemClassLoader}; // 系统类加载器
  }

这个方法返回特定顺序的类加载器列表,加载配置文件就是从中顺序的选择能够进行加载的类加载器

另一个方法就是加载类 classForName

/**
 * 进行类的加载
 *
 * @param name        - 待加载类的名称
 * @param classLoader - 类加载器列表
 * @return the class
 * @throws ClassNotFoundException - 类没有找到,则抛出 {@link ClassNotFoundException}
 */
Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
  // 遍历类加载器的列表
  for (ClassLoader cl : classLoader) {

    if (null != cl) {

      try {
	    // 尝试进行类的加载
        return Class.forName(name, true, cl);

      } catch (ClassNotFoundException e) {
        // we'll ignore this until all classloaders fail to locate the class
      }

    }

  }

  throw new ClassNotFoundException("Cannot find class: " + name);

}

另外的一些方法就是将配置文件转化为二进制流,拿一个进行举例,其它同理。

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

// 重载得到下面的方法

InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
    // 拿到类加载器列表后进行遍历
    for (ClassLoader cl : classLoader) {
      if (null != cl) {

        // 尝试加载配置文件
        InputStream returnValue = cl.getResourceAsStream(resource);

        // 如果没有加载到,则前面添加"/"尝试一次
        if (null == returnValue) {
          returnValue = cl.getResourceAsStream("/" + resource);
        }
		//  不为null即加载成功,返回加载后的结果
        if (null != returnValue) {
          return returnValue;
        }
      }
    }
    return null;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值