Mybatis源码 ------ xml配置文件解析

  在不整合spring的情况下,通过mybatis的xml配置文件配置mybatis的各种属性,完成SqlSessionFactory初始化。

public SqlSessionFactory getSqlSessionFactory() throws IOException {
    return new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      //通过XMLConfigBuilder对象 解析 xml配置文件
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
	//父类的configuration属性赋值为new Configuration() , configuration对象很重要 , 里面保存非常多的属性。
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    //configuration的的variables设置为props
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    //parser赋值为parser
    this.parser = parser;
}
public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    //从根标签configuration开始解析
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
}
private void parseConfiguration(XNode root) {
    try {
      //解析properties标签  比如<properties resource="database.properties"/> 引入配置信息 
      //使得可以在xml配置文件中使用${}占位符获取相应的值
      propertiesElement(root.evalNode("properties"));
      //解析settings标签 获取子标签setting的name value属性,封装为Properties对象返回
      //<setting name="safeResultHandlerEnabled" value="true"/> 开启自动驼峰转换
      //<setting name="cacheEnabled" value="true"/> 开启二级缓存功能 (一般不去使用,特别是分布式的环境)
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      //获取vfsImpl属性值,设置到configuration的vfsImpl属性中
      //且再VFS类的USER_IMPLEMENTATIONS容器中放入该vfsImpl对应的class对象
      //一般使用默认的DefaultVFS
      loadCustomVfs(settings);
      //获取到logImpl的属性值,设置到configuration的logImpl属性中
      //且把实例化该属性值对应的类的构造函数,把该日志构造函数设置到LogFactory的logConstructor属性中
      loadCustomLogImpl(settings);
      //解析typeAliases标签
      typeAliasesElement(root.evalNode("typeAliases"));
      //解析plugins标签
      pluginElement(root.evalNode("plugins"));
      //这几个属性一般使用默认的就行,数据库字段映射到实体类用到的类
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      //将setting标签配置的各种属性封装到configuration对应的属性中
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      //解析environments标签
      environmentsElement(root.evalNode("environments"));
      //解析databaseIdProvider标签
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      //解析typeHandlers标签
      typeHandlerElement(root.evalNode("typeHandlers"));
      //解析mappers标签
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

  解析properties标签

private void propertiesElement(XNode context) throws Exception {
    if (context != null) {
      //获取子标签的name value属性,封装为Properties对象
      Properties defaults = context.getChildrenAsProperties();
      //获取resource属性的值
      String resource = context.getStringAttribute("resource");
      //获取url属性的值
      String url = context.getStringAttribute("url");
      if (resource != null && url != null) {
        throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
      }
      //读取配置文件的值,封装为Properties对象 加入到defaults 中。
      if (resource != null) {
        defaults.putAll(Resources.getResourceAsProperties(resource));
      } else if (url != null) {
        defaults.putAll(Resources.getUrlAsProperties(url));
      }
      //从configuration中获取variables
      Properties vars = configuration.getVariables();
      if (vars != null) {
      	//如果有值,添加到defaults中
        defaults.putAll(vars);
      }
      //将parser的variables设置为defaults
      parser.setVariables(defaults);
      //将configuration的variables设置为defaults
      configuration.setVariables(defaults);
    }
  }

  解析name属性为logImpl的setting标签

private void loadCustomLogImpl(Properties props) {
	//获取logImpl属性值,并且包装为class对象,这里的值可以不是一个类的完整限定名,而是一个别名
    Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));
 	//将logImpl设置到configuration的logImpl属性中
    configuration.setLogImpl(logImpl);
}
protected <T> Class<? extends T> resolveClass(String alias) {
    if (alias == null) {
      return null;
    }
    try {
  	   //看这里
      return resolveAlias(alias);
    } catch (Exception e) {
      throw new BuilderException("Error resolving class. Cause: " + e, e);
    }
}
protected <T> Class<? extends T> resolveAlias(String alias) {	
	//看这里
    return typeAliasRegistry.resolveAlias(alias);
}
public <T> Class<T> resolveAlias(String string) {
    try {
      if (string == null) {
        return null;
      }
      // issue #748
      //先转为小写
      String key = string.toLowerCase(Locale.ENGLISH);
      Class<T> value;
      //Configuration对象实例化的时候(构造函数的具体逻辑),向typeAliases这个map中,放入了许多内置的值。
      //比如typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);(注册的key会先转为小写)
      if (typeAliases.containsKey(key)) {
        //如果别名集合中含有该值,从取到对应的类
        value = (Class<T>) typeAliases.get(key);
      } else {
		//没有,则直接调用classForName获取到class对象
        value = (Class<T>) Resources.classForName(string);
      }
      return value;
    } catch (ClassNotFoundException e) {
      throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + e, e);
    }
}
public void setLogImpl(Class<? extends Log> logImpl) {
    if (logImpl != null) {
      //将logImpl设置到configuration的logImpl属性中
      this.logImpl = logImpl;
      LogFactory.useCustomLogging(this.logImpl);
    }
}
public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
    setImplementation(clazz);
}
private static void setImplementation(Class<? extends Log> implClass) {
    try {
      //获取该日志类的构造函数
      Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
      Log log = candidate.newInstance(LogFactory.class.getName());
      if (log.isDebugEnabled()) {
        log.debug("Logging initialized using '" + implClass + "' adapter.");
      }
      //把该日志构造函数设置到LogFactory的logConstructor属性中
      logConstructor = candidate;
    } catch (Throwable t) {
      throw new LogException("Error setting Log implementation.  Cause: " + t, t);
}

  typeAliases标签解析

private void typeAliasesElement(XNode parent) {
    if (parent != null) {
      //获取子标签
      for (XNode child : parent.getChildren()) {
      	//获取package标签
        if ("package".equals(child.getName())) {
          //获取name属性,也就是包名
          String typeAliasPackage = child.getStringAttribute("name");
          //看这里
          configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
        } else {
          //配置的不是package,直接配置的别名和类的方式
          String alias = child.getStringAttribute("alias");
          String type = child.getStringAttribute("type");
          try {
            //获取class对象
            Class<?> clazz = Resources.classForName(type);
            //别名没有配置
            if (alias == null) {
              //找类上的Alias注解,注解也没有,直接使用类的simpleName作为别名
              typeAliasRegistry.registerAlias(clazz);
            } else {
              //注册别名和类的对应关系到typeAliases中
              typeAliasRegistry.registerAlias(alias, clazz);
            }
          } catch (ClassNotFoundException e) {
            throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
          }
        }
      }
    }
}
public void registerAliases(String packageName) {
	//Object类型
    registerAliases(packageName, Object.class);
}
public void registerAliases(String packageName, Class<?> superType) {
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
    //找到该包下所有的class文件
    //使用classLoader.loadClass获取对应class,如果是superType类型
    //收集到resolverUtil的matches集合中
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    //获得resolverUtil的matches集合的类
    Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
    for (Class<?> type : typeSet) {
      // Ignore inner classes and interfaces (including package-info.java)
      // Skip also inner classes. See issue #6
      //如果类的SimpleName不为空,不是接口 , 不是内部类
      if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
        registerAlias(type);
      }
    }
}
public ResolverUtil<T> find(Test test, String packageName) {
	//将配置的包名中的.替换为/
    String path = getPackagePath(packageName);

    try {
      //VFS.getInstance(),静态内部类的方式实现的单例模式
      //VFS主要用来读取当前应用程序的资源文件,默认有JBoss6VFS和DefaultVFS,loadCustomVfs方法会添加其他VFS的实现类
      //找到所有的资源文件
      List<String> children = VFS.getInstance().list(path);
      for (String child : children) {
        //如果以.class结尾
        if (child.endsWith(".class")) {
          addIfMatching(test, child);
        }
      }
    } catch (IOException ioe) {
      log.error("Could not read package: " + packageName, ioe);
    }

    return this;
}
protected void addIfMatching(Test test, String fqn) {
    try {
      //转换为类的完整限定名
      String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
      ClassLoader loader = getClassLoader();
      if (log.isDebugEnabled()) {
        log.debug("Checking to see if class " + externalName + " matches criteria [" + test + "]");
      }
	
	  //使用类加载器加载该类
      Class<?> type = loader.loadClass(externalName);
      //使用的test为new ResolverUtil.IsA
      //对应的matches为
      //public boolean matches(Class<?> type) {
      //  return type != null && parent.isAssignableFrom(type);
      //}
      if (test.matches(type)) {
        //添加到matches容器中
        matches.add((Class<T>) type);
      }
    } catch (Throwable t) {
    //加载不到,忽略
      log.warn("Could not examine class '" + fqn + "'" + " due to a " +
          t.getClass().getName() + " with message: " + t.getMessage());
    }
}
public void registerAlias(Class<?> type) {
	//alias为类的simpleName
    String alias = type.getSimpleName();
    //获取类的Alias注解的值
    Alias aliasAnnotation = type.getAnnotation(Alias.class);
    //注解不为空alias为注解配置的值
    if (aliasAnnotation != null) {
      alias = aliasAnnotation.value();
    }
    //注册别名和类的对应关系到typeAliases中
    registerAlias(alias, type);
}
public void registerAlias(String alias, Class<?> value) {
    if (alias == null) {
      throw new TypeException("The parameter alias cannot be null");
    }
    // issue #748
    //将别名传为小写
    String key = alias.toLowerCase(Locale.ENGLISH);
    if (typeAliases.containsKey(key) && typeAliases.get(key) != null && !typeAliases.get(key).equals(value)) {
      throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + typeAliases.get(key).getName() + "'.");
    }
    //放入typeAliases(map)中
    typeAliases.put(key, value);
}

  解析plugins标签

