Mybatis初始化

和 Spring 框架 的 IoC 容器初始化 一样,Mybatis 也会通过定位、解析相应的配置文件完成自己的初始化。Mybatis 的配置文件主要有 mybatis-config.xml 核心配置文件 及一系列映射配置文件,另外,Mybatis 也会根据注解进行配置。

1 BaseBuilder

Mybatis 初始化 的主要内容是加载并解析 mybatis-config.xml 配置文件、映射配置文件以及相关的注解信息。Mybatis 的初始化入口是 SqlSessionFactoryBuilder 的 build()方法。

public class SqlSessionFactoryBuilder {
   

  public SqlSessionFactory build(Reader reader) {
   
    return build(reader, null, null);
  }

  public SqlSessionFactory build(Reader reader, String environment) {
   
    return build(reader, environment, null);
  }

  public SqlSessionFactory build(Reader reader, Properties properties) {
   
    return build(reader, null, properties);
  }

  /**
   * build()方法 的主要实现
   */
  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
   
    try {
   
      // SqlSessionFactory 会创建 XMLConfigBuilder对象 来解析 mybatis-config.xml配置文件
      // XMLConfigBuilder 继承自 BaseBuilder抽象类,顾名思义这一系的类使用了 建造者设计模式
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      // 解析配置文件的内容 到 Configuration对象,根据 Configuration对象
      // 创建 DefaultSqlSessionFactory对象,然后返回
      return build(parser.parse());
    } catch (Exception e) {
   
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
   
      ErrorContext.instance().reset();
      try {
   
        // 关闭配置文件输入流
        reader.close();
      } catch (IOException e) {
   
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

  public SqlSessionFactory build(Configuration config) {
   
    return new DefaultSqlSessionFactory(config);
  }

BaseBuilder 中的核心字段如下:

public abstract class BaseBuilder {
   

  // 保存了 Mybatis 的几乎所以核心配置信息,全局唯一
  protected final Configuration configuration;
  // 在 mybatis-config.xml 中可以通过 <typeAliases>标签 定义别名
  protected final TypeAliasRegistry typeAliasRegistry;
  // 在 mybatis-config.xml 中可以通过 <typeHandlers>标签 添加 自定义TypeHandler
  // TypeHandler 用于完成 JDBC数据类型 与 Java类型 的相互转换,所有的 TypeHandler
  // 都保存在 typeHandlerRegistry 中
  protected final TypeHandlerRegistry typeHandlerRegistry;

  public BaseBuilder(Configuration configuration) {
   
    this.configuration = configuration;
    this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
    this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
  }
}

BaseBuilder 中的 typeAliasRegistry 和 typeHandlerRegistry 字段 均来自于 configuration,通过 BaseBuilder 的构造方法可以看到详细内容。

2 XMLConfigBuilder

XMLConfigBuilder 是 BaseBuilder 的众多子类之一,主要负责解析 mybatis-config.xml 配置文件。它通过调用 parseConfiguration()方法 实现整个解析过程,其中,mybatis-config.xml 配置文件 中的每个节点都被封装成了一个个相应的解析方法,parseConfiguration()方法 只是依次调用了这些解析方法而已。

public class XMLConfigBuilder extends BaseBuilder {
   

  // 标记是否解析过 mybatis-config.xml文件
  private boolean parsed;
  // 用于解析 mybatis-config.xml 的解析器
  private final XPathParser parser;
  // 标识 <environment>配置 的名称,默认读取 <environment>标签 的 default属性
  private String environment;
  // 创建并缓存 Reflector对象
  private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();

  /**
   * 解析的入口,调用了 parseConfiguration() 进行后续的解析
   */
  public Configuration parse() {
   
    // parsed标志位 的处理
    if (parsed) {
   
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    // 在 mybatis-config.xml配置文件 中查找 <configuration>节点,并开始解析
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

  private void parseConfiguration(XNode root) {
   
    try {
   
      // 根据 root.evalNode("properties") 中的值就可以知道具体是解析哪个标签的方法咯
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
   
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

Mybatis 中的标签很多,所以相对应的解析方法也很多,这里挑几个比较重要的标签进行分析。

2.1 解析<typeHandlers>标签

  private void typeHandlerElement(XNode parent) throws Exception {
   
    if (parent != null) {
   
      // 处理 <typeHandlers> 下的所有子标签
      for (XNode child : parent.getChildren()) {
   
        // 处理 <package> 标签
        if ("package".equals(child.getName())) {
   
          // 获取指定的包名
          String typeHandlerPackage = child.getStringAttribute("name");
          // 通过 typeHandlerRegistry 的 register(packageName)方法
          // 扫描指定包中的所有 TypeHandler类,并进行注册
          typeHandlerRegistry.register(typeHandlerPackage);
        } else {
   
          // Java数据类型
          String javaTypeName = child.getStringAttribute("javaType");
          // JDBC数据类型
          String jdbcTypeName = child.getStringAttribute("jdbcType");
          String handlerTypeName = child.getStringAttribute("handler");
          Class<?> javaTypeClass = resolveClass(javaTypeName);
          JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
          Class<?> typeHandlerClass = resolveClass(handlerTypeName);
          // 注册
          if (javaTypeClass != null) {
   
            if (jdbcType == null) {
   
              typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
            } else {
   
              typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
            }
          } else {
   
            typeHandlerRegistry
  • 27
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值