1.pluginElement(root.evalNode("plugins")) 解析plugins节点(注册interceptorChain里记录对应的拦截器)
  private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
//解析interceptor对应的class名
String interceptor = child.getStringAttribute("interceptor");
//解析properties
Properties properties = child.getChildrenAsProperties();
//根据interceptor从resolveClass里拿出class,通过反射生成实例
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
//给interceptorInstance设置properties
interceptorInstance.setProperties(properties);
//注册到interceptorChain里,责任链模式
configuration.addInterceptor(interceptorInstance);
}
}
}
  <plugins>
<plugin interceptor="org.apache.ibatis.builder.ExamplePlugin">
<property name="pluginProperty" value="100"/>
</plugin>
</plugins>
public class InterceptorChain {

  private final List<Interceptor> interceptors = new ArrayList<>();

  public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
} public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
} public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
} }
2.objectFactoryElement,objectWrapperFactoryElement,reflectorFactoryElement 这三个节点的解析都是类似反射实例化操作,就不解释了。
  private void objectFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties properties = context.getChildrenAsProperties();
ObjectFactory factory = (ObjectFactory) resolveClass(type).getDeclaredConstructor().newInstance();
factory.setProperties(properties);
configuration.setObjectFactory(factory);
}
} private void objectWrapperFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).getDeclaredConstructor().newInstance();
configuration.setObjectWrapperFactory(factory);
}
} private void reflectorFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
ReflectorFactory factory = (ReflectorFactory) resolveClass(type).getDeclaredConstructor().newInstance();
configuration.setReflectorFactory(factory);
}
}
3.settingsElement(settings) 设置其它的setting参数。
  private void settingsElement(Properties props) {
//指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。
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));
//设置默认的ExecutorType
configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
//设置默认的Statement执行超时时间
configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
//设置默认获取数量
configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
//设置默认的ResultSet类型
configuration.setDefaultResultSetType(resolveResultSetType(props.getProperty("defaultResultSetType")));
//是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射
configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
//设置允许在嵌套语句中使用分页(RowBounds)
configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
//MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。
// 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。
configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
//当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。
configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
//指定对象的哪个方法触发一次延迟加载
configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
//设置ResultHandler的安全性检查
configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
//设置默认的ScriptingLanguage,用来生成boundsql
configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
//设置默认的defaultEnumTypeHandler
configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
//指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。
configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
// 允许使用方法签名中的名称作为语句参数名称。
configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
//当返回行的所有列都是空时,MyBatis默认返回null。 当开启这个设置时,MyBatis会返回一个空实例。
configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
//设置log前缀
configuration.setLogPrefix(props.getProperty("logPrefix"));
//设置ConfigurationFactory
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
//设置shrinkWhitespacesInSql,删除sql中多余的空白字符
configuration.setShrinkWhitespacesInSql(booleanValueOf(props.getProperty("shrinkWhitespacesInSql"), false));
//设置defaultSqlProviderType,动态sql拼接
configuration.setDefaultSqlProviderType(resolveClass(props.getProperty("defaultSqlProviderType")));
}
  <settings>
<setting name="autoMappingBehavior" value="NONE"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="cacheEnabled" value="false"/>
<setting name="proxyFactory" value="CGLIB"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
<setting name="multipleResultSetsEnabled" value="false"/>
<setting name="useColumnLabel" value="false"/>
<setting name="useGeneratedKeys" value="true"/>
<setting name="defaultExecutorType" value="BATCH"/>
<setting name="defaultStatementTimeout" value="10"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="defaultResultSetType" value="SCROLL_INSENSITIVE"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="safeRowBoundsEnabled" value="true"/>
<setting name="localCacheScope" value="STATEMENT"/>
<setting name="jdbcTypeForNull" value="${jdbcTypeForNull}"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString,xxx"/>
<setting name="safeResultHandlerEnabled" value="false"/>
<setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.defaults.RawLanguageDriver"/>
<setting name="callSettersOnNulls" value="true"/>
<setting name="logPrefix" value="mybatis_"/>
<setting name="logImpl" value="SLF4J"/>
<setting name="vfsImpl" value="org.apache.ibatis.io.JBoss6VFS"/>
<setting name="configurationFactory" value="java.lang.String"/>
<setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
<setting name="shrinkWhitespacesInSql" value="true"/>
<setting name="defaultSqlProviderType" value="org.apache.ibatis.builder.XmlConfigBuilderTest$MySqlProvider"/>
</settings>
4.environmentsElement(root.evalNode("environments")) 解析environments
  private void environmentsElement(XNode context) throws Exception {
if (context != null) {
//environment没设置的话,默认用defalut对应的value
if (environment == null) {
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
//根据environment取对应的配置
if (isSpecifiedEnvironment(id)) {
//实例化TransactionFactory
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//实例化DataSourceFactory
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory).dataSource(dataSource);
//设置environment
configuration.setEnvironment(environmentBuilder.build());
break;
}
}
}
}
  <environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