private void pluginElement(XNode parent) throws Exception {
    if (parent != null) {	
      //获取子标签
      for (XNode child : parent.getChildren()) {
      	//获取interceptor属性值(类名或者别名都可以)
        String interceptor = child.getStringAttribute("interceptor");
        //获取child 的 子标签的name和value值
        Properties properties = child.getChildrenAsProperties();
        //实例化拦截器类
        Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
        //调用拦截器的setProperties 入参为 properties
        interceptorInstance.setProperties(properties);
        //将拦截器添加到configuration的interceptorChain的interceptors集合中
        configuration.addInterceptor(interceptorInstance);
      }
    }
  }

  解析environments标签

private void environmentsElement(XNode context) throws Exception {
    if (context != null) {
      if (environment == null) {
      	//获取default属性赋值给environment属性
        environment = context.getStringAttribute("default");
      }
      //循环所有的子标签environment
      for (XNode child : context.getChildren()) {
      	//获取子标签environment的id属性
        String id = child.getStringAttribute("id");
        //如果id和environment相等
        if (isSpecifiedEnvironment(id)) {
          //解析environment标签的transactionManager标签
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
           //解析environment标签的dataSource标签
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
          DataSource dataSource = dsFactory.getDataSource();
          //设置txFactory,dataSource和id到environmentBuilder中
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);
          //将environmentBuilder.build()赋值给configuration的environment属性
          configuration.setEnvironment(environmentBuilder.build());
        }
      }
    }
}
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
    if (context != null) {
      //获取type属性,事务管理器的别名或者类名
      String type = context.getStringAttribute("type");
      //获取子标签的name和value属性封装为Properties 
      Properties props = context.getChildrenAsProperties();
      //实例化事务管理器
      TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
      //设置props的值到TransactionFactory 中
      factory.setProperties(props);
      return factory;
    }
    throw new BuilderException("Environment declaration requires a TransactionFactory.");
}  
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
    if (context != null) {
      //获取type属性,数据源工厂的别名或者类名
      String type = context.getStringAttribute("type");
      //获取子标签的name和value属性封装为Properties 
      Properties props = context.getChildrenAsProperties();
      //实例化数据源工厂
      DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
      //设置props的值到DataSourceFactory 中
      factory.setProperties(props);
      return factory;
    }
    throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}

  解析databaseIdProvider标签

