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());
...