5.databaseIdProviderElement(root.evalNode("databaseIdProvider"))解析databaseIdProvider节点(databaseId)
  private void databaseIdProviderElement(XNode context) throws Exception {
DatabaseIdProvider databaseIdProvider = null;
if (context != null) {
String type = context.getStringAttribute("type");
// awful patch to keep backward compatibility
if ("VENDOR".equals(type)) {
type = "DB_VENDOR";
}
Properties properties = context.getChildrenAsProperties();
//实例化databaseIdProvider
databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor().newInstance();
databaseIdProvider.setProperties(properties);
}
Environment environment = configuration.getEnvironment();
if (environment != null && databaseIdProvider != null) {
//根据environment中设置的dataSource取得databaseId
String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
//设置databaseId
configuration.setDatabaseId(databaseId);
}
}
  <databaseIdProvider type="DB_VENDOR">
<property name="Apache Derby" value="derby"/>
</databaseIdProvider>
6.typeHandlerElement(root.evalNode("typeHandlers"))解析typeHandlers节点,注册类型转换器(typeHandlerRegistry)
  private void typeHandlerElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
//package配置,老规矩直接取该路径下的所有TypeHandler类型的class注册到typeHandlerRegistry
if ("package".equals(child.getName())) {
String typeHandlerPackage = child.getStringAttribute("name");
typeHandlerRegistry.register(typeHandlerPackage);
} else {
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);
//根据下图xml中配置的三种不同的配置方式,注册到typeHandlerRegistry
if (javaTypeClass != null) {
if (jdbcType == null) {
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
} else {
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
}
} else {
typeHandlerRegistry.register(typeHandlerClass);
}
}
}
}
}
  <typeHandlers>
<typeHandler javaType="String" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/>
<typeHandler javaType="String" jdbcType="VARCHAR" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/>
<typeHandler handler="org.apache.ibatis.builder.CustomLongTypeHandler"/>
<package name="org.apache.ibatis.builder.typehandler"/>
</typeHandlers>
看下只有typeHandlerClass的注册方式,其它两种都是大同小异:
  public void register(Class<?> typeHandlerClass) {
//flag
boolean mappedTypeFound = false;
//取MappedTypes注解
MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
if (mappedTypes != null) {
for (Class<?> javaTypeClass : mappedTypes.value()) {
//根据MappedTypes的value值当作javaTypeClass,走javaTypeClass+typeHandlerClass的注册
register(javaTypeClass, typeHandlerClass);
mappedTypeFound = true;
}
}
//如果没有MappedTypes注解,走只有typeHandlerClass的注册
if (!mappedTypeFound) {
register(getInstance(null, typeHandlerClass));
}
}
  public <T> void register(TypeHandler<T> typeHandler) {
...
// (从3.1.0开始,尝试走自动发现的注册)
if (!mappedTypeFound && typeHandler instanceof TypeReference) {
try {
TypeReference<T> typeReference = (TypeReference<T>) typeHandler;
register(typeReference.getRawType(), typeHandler);
mappedTypeFound = true;
} catch (Throwable t) {
// maybe users define the TypeReference with a different type and are not assignable, so just ignore it
}
}
if (!mappedTypeFound) {
register((Class<T>) null, typeHandler);
}
}
  Type getSuperclassTypeParameter(Class<?> clazz) {
//嵌套查询反射获得带有泛型的父类
Type genericSuperclass = clazz.getGenericSuperclass() ;
if (genericSuperclass instanceof Class) {
// try to climb up the hierarchy until meet something useful
if (TypeReference.class != genericSuperclass) {
return getSuperclassTypeParameter(clazz.getSuperclass());
}
throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "
+ "Remove the extension or add a type parameter to it.");
}
//取出TypeReference<T>中的泛型的第一个参数,例如 BaseTypeHandler<BigDecimal>中的BigDecimal
Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
// TODO remove this when Reflector is fixed to return Types
if (rawType instanceof ParameterizedType) {
rawType = ((ParameterizedType) rawType).getRawType();
}
return rawType;
}
  private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
if (javaType != null) {
Map<JdbcType, TypeHandler<?>> map = typeHandlerMap.get(javaType);
if (map == null || map == NULL_TYPE_HANDLER_MAP) {
map = new HashMap<>();
}
map.put(jdbcType, handler);
typeHandlerMap.put(javaType, map);
}
allTypeHandlersMap.put(handler.getClass(), handler);
}
另外TypeHandlerRegistry在初始化的时候已经内置了一些共通的TypeHandler:
  public TypeHandlerRegistry(Configuration configuration) {
this.unknownTypeHandler = new UnknownTypeHandler(configuration); register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler()); register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler()); register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
...