private void databaseIdProviderElement(XNode context) throws Exception {
	//<databaseIdProvider type="DB_VENDOR">
    //    <property name="Oracle" value="oracle"/>
    //    <property name="MySQL" value="mysql"/>
    //</databaseIdProvider>
    //oracle mysql这种值用于配置到mapper.xml中的databaseId属性中.
    
    DatabaseIdProvider databaseIdProvider = null;
    if (context != null) {
      //获取	type属性值
      String type = context.getStringAttribute("type");
      // awful patch to keep backward compatibility
      //如果配置的是VENDOR,则转为DB_VENDOR,都会用VendorDatabaseIdProvider类
      //typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
      if ("VENDOR".equals(type)) {
        type = "DB_VENDOR";
      }
      //获取子标签的name和value值封装为properties 
      Properties properties = context.getChildrenAsProperties();
      //实例化DatabaseIdProvider类型
      databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
      //设置properties属性值到databaseIdProvider中
      databaseIdProvider.setProperties(properties);
    }
    //获取configuration的environment属性
    Environment environment = configuration.getEnvironment();
    if (environment != null && databaseIdProvider != null) {
      //获取当前数据源对象对应property中的value值
      String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
      //设置value值到configuration的databaseId中
      configuration.setDatabaseId(databaseId);
    }
}
public String getDatabaseId(DataSource dataSource) {
    if (dataSource == null) {
      throw new NullPointerException("dataSource cannot be null");
    }
    try {
  	   //看这里
      return getDatabaseName(dataSource);
    } catch (Exception e) {
      LogHolder.log.error("Could not get a databaseId from dataSource", e);
    }
    return null;
}
private String getDatabaseName(DataSource dataSource) throws SQLException {
	//获取databaseProductName
    String productName = getDatabaseProductName(dataSource);
    if (this.properties != null) {
      //循环配置的所有的properties值
      for (Map.Entry<Object, Object> property : properties.entrySet()) {
      	//如果productName包含property的key,则返回property的value
        if (productName.contains((String) property.getKey())) {
          return (String) property.getValue();
        }
      }
      // no match, return null
      return null;
    }
    return productName;
}
private String getDatabaseProductName(DataSource dataSource) throws SQLException {
    Connection con = null;
    try {
      //使用数据源对象获取连接对象
      con = dataSource.getConnection();
      DatabaseMetaData metaData = con.getMetaData();
      //获取连接对象的DatabaseProductName , 比如 Oracle  MySQL 等
      return metaData.getDatabaseProductName();
    } finally {
      if (con != null) {
        try {
          con.close();
        } catch (SQLException e) {
          // ignored
        }
      }
    }
}

  解析typeHandlers标签

private void typeHandlerElement(XNode parent) throws Exception {
        if (parent != null) {
        	//获取子标签typeHandler或package
            for (XNode child : parent.getChildren()) {
            	//获取package标签
                if ("package".equals(child.getName())) {
                	//获取package标签的name属性1
                    String typeHandlerPackage = child.getStringAttribute("name");
                    //扫描包,并且注册typeHandle
                    typeHandlerRegistry.register(typeHandlerPackage);
                } else {
                	//处理子标签typeHandler
                    String javaTypeName = child.getStringAttribute("javaType");
                    String jdbcTypeName = child.getStringAttribute("jdbcType");
                    String handlerTypeName = child.getStringAttribute("handler");
                    //可以配置别名,使用resolveClass获取到具体的类
                    Class<?> javaTypeClass = resolveClass(javaTypeName);
                    JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
                    Class<?> typeHandlerClass = resolveClass(handlerTypeName);
                    //注册javaType和Map<JdbcType, TypeHandler<?>> map(jdbcType和TypeHandler的映射关系)的映射关系
                    if (javaTypeClass != null) {
                        if (jdbcType == null) {
                            typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
                        } else {
                            typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
                        }
                    } else {
                        typeHandlerRegistry.register(typeHandlerClass);
                    }
                }
            }
        }
}
public void register(String packageName) {
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
    //扫描获取包路径下的所有TypeHandler类型的class
    resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
    //获取扫描到的所有的TypeHandler类
    Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
    for (Class<?> type : handlerSet) {
      //Ignore inner classes and interfaces (including package-info.java) and abstract classes
      if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
      	//注册
        register(type);
      }
    }
}
public void register(Class<?> typeHandlerClass) {
    boolean mappedTypeFound = false;
    //获取MappedTypes注解
    MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
    if (mappedTypes != null) {
      //循环MappedTypes注解的值,也就是对应的可以处理的java类型
      for (Class<?> javaTypeClass : mappedTypes.value()) {
        //注册
        register(javaTypeClass, typeHandlerClass);
        mappedTypeFound = true;
      }
    }
    if (!mappedTypeFound) {
      //注解没有值的一样可以注册
      register(getInstance(null, typeHandlerClass));
    }
}
private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {
    //获取MappedJdbcTypes注解
    MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
    if (mappedJdbcTypes != null) {
       //循环MappedJdbcTypes注解的值,也就是对应的可以处理的jdbc类型
      for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
        //注册
        register(javaType, handledJdbcType, typeHandler);
      }
      if (mappedJdbcTypes.includeNullJdbcType()) {
         //注册
        register(javaType, null, typeHandler);
      }
    } else {
       //注册
      register(javaType, null, typeHandler);
    }
}
private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
    if (javaType != null) {
      //使用javaType获取到map
      Map<JdbcType, TypeHandler<?>> map = typeHandlerMap.get(javaType);
      if (map == null || map == NULL_TYPE_HANDLER_MAP) {
        map = new HashMap<>();
        //注册javaType和Map<JdbcType, TypeHandler<?>> map的映射关系
        typeHandlerMap.put(javaType, map);
      }
      //注册jdbcType和typeHndler的映射关系
      map.put(jdbcType, handler);
    }
    //建立TypeHandler的class和TypeHandler的映射关系
    allTypeHandlersMap.put(handler.getClass(), handler);
}

  解析mappers标签

private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      //获取子标签package或者mapper
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          //获取package标签的name属性
          String mapperPackage = child.getStringAttribute("name");
          //扫描包下的xml文件,解析加入到configuration中
          //解析mapper的xml的代码和注解里面的指定的sql的代码较为繁琐这里就不详细展开了
          //主要需要了解到:
          //解析的resultMap标签的内容会加入configuration的resultMaps(Map)中,key为namespace加resultMap标签的id属性
          //解析的sql内容最终包装为MappedStatement,加入到configuration的mappedStatements(map)中,key为namespace加自己标签的id属性
          //将mapper的接口类型和生成的代理工厂类(MapperProxyFactory)注册到Configuration的mapperRegistry的knownMappers属性中(这个后续再详细说)
          //knownMappers.put(type, new MapperProxyFactory<>(type));
          configuration.addMappers(mapperPackage);
        } else {
          //处理mapper标签的属性
          //读取到配置的xml文件
          //解析加入到configuration中
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
          if (resource != null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url != null && mapperClass == null) {
            ErrorContext.instance().resource(url);
            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.");
          }
        }
      }
    }
}

public void parseStatementNode() {
	//省略部分源码
	
	//解析的sql内容包装为SqlSource 
	//一般有动态标签的则为DynamicSqlSource
	//DynamicSqlSource含有configuration和rootSqlNode(解析出的sql内容,包装为了MixedSqlNode,里面持有其他的sqlNode节点,树状结构嵌套各个sqlNode(标签中包含sql或者换行空格或者其他标签))
    SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
    StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    
    //省略部分源码
	
	//解析的sql包裝為MappedStatement,然后加入到configuration中
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered,
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}

  到此解析mybatis的xml配置文件的主要流程就结束了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值