【Mybatis 源码】 Mybatis 是如何解析配置文件中的内容 -- settings
创始人
2024-03-17 20:39:30

Mybatis 是如何解析配置文件中的内容 – settings

文章目录

  • Mybatis 是如何解析配置文件中的内容 -- settings
  • 一、解析 settings 节点
    • 1. 使用方式
    • 2. 获取配置文件中的选项
    • 3. 加载 vfs 组件
    • 4. 加载日志配置
      • 【1】获取配置的类
      • 【2】LogFactory 设定自定义的日志类
    • 5. 加载全部的 setting 设置
      • 【1】加载过程
  • 二、参考链接


提示:Mbatis 的加载入口可以看这篇文章:【Mybatis 源码】 Mybatis 是如何解析配置文件中的内容 – properties

一、解析 settings 节点

节点在解析的过程中分为了几块内容:

// 获取配置文件中设置的选项
Properties settings = settingsAsProperties(root.evalNode("settings"));  
// 加载 VFS
loadCustomVfs(settings);  
// 加载日志配置选项
loadCustomLogImpl(settings);
// 给全部配置选项设置默认值或者用户自定义的值
settingsElement(settings);

1. 使用方式

设置项目参考链接:【Mybatis 使用】mybatis-config.xml 配置(properties 和 settings)

因为配置项比较多,而且有些配置项平常基本使用不到,所以这边不详细讲解,只挑选一些典型的作为例子,具体的可以等到用到的时候再配置。

                  

2. 获取配置文件中的选项

private Properties settingsAsProperties(XNode context) {if (context == null) {return new Properties();}// 获取文件中的配置的选项Properties props = context.getChildrenAsProperties();// 判断设置的选项是否是属于已知的选项,如果不是已知选项中的一员,则会抛出异常MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);for (Object key : props.keySet()) {if (!metaConfig.hasSetter(String.valueOf(key))) {hrow new BuilderException("The setting " + key + " is not known.  Make sure you spelled it correctly (case sensitive).");}}return props;
}

3. 加载 vfs 组件

vfs(虚拟化文件系统),平常基本上用不到这个组件,所以只需要了解一下就行。

private void loadCustomVfs(Properties props) throws ClassNotFoundException {  // 获取配置文件中配置的 vfs 自定义类String value = props.getProperty("vfsImpl");  if (value != null) {// 配置文件中定义的 vfs 可以用逗号来分隔,所以按照逗号来获取多个自定义类String[] clazzes = value.split(",");for (String clazz : clazzes) {// 判断clazz是否为空if (!clazz.isEmpty()) {  // 获取类名@SuppressWarnings("unchecked")  Class vfsImpl = (Class)Resources.classForName(clazz);  // 在全局配置中配置 vfs 等待后面使用configuration.setVfsImpl(vfsImpl);  }  }  }  
}

4. 加载日志配置

日志配置会先从预设好的值中获取相对应的类,比如在官方文档中,日志的选项有这么几种 SLF4JLOG4J(3.5.9 起废弃)LOG4J2JDK_LOGGINGCOMMONS_LOGGINGSTDOUT_LOGGINGNO_LOGGING,这些选项都是各个日志类的别名,在实际使用过程中,用户会先从这些别名中挑选自己需要的日志类,然后等待 Mybatis 加载此日志类就可以使用。

比如如果在设置的时候使用了 SLF4J,那在 Mybatis 加载的时候会根据 SLF4J 去找到 Slf4jImpl.class 这个日志来作为整个框架的日志类。

  • Mybatis 加载日志类的过程:
private void loadCustomLogImpl(Properties props) {// 获取和配置名相匹配的日志类Class logImpl = resolveClass(props.getProperty("logImpl"));// 加载获取到的日志类configuration.setLogImpl(logImpl);  
}

【1】获取配置的类

获取配置类的过程其实就是从预设置的各种日志类获取相匹配的类的过程。

  • BaseBuilder#resolveClass():
protected  Class resolveClass(String alias) {if (alias == null) {return null;}try {// 获取别名对应的类return resolveAlias(alias);} catch (Exception e) {throw new BuilderException("Error resolving class. Cause: " + e, e);}
}
  • BaseBuilder#resolveAlias():
protected  Class resolveAlias(String alias) {  return typeAliasRegistry.resolveAlias(alias);  
}
  • TypeAliasRegistry#resolveAlias():
public  Class resolveAlias(String string) {  try {  if (string == null) {  return null;  }  // 转换为小写String key = string.toLowerCase(Locale.ENGLISH);  Class value;// 如果预设的值包含了此值,则会获取此值对应的类if (typeAliases.containsKey(key)) {  value = (Class) typeAliases.get(key);  } else {// 否则会用 Resources 加载对应的类value = (Class) Resources.classForName(string);  }  return value;  } catch (ClassNotFoundException e) {  throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + e, e);  }  
}

在加载过程中预设的值都是在 Configuration 类初始化的过程中进行设置的,下面的代码就是上面文档中那七种日志类预设置的过程。

public Configuration() {// 给各种日志类设置别名,方便用户设置typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);  typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);  typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);  typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);  typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);  typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);  typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);  
}

【2】LogFactory 设定自定义的日志类

设置类的过程其实就是在前面第一步获取日志类成功以后,交给 LogFactory 日志框架进行加载。

public void setLogImpl(Class logImpl) {  if (logImpl != null) {  this.logImpl = logImpl;  LogFactory.useCustomLogging(this.logImpl);  }  
}

5. 加载全部的 setting 设置

等到上面两个自定义的设置全部处理好以后,最后就是来到了加载 标签的最后一步,就是将配置文件中设置的所有的自定义框架设置进行加载,如果在文件中有些框架设置没有单独配置,则会使用默认的值来设置。

比如在最开始的时候,在配置文件中设置了四项需要的框架配置,那在加载时候,会将 value 设置的值填充并加载。

                  

【1】加载过程

在加载过程中可以看到所有框架配置的选项,以及每个选项的默认值。

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.setArgNameBasedConstructorAutoMapping(booleanValueOf(props.getProperty("argNameBasedConstructorAutoMapping"), false));configuration.setDefaultSqlProviderType(resolveClass(props.getProperty("defaultSqlProviderType")));configuration.setNullableOnForEach(booleanValueOf(props.getProperty("nullableOnForEach"), false));
}

二、参考链接

  • 设置(settings)

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...