Mybatis3源码笔记(四)Configuration(续)的更多相关文章

  1. Tomcat8源码笔记(四)Server和Service初始化

    上一章 简单说明下Tomcat各个组件: Server:服务器,Tomcat服务器,一个Tomcat只有一个Server组件; Service:业务层,是Server下最大的子容器,一个Server可 ...

  2. Mybatis3源码笔记(八)小窥MyBatis-plus

    前言 Mybatis-Plus是一个 MyBatis增强工具包,简化 CRUD 操作,在 MyBatis 的基础上只做增强不做改变,为简化开发.提高效率而生,号称无侵入,现在开发中比较常用,包括我自己 ...

  3. Mybatis3源码笔记(六)SqlSession执行过程

    前几篇大致分析了初始化的过程,今天打算走一个SqlSession具体执行过程. @Test void shouldSelectAllAuthors() { try (SqlSession sessio ...

  4. Mybatis3源码笔记(一)环境搭建

    1. 源码下载 地址:https://github.com/mybatis/mybatis-3.git. 国内访问有时确实有点慢,像我就直接先fork.然后从git上同步到国内的gitte上,然后在i ...

  5. Mybatis3源码笔记(三)Configuration

    1. XMLConfigBuilder 上一篇大致介绍了SqlSession的生成.在DefaultSqlSessionFactory的构造函数中就提到了Configuration这个对象.现在我们来 ...

  6. Mybatis3源码笔记(七)Plugin

    1.Mybatis3的插件其实主要是用到了责任链和动态代理两种模式相结合而生成的.下面我们看一个例子,在执行所有update操作时,执行一个小小的测试输出. @Intercepts({@Signatu ...

  7. Mybatis3源码笔记(五)mapperElement

    1.四种解析mapper方式 : package,resource,url,class. <mappers> <mapper resource="org/apache/ib ...

  8. Mybatis3源码笔记(二)SqlSession

    1. 核心层次 2. SqlSession 先从顶层的SqlSession接口开始说起.SqlSession是MyBatis提供的面向用户的API,表示和数据库的会话对象,用于完成对数据库的一系列CR ...

  9. jQuery源码笔记——四

    each()实现 var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context ) ...

随机推荐

  1. 一文学会Dockerfile语法

    接应上篇,续讲前文.今天咱来聊一下Dockerfile的使用 . 虽然可以通过docker commit命令来手动创建镜像,但是通过Dockerfile文件,可以帮助我们自动创建镜像,并且能够自定义创 ...

  2. 手把手教你使用IDEA2020创建SpringBoot项目

    一.New Project 二.如图选择Spring Initalizr,选择jdk版本,然后点击Next(注意:SpringBoot2开始至少使用JDK1.8) 三.如图根据自己需要修改,然后点击N ...

  3. .Net -- NLog日志框架配置与使用

    NLog是适用于各种.NET平台(包括.NET标准)的灵活,免费的日志记录平台,NLog可将日志写入多个目标,比如Database.File.Console.Mail.下面介绍下NLog的基本使用方法 ...

  4. EF获取数据库表名和列名

    EF获取数据库表名和列名 新建 模板 小书匠 /// <summary>  /// 通过当前DBContext上下文获取对应数据库中所有得表  /// </summary>  ...

  5. BurpSuite 一些小技巧

    拦截请求 设置不拦截下面的网站(记得保存项目,不然每次都要添加) .*\.?baidu.com|.*\.?google.com|.*\.?bcebos.com|.*\.?bdstatic.com|.* ...

  6. 在C++中实现aligned_malloc

    malloc的默认行为 大家都知道C++中可以直接调用malloc请求内存被返回分配成功的内存指针,该指针指向的地址就是分配得到的内存的起始地址.比如下面的代码 int main() { void * ...

  7. 我给Apache顶级项目贡献了点源码。

    这是why技术的第 91 篇原创文章 这篇文章其实并没有什么技术性的分享,从我的角度而言,更多是记录和思考. 把我对于源码和之前写的部分文章反哺给我的一些东西,带来的一点点思考分享给大家. 一行源码 ...

  8. 报错NameError: name ‘null’ is not defined的解决方法

    报错NameError: name 'null' is not defined的解决方法 eval()介绍 eval()函数十分强大,官方demo解释为:将字符串str当成有效的表达式来求值并返回计算 ...

  9. WPF 应用 - 拖拽窗体、控件

    1. 拖拽窗体 使用 System.Windows.Window 自带的 DragMove() 方法即可识别窗体拖动. DragMove(); 2. 拖拽控件:复制.移动控件 <Grid> ...

  10. 【vscode】【python】自定义代码自动补全

    引自:https://blog.csdn.net/Kyrielong/article/details/88058884 { "python.jediEnabled": true, ...