Mybatis3源码笔记(四)Configuration(续)
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(续)的更多相关文章
- Tomcat8源码笔记(四)Server和Service初始化
上一章 简单说明下Tomcat各个组件: Server:服务器,Tomcat服务器,一个Tomcat只有一个Server组件; Service:业务层,是Server下最大的子容器,一个Server可 ...
- Mybatis3源码笔记(八)小窥MyBatis-plus
前言 Mybatis-Plus是一个 MyBatis增强工具包,简化 CRUD 操作,在 MyBatis 的基础上只做增强不做改变,为简化开发.提高效率而生,号称无侵入,现在开发中比较常用,包括我自己 ...
- Mybatis3源码笔记(六)SqlSession执行过程
前几篇大致分析了初始化的过程,今天打算走一个SqlSession具体执行过程. @Test void shouldSelectAllAuthors() { try (SqlSession sessio ...
- Mybatis3源码笔记(一)环境搭建
1. 源码下载 地址:https://github.com/mybatis/mybatis-3.git. 国内访问有时确实有点慢,像我就直接先fork.然后从git上同步到国内的gitte上,然后在i ...
- Mybatis3源码笔记(三)Configuration
1. XMLConfigBuilder 上一篇大致介绍了SqlSession的生成.在DefaultSqlSessionFactory的构造函数中就提到了Configuration这个对象.现在我们来 ...
- Mybatis3源码笔记(七)Plugin
1.Mybatis3的插件其实主要是用到了责任链和动态代理两种模式相结合而生成的.下面我们看一个例子,在执行所有update操作时,执行一个小小的测试输出. @Intercepts({@Signatu ...
- Mybatis3源码笔记(五)mapperElement
1.四种解析mapper方式 : package,resource,url,class. <mappers> <mapper resource="org/apache/ib ...
- Mybatis3源码笔记(二)SqlSession
1. 核心层次 2. SqlSession 先从顶层的SqlSession接口开始说起.SqlSession是MyBatis提供的面向用户的API,表示和数据库的会话对象,用于完成对数据库的一系列CR ...
- jQuery源码笔记——四
each()实现 var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context ) ...
随机推荐
- 开源OA办公系统的“应用市场”,能够为协同办公开拓什么样的“前路”?
在我们的日常生活中,应用市场这个词,总是与智能手机划上等号,不管使用的是iPhone还是安卓,总会接触到手机上的APP应用市场,我们可以在应用市场中,选择自己所需要的APP应用软件,下载使用后,可以让 ...
- 死磕Spring之IoC篇 - 解析自定义标签(XML 文件)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- QT实现输入框与下拉框提示并可模糊匹配
功能:支持下拉框选择.手动输入更改和模糊匹配 组件:QLineEdit.QComboBox.QCompleter.QStringListModel 一.组件介绍 1.1 QLineEdit QLine ...
- BERT 服务化 bert-as-service
bert-as-service 用 BERT 作为句子编码器, 并通过 ZeroMQ 服务托管, 只需两行代码就可以将句子映射成固定长度的向量表示; 准备 windows10 + python3.5 ...
- nessus 故障处理
0x00 问题描述 打开Nessues Web Client时,界面循环在Initializing Please wait while Nessus prepares files needed...和 ...
- 关于个Base64,MD5,16进制的转换
1,待签名数据以UTF-8的格式转字节流,对字节流进行MD5算法得到的签名字节流,再转换为16进制字符串,即生成了数字签名. byte[] targetData = md5.ComputeHash(S ...
- 对String Intern()方法的理解
今天重新看了一点周志明大佬的<深入理解Java虚拟机>,发现这个地方讲的不是很透彻,在网络上看到一些博客基本也都是在搬运原文,搞得一头雾水.弄了半天算是彻底明白了,做一下笔记. 搬运一下原 ...
- MyBatis(三):自定义持久层框架实现
代码已上传至码云:https://gitee.com/rangers-sun/mybatis 新建Maven工程 架构端MyPersistent.使用端MyPersistentTest,使用端引入架构 ...
- C# 基础 - Enum 的一些操作
1. int 转换成 enum public enum Suit { Spades, Hearts, Clubs, Diamonds } Suit spades = (Suit)0; Suit hea ...
- 浅谈Java的反射的原理
Java的编译过程 谈及反射,不得不先了解一下,java的整个编译过程,整体的java编译过程可以参考 之前的一篇 一个java文件被执行的历程 这里我们只针对 对象这一层级来讨论,一个java文件, ...