mybatis 初始化过程

mybatis 初始化过程

gitee mybatis 3.5.8版本 仓库地址
https://gitee.com/geng_zhao_kai/mybatis-3/tree/master

调用时序图

image-20210709195139068

mybatis首先是加载 mybatis-config.xml 文件

image-20210708092947311

读取mybatis-config.xml

Reader reader = Resources.getResourceAsReader("org/apache/ibatis/autoconstructor/mybatis-config.xml")

根据mybatis-config.xml, 创建SqlSessionFactory

sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

通过调用 SqlSessionFactoryBuilder 的 build方法,把读取的 mybatis-config.xml 文件带入

image-20210708093358659

在 SqlSessionFactoryBuilder 中通过 build 方法的重载,调用真正的 build 方法

image-20210708093432016

创建 Configuration 对象,Configuration 是 mybatis 中的全局配置

XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);

在 XMLConfigBuilder 中,又是通过重载的方式, 使用 this 调用了构造

image-20210708093731502

真正的创建 Configuration 对象

image-20210708093834362

  private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    // 创建 Configuration 对象, 并在父类 BaseBuilder 中赋值
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }

然后返回到 SqlSessionFacotryBuilder ,查看返回的 XMLConfiguration 对象调用的 parse()

image-20210708094449702

判断是否加载过 mybatis-config.xml 的配置,然后解析 mybatis-config.xml 中 中的属性

image-20210708094638371

mybatis-config.xml 中有 数据源,mapper信息, 插件,以及别名,自定义类型,配置 等等

image-20210708094907132

private void parseConfiguration(XNode root) {
    try {
      // 解析 *.properties 的文件,添加到 config
      propertiesElement(root.evalNode("properties"));
      // 解析 setting 表中的数据,并进行配置
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      // 解析 settings 中的 vfsImpl 标签
      // vfs 是一个虚拟文件系统
      loadCustomVfs(settings);
      // 解析 logImpl 可指定对应的日志实现
      loadCustomLogImpl(settings);
      // 解析 别名设置
      // <typeAlias type="com.demo.entity.User" alias="user"/>
      typeAliasesElement(root.evalNode("typeAliases"));
      // 解析 插件标签
      pluginElement(root.evalNode("plugins"));
      // 解析 对象工厂
      // <objectFactory type="com.demo.config.ExampleObjectFactory">
      // 通过获取标签的 type 获取 class 包路径,然后通过反射创建对象,
      // 并放到 configuration中
      objectFactoryElement(root.evalNode("objectFactory"));
      // 解析 对象包装器工厂
      // 同理根据包路径反射创建对象,并放到 configuration
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      // 解析 自定义反射工厂
      // 也是根据获取包路径,然后反射创建对象,放到 configuration
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      // 把 setting 中的属性赋值到 configuration中
      settingsElement(settings);
      // 解析配置文件中的数据源,并设置到 Configuration 的 Environment 中
      environmentsElement(root.evalNode("environments"));
      // 多数据库配置类
      // 比如同一个服务中同时使用 mysql oracle
      // 在 xml 上添加 databaseId 即可使用指定的数据方言
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      // 解析自定义的数据类型
      typeHandlerElement(root.evalNode("typeHandlers"));
      // 解析 mapper.xml
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
// 解析 typeAliases 标签
private void typeAliasesElement(XNode parent) {
  if (parent != null) {
    for (XNode child : parent.getChildren()) {
      if ("package".equals(child.getName())) {
        String typeAliasPackage = child.getStringAttribute("name");
        configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
      } else {
        // 获取别名
        String alias = child.getStringAttribute("alias");
        // 获取文件路径
        String type = child.getStringAttribute("type");
        try {
          // 反射创建 class
          Class<?> clazz = Resources.classForName(type);
          // 注册到 typeAliasRegistry 中
          if (alias == null) {
            typeAliasRegistry.registerAlias(clazz);
          } else {
            typeAliasRegistry.registerAlias(alias, clazz);
          }
        } catch (ClassNotFoundException e) {
          throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
        }
      }
    }
  }
}
// TypeAliasRegistry 通过一个 Map<String, Class<?>> 进行存储 alias
// 构造方法中加载了常用的数据类型
public TypeAliasRegistry() {
    registerAlias("string", String.class);

    registerAlias("byte", Byte.class);
    registerAlias("long", Long.class);
    registerAlias("byte[]", Byte[].class);
    registerAlias("long[]", Long[].class);
    registerAlias("short[]", Short[].class);
    registerAlias("int[]", Integer[].class);
    
    registerAlias("ResultSet", ResultSet.class);
    ...
  }

// 解析插件
// <plugin interceptor="com.demo.pligins.ExamplePlugin"></plugin>
private void pluginElement(XNode parent) throws Exception {
  if (parent != null) {
    // 获取 plugins 集合
    for (XNode child : parent.getChildren()) {
      // 获取 plugin 标签中的 interceptor
      // class 的包路径
      String interceptor = child.getStringAttribute("interceptor");
      Properties properties = child.getChildrenAsProperties();
      // 通过反射创建插件
      Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
      interceptorInstance.setProperties(properties);
      // 添加到全局配置(Configuration)中
      configuration.addInterceptor(interceptorInstance);
    }
  }
}

// 插件处理类
public class InterceptorChain {

  // 把所有的插件全部放到 list 中
  private final List<Interceptor> interceptors = new ArrayList<>();

  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      // 根据插件生成对应的代理类
      // Interceptor 接口中实现
      target = interceptor.plugin(target);
    }
    return target;
  }
  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }
  public List<Interceptor> getInterceptors() {
    return Collections.unmodifiableList(interceptors);
  }
}

// 插件统一实现类
public interface Interceptor {

  Object intercept(Invocation invocation) throws Throwable;

  default Object plugin(Object target) {
    // 生成代理类的方法
    return Plugin.wrap(target, this);
  }

  default void setProperties(Properties properties) {
    // NOP
  }
}

// 插件处理类
public class Plugin implements InvocationHandler {
  public static Object wrap(Object target, Interceptor interceptor) {
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
      // 通过 jdk 动态代理生成 代理类
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }
}
// mybatis-config.xml 中 settings 标签中设置的属性, 如果属性不存在就是用默认值
private void settingsElement(Properties props) {
  configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
  configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
  configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
  configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
  configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
  configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
  configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
  configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
  configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
  configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
  configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
  configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
  configuration.setDefaultResultSetType(resolveResultSetType(props.getProperty("defaultResultSetType")));
  configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
  configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
  configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
  configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
  configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
  configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
  configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
  configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
  configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
  configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
  configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
  configuration.setLogPrefix(props.getProperty("logPrefix"));
  configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
  configuration.setShrinkWhitespacesInSql(booleanValueOf(props.getProperty("shrinkWhitespacesInSql"), false));
  configuration.setDefaultSqlProviderType(resolveClass(props.getProperty("defaultSqlProviderType")));
}
// 解析数据源信息赋值到 configuration 的 environment 中
private void environmentsElement(XNode context) throws Exception {
  if (context != null) {
    if (environment == null) {
      environment = context.getStringAttribute("default");
    }
    for (XNode child : context.getChildren()) {
      // 数据源id
      String id = child.getStringAttribute("id");
      if (isSpecifiedEnvironment(id)) {
        // 事务管理器 一个 JDBC,一个MANAGED
        // JDBC 是直接使用 jdbc 中的 commit 和 rollback
        // MANAGED 让容器实现事务,mybatis 不会进行实现
        TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
        // 数据源信息
        DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
        DataSource dataSource = dsFactory.getDataSource();
        Environment.Builder environmentBuilder = new Environment.Builder(id)
            .transactionFactory(txFactory)
            .dataSource(dataSource);
        configuration.setEnvironment(environmentBuilder.build());
        break;
      }
    }
  }
}

// 数据库配置类
public final class Environment {
  private final String id;
  private final TransactionFactory transactionFactory;
  private final DataSource dataSource;
}
// 解析自定义数据类型
private void typeHandlerElement(XNode parent) {
  if (parent != null) {
    for (XNode child : parent.getChildren()) {
      // 如果是使用 package 那么将包下的所有 class 都注册到 configuration 的 typeHandlerRegistry 中
      if ("package".equals(child.getName())) {
        String typeHandlerPackage = child.getStringAttribute("name");
        // 调用注册方法
        typeHandlerRegistry.register(typeHandlerPackage);
      } else {
        // 解析判断是什么类型,最后注册到 configuration 的 typeHandlerRegistry 中
        String javaTypeName = child.getStringAttribute("javaType");
        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.register(typeHandlerClass);
        }
      }
    }
  }
}
// 解析 *mapper.xml 文件
private void mapperElement(XNode parent) throws Exception {
  if (parent != null) {
    for (XNode child : parent.getChildren()) {
      // 如果传入一个包路径, 根据包路径解析包路径下的所有xml
      // 并将所有反射创建出来的mapper保存在 configuration 的 mapperRegistry 中
      if ("package".equals(child.getName())) {
        String mapperPackage = child.getStringAttribute("name");
        configuration.addMappers(mapperPackage);
      } else {
        String resource = child.getStringAttribute("resource");
        String url = child.getStringAttribute("url");
        String mapperClass = child.getStringAttribute("class");
        if (resource != null && url == null && mapperClass == null) {
          // 通过 resource 解析
          ErrorContext.instance().resource(resource);
          // 根据 xml 路径(com/demo/resource/*mapper.xml)读取 xml
          try(InputStream inputStream = Resources.getResourceAsStream(resource)) {
            // 根据 xml 创建 mapper对象
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            // 解析 mapper.xml 中的标签
            mapperParser.parse();
          }
        } else if (resource == null && url != null && mapperClass == null) {
          // 通过 url 解析, 跟 resource 方式相同
          ErrorContext.instance().resource(url);
          try(InputStream inputStream = Resources.getUrlAsStream(url)){
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          }
        } else if (resource == null && url == null && mapperClass != null) {
          Class<?> mapperInterface = Resources.classForName(mapperClass);
          configuration.addMapper(mapperInterface);
        } else {
          throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
        }
      }
    }
  }
}

// 存放解析出来的 xml 文件
// 通过 class 对应 xml 解析后的代理对象的方式存储 xml信息
public class MapperRegistry {
  private final Configuration config;
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
}

// 解析 mapper.xml 中的标签
public void parse() {
    // 判断当前 mapper.xml 是否已经加载过
    if (!configuration.isResourceLoaded(resource)) {
      // 解析 mapper.xml 中的标签
      configurationElement(parser.evalNode("/mapper"));
      // 将 mapper.xml 的包路径存在 configuration 中的 loadResouece 中
      // loadResource 是一个 Set
      configuration.addLoadedResource(resource);
      // 绑定类型到 nameSpace上
      bindMapperForNamespace();
    }

    parsePendingResultMaps();
    parsePendingCacheRefs();
    parsePendingStatements();
}

// 解析 mapper.xml 下的标签
private void configurationElement(XNode context) {
    try {
      // 获取 xml 中的 nameSpace
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.isEmpty()) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      // 将 nameSpace 放到 MapperBuilderAssistant 对象中
      builderAssistant.setCurrentNamespace(namespace);
      // 解析引用缓存
      cacheRefElement(context.evalNode("cache-ref"));
      // 解析缓存
      cacheElement(context.evalNode("cache"));
      // 解析 parameterMap 标签
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      // 解析 resultMap 标签
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      // 解析 sql 标签
      sqlElement(context.evalNodes("/mapper/sql"));
 	  // 解析 select insert update delete 标签
     buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
    }
}

  // 解析 insert select update delete 标签
  private void buildStatementFromContext(List<XNode> list) {
    // 判断是否使用了多数据库
    if (configuration.getDatabaseId() != null) {
      // 如果使用多数据库,将指定数据库id(oracle | mysql)
      buildStatementFromContext(list, configuration.getDatabaseId());
    }
    // 单方言解析 sql
    buildStatementFromContext(list, null);
  }

// 处理 sql 语句标签
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
    // 循环所有的sql标签
    for (XNode context : list) {
      // 构建 sql Statement 对象
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
      try {
        // 解析 sql
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        // 存放解析错误的 xml
        configuration.addIncompleteStatement(statementParser);
      }
    }
  }

// 解析所有 sql 中的属性
public void parseStatementNode() {
    String id = context.getStringAttribute("id");
    String databaseId = context.getStringAttribute("databaseId");

    if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
      return;
    }

    String nodeName = context.getNode().getNodeName();
    SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
    boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
    boolean useCache = context.getBooleanAttribute("useCache", isSelect);
    boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);

    // Include Fragments before parsing
    XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
    includeParser.applyIncludes(context.getNode());

    String parameterType = context.getStringAttribute("parameterType");
    Class<?> parameterTypeClass = resolveClass(parameterType);

    String lang = context.getStringAttribute("lang");
    LanguageDriver langDriver = getLanguageDriver(lang);

    // Parse selectKey after includes and remove them.
    processSelectKeyNodes(id, parameterTypeClass, langDriver);

    // Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
    KeyGenerator keyGenerator;
    String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
    keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
    if (configuration.hasKeyGenerator(keyStatementId)) {
      keyGenerator = configuration.getKeyGenerator(keyStatementId);
    } else {
      keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
          configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
          ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
    }

    SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
    StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    Integer fetchSize = context.getIntAttribute("fetchSize");
    Integer timeout = context.getIntAttribute("timeout");
    String parameterMap = context.getStringAttribute("parameterMap");
    String resultType = context.getStringAttribute("resultType");
    Class<?> resultTypeClass = resolveClass(resultType);
    String resultMap = context.getStringAttribute("resultMap");
    String resultSetType = context.getStringAttribute("resultSetType");
    ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
    if (resultSetTypeEnum == null) {
      resultSetTypeEnum = configuration.getDefaultResultSetType();
    }
    String keyProperty = context.getStringAttribute("keyProperty");
    String keyColumn = context.getStringAttribute("keyColumn");
    String resultSets = context.getStringAttribute("resultSets");

    // 存储解析后的sql
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered,
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
  }

// 将解析后的sql对象 MappedStatement 对象 存入 configuration
public MappedStatement addMappedStatement(
      String id,
      SqlSource sqlSource,
      StatementType statementType,
      SqlCommandType sqlCommandType,
      Integer fetchSize,
      Integer timeout,
      String parameterMap,
      Class<?> parameterType,
      String resultMap,
      Class<?> resultType,
      ResultSetType resultSetType,
      boolean flushCache,
      boolean useCache,
      boolean resultOrdered,
      KeyGenerator keyGenerator,
      String keyProperty,
      String keyColumn,
      String databaseId,
      LanguageDriver lang,
      String resultSets) {

    if (unresolvedCacheRef) {
      throw new IncompleteElementException("Cache-ref not yet resolved");
    }

    id = applyCurrentNamespace(id, false);
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;

    MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
        .resource(resource)
        .fetchSize(fetchSize)
        .timeout(timeout)
        .statementType(statementType)
        .keyGenerator(keyGenerator)
        .keyProperty(keyProperty)
        .keyColumn(keyColumn)
        .databaseId(databaseId)
        .lang(lang)
        .resultOrdered(resultOrdered)
        .resultSets(resultSets)
        .resultMaps(getStatementResultMaps(resultMap, resultType, id))
        .resultSetType(resultSetType)
        .flushCacheRequired(valueOrDefault(flushCache, !isSelect))
        .useCache(valueOrDefault(useCache, isSelect))
        .cache(currentCache);

    ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
    if (statementParameterMap != null) {
      statementBuilder.parameterMap(statementParameterMap);
    }

    MappedStatement statement = statementBuilder.build();
    configuration.addMappedStatement(statement);
    // 在回到 parae() 中
    return statement;
  }

处理完 mybatis-config.xml 中的标签后返回 configuration

image-20210709190808456

最后 build(configuration)

image-20210709190935383

创建全局的 DefaultSqlSessionFactory

image-20210709191732163

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值