mybatis源码阅读笔记-卷三(核心知识下)
十四.binding
14.1MapperMethod
映射器方法构造函数中需要传入Mapper的type,具体的Method对象以及配置。然后在构造器初始化一个SqlCommand静态内部类对象和MethodSignature静态内部类对象。
(1)初始化SqlCommand
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
//获取方法名
final String methodName = method.getName();
final Class<?> declaringClass = method.getDeclaringClass();
//获取到映射器声明,当declaringClass和mapperInterface相同时,直接返回了空
//也就是说在configuration必须要存在映射声明,或者declaringClass为实现类,而不是mapperInterface
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
if (ms == null) {
if(method.getAnnotation(Flush.class) != null){
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException("Invalid bound statement (not found): "
+ mapperInterface.getName() + "." + methodName);
}
} else {
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
(2)初始化MethodSignature
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
//解析返回参数类型
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
//判断是否为普通类
if (resolvedReturnType instanceof Class<?>) {
this.returnType = (Class<?>) resolvedReturnType;
//判断是否为泛型类
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
//返回类型是否为void
this.returnsVoid = void.class.equals(this.returnType);
//返回类型是集合还是数组
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
this.returnsCursor = Cursor.class.equals(this.returnType);
this.returnsOptional = Optional.class.equals(this.returnType);
//获取map的键值取于哪一列
this.mapKey = getMapKey(method);
//返回是否为map
this.returnsMap = this.mapKey != null;
//获取方法参数表中RowBounds位于第几个
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
//获取方法参数表中ResultHandler位于第几个
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
//解析标注Param的注解,获取注解的value,将参数的位置和value存入map
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
(3)execute方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
//返回param参数map,键值为@Param的value,值为方法入参数的值
Object param = method.convertArgsToSqlCommandParam(args);
//command.getName()=statementId
//调用sqlSession中的insert方法,返回值类型可以为void|boolean|integer|long
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
//具有ResultHandler的方法
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
//返回数组类型或Collection类型的结果集
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
//返回map类型的结果集
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional() &&
(result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
14.2MapperProxy
映射器代理主要是往methodCache中插入新的MapperMethod,且委托MapperMethod执行方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
//如果实现类是Object,直接执行方法,如toString()。
return method.invoke(this, args);
//判断是否是接口中的default方法
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//如果不在缓存中则新增缓存,method为键,MapperMethod对象为value
final MapperMethod mapperMethod = cachedMapperMethod(method);
//使用MapperMethod中的方法进行执行。
return mapperMethod.execute(sqlSession, args);
}
14.3 MapperProxyFactory映射代理工厂
映射器代理工厂是一个泛型类,通过newInstance(MapperProxy<T> mapperProxy)方法和newInstance(SqlSession sqlSession)方法来产生Mapper的实例对象。
14.4 MapperRegistry映射注册机
(1)获取映射
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//从缓存中获取映射器代理工厂
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//通过sqlSession获取实例化Mapper对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
(2)添加映射
public <T> void addMapper(Class<T> type) {
//只有是interface才会执行下面的逻辑,也就是说Mapper只能是接口
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
//解析Mapper
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
//这里面会有很多异常情况抛出,如果抛出异常,就不能设置loadComplete为true
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
15.executor
执行流程:
image
执行器包内核心接口定义了如下方法:
//没有结果处理器
ResultHandler NO_RESULT_HANDLER = null;
//执行更新
int update(MappedStatement ms, Object parameter) throws SQLException;
//执行查询,自己传入cacheKey和boundSql
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
//执行查询,和上面的接口差不多,只不过上面的后两个参数通过传入的参数生成
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
//带指向箭头的查询
<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
//执行冲刷批处理
List<BatchResult> flushStatements() throws SQLException;
//提交
void commit(boolean required) throws SQLException;
//回滚
void rollback(boolean required) throws SQLException;
//创建缓存Key对象
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
//是否已经缓存
boolean isCached(MappedStatement ms, CacheKey key);
//清除本地换缓存
void clearLocalCache();
//延迟加载
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
//获取事务对象
Transaction getTransaction();
//关闭连接
void close(boolean forceRollback);
//是否已经关闭
boolean isClosed();
//设置执行器包装
void setExecutorWrapper(Executor executor);
15.1ErrorContext错误上下文
用于存放错误信息,内部有一个ThreadLocal用于读取线程本地变量信息。
15.2CachingExecutor
这个类实现了Executor接口,但是它并没有真正的去执行,而是调用构造器中传入的执行器对象去执行,感觉像是一个委托执行器。
15.3BaseExecutor基础执行器
这是一个抽象类,实现了Executor中定义的部分方法,主要为:
(1)update方法:
public int update(MappedStatement ms, Object parameter) throws SQLException {
//先设置错误上下文信息,resource就是Mapper的资源全路径
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();
//调用update方法,这里没有实现,等待实体类去实现
return doUpdate(ms, parameter);
}
(2)query查询方法:
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
//设置错误上下文resource是mapper的全路径,id是路径后+.方法名+参数类型,全局唯一
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
//如果没有传入结果处理器,则从缓存中取数据
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
//处理缓存中的OUT参数,根据key取
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//从数据库中获取数据
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
//如果没有意外这里应该都是0吧
if (queryStack == 0) {
//逐个载入延迟队列的元素
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
//队列全部清空
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
//先用一个placeHolder占一下位子
//是不是防止别的地方插入,这个东西有点奇怪
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
//调用查询接口
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
//删除占位
localCache.removeObject(key);
}
//放入真正的查询结果
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
//如果是callable类型,则放入缓存,待取用
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
(3)deferLoad延迟加载:
public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
DeferredLoad deferredLoad = new DeferredLoad(resultObject, property, key, localCache, configuration, targetType);
//判断能不能加载---缓存中不为空,或者不是placeHolder,这么一来刚才用的占位符就有意义了
if (deferredLoad.canLoad()) {
deferredLoad.load();
} else {
//为什么不把刚才的对象放在队列中,需要新new一个?
deferredLoads.add(new DeferredLoad(resultObject, property, key, localCache, configuration, targetType));
}
}
(4)createCacheKey缓存key:
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
//生成key对象
CacheKey cacheKey = new CacheKey();
//实际上就是调用了他内部list的add方法
cacheKey.update(ms.getId());
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
cacheKey.update(boundSql.getSql());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
// mimic DefaultParameterHandler logic
for (ParameterMapping parameterMapping : parameterMappings) {
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
//获取属性名
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
//如果有使用类型处理器,就不处理,直接赋值
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
cacheKey.update(value);
}
}
if (configuration.getEnvironment() != null) {
// issue #176
//缓存环境的id
cacheKey.update(configuration.getEnvironment().getId());
}
return cacheKey;
}
15.4keygen包
15.4.1Jdbc3KeyGenerator
它的processBefore是没用的,只有后置处理生效了
public void processBatch(MappedStatementms, Statement stmt, Object parameter) {
//自动生成的键值名,如自增序列的列名
final String[] keyProperties = ms.getKeyProperties();
if (keyProperties == null || keyProperties.length == 0) {
return;
}
ResultSet rs = null;
try {
//调用statement的方法获取生成键
rs = stmt.getGeneratedKeys();
final Configuration configuration = ms.getConfiguration();
if (rs.getMetaData().getColumnCount() >= keyProperties.length) {
//获取唯一参数
Object soleParam = getSoleParameter(parameter);
if (soleParam != null) {
//将rs中的值赋给soleParam
assignKeysToParam(configuration, rs, keyProperties, soleParam);
} else {
//给子属性赋值
assignKeysToOneOfParams(configuration, rs, keyProperties, (Map) parameter);
}
}
}catch (Exception e) {
throw new ExecutorException("Error getting generated key or settingresult to parameter object. Cause: " + e, e);
}finally {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
// ignore
}
}
}
}
15.4.2SelectKeyGenerator
这个和Jdbc3的Key生成器正好相反,它只有ProcessBefore有用。
private voidprocessGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
try {
if (parameter != null &&keyStatement != null && keyStatement.getKeyProperties() != null) {
String[] keyProperties =keyStatement.getKeyProperties();
final Configuration configuration =ms.getConfiguration();
final MetaObject metaParam =configuration.newMetaObject(parameter);
if (keyProperties != null) {
// Do not close keyExecutor.
// The transaction will be closed byparent executor.
Executor keyExecutor =configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
List values =keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT,Executor.NO_RESULT_HANDLER);
if (values.size() == 0) {
throw newExecutorException("SelectKey returned no data.");
} else if (values.size() > 1) {
throw newExecutorException("SelectKey returned more than one value.");
} else {
MetaObject metaResult =configuration.newMetaObject(values.get(0));
if (keyProperties.length == 1) {
if(metaResult.hasGetter(keyProperties[0])) {
//给metaParam中与keyProperties[0]属性名对应的属性赋值
setValue(metaParam,keyProperties[0], metaResult.getValue(keyProperties[0]));
} else {
// no getter for the property -maybe just a single value object
// so try that
setValue(metaParam,keyProperties[0], values.get(0));
}
} else {
handleMultipleProperties(keyProperties, metaParam, metaResult);
}
}
}
}
} catch (ExecutorException e) {
throw e;
} catch (Exception e) {
throw new ExecutorException("Errorselecting key or setting result to parameter object. Cause: " + e, e);
}
}
15.5 statement包
15.5.1StatementHandler接口类
它是一个接口类,内部声明了8个接口方法,BaseStatementHandler中简单了实现了部分功能,从未称为基类,但是BaseStatementHandler是一个抽象的类,它还是有部分是空的,内部实现了部分方法,还有部分方法未实现,待真正的实现类去实现。
//通过连接和事务超时,获取Statement
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
//statement参数化
void parameterize(Statement statement)
throws SQLException;
//批处理
void batch(Statement statement)
throws SQLException;
//更新操作
int update(Statement statement)
throws SQLException;
//查询操作
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
//查询
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;
//获取boundSql
BoundSql getBoundSql();
//得到参数处理器
ParameterHandler getParameterHandler();
15.5.2 StatementUtil
工具类中提供了一个应用事务超时的方法:
public static void applyTransactionTimeout(Statement statement, Integer queryTimeout,
Integer transactionTimeout) throws SQLException {
if (transactionTimeout == null){
return;
}
Integer timeToLiveOfQuery = null;
if (queryTimeout == null || queryTimeout == 0) {
//查询超时为0或空,则超时就等于事务超时时间
timeToLiveOfQuery = transactionTimeout;
} else if (transactionTimeout < queryTimeout) {
//当事务超时时间小于查询超时时间,取事务超时
//貌似可以和上面的条件和并0<=transactionTimeout<queryTimeout
timeToLiveOfQuery = transactionTimeout;
}
//到这里应该能发现,如果查询超时小于事务超时,则不做更改
if (timeToLiveOfQuery != null) {
statement.setQueryTimeout(timeToLiveOfQuery);
}
}
15.7result包
15.7.1 DefaultMapResultHandler
public void handleResult(ResultContext<? extends V> context) {
//以前版本是将得到的Object强转到V,现在是直接赋值
final V value = context.getResultObject();
//利用对象工厂和对象包装器,反射工厂对value进行包装
final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
// TODO is that assignment always true?
final K key = (K) mo.getValue(mapKey);
//利用属性中的map存放key属性名和值
mappedResults.put(key, value);
}
15.7.2 DefaultResultSetHandler默认结果集处理器
默认的结果集貌似就是ArrayList,两个构造器的实现结果都一样:
public DefaultResultHandler() {
list = new ArrayList<>();
}
@SuppressWarnings("unchecked")
public DefaultResultHandler(ObjectFactory objectFactory) {
//通过对象工厂构建List,和上面的构造器效果是一样的,最终处理成了ArrayList
//这里既然最终结果都一样,为什么不直接使用新建一个对象,非得要使用对象工厂去新建呢,降低了整体的效率
list = objectFactory.create(List.class);
}
15.8resultset包
15.8.1 ResultSetHandler
接口声明了三个方法,相较于从前新增了一个方法:
//处理结果集
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
//新增的接口,处理Cursor结果集
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
//处理出参数
void handleOutputParameters(CallableStatement cs) throws SQLException;
15.8.2 ResultSetWrapper结果集包装器
(1)包装器的构造函数中将结果的列名、类型、jdbc中的数据类型,存放到三个列表中:
public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
super();
//从配置中获取类型处理注册器
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.resultSet = rs;
final ResultSetMetaData metaData = rs.getMetaData();
//结果集的列数
final int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
//结果集列名,默认都是使用的列标签
columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
//类型处理
jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
//列名对应的值的type
classNames.add(metaData.getColumnClassName(i));
}
}
(2)获取类型处理器:
public TypeHandler<?> getTypeHandler(Class<?> propertyType, String columnName) {
TypeHandler<?> handler = null;
//从类型处理map中获取类型处理器map
Map<Class<?>, TypeHandler<?>> columnHandlers = typeHandlerMap.get(columnName);
if (columnHandlers == null) {
columnHandlers = new HashMap<>();
typeHandlerMap.put(columnName, columnHandlers);
} else {
handler = columnHandlers.get(propertyType);
}
if (handler == null) {
//根据列名获取jdbc类型,前面有三个列表(列名,jdbc类型,java类型)
// 数据的时候是同步存入的,取用的时候也可以同步取用
JdbcType jdbcType = getJdbcType(columnName);
//获取类型处理器
handler = typeHandlerRegistry.getTypeHandler(propertyType, jdbcType);
// Replicate logic of UnknownTypeHandler#resolveTypeHandler
// See issue #59 comment 10
if (handler == null || handler instanceof UnknownTypeHandler) {
//找到list中的索引
final int index = columnNames.indexOf(columnName);
//根据索引获取java类型
final Class<?> javaType = resolveClass(classNames.get(index));
if (javaType != null && jdbcType != null) {
handler = typeHandlerRegistry.getTypeHandler(javaType, jdbcType);
} else if (javaType != null) {
handler = typeHandlerRegistry.getTypeHandler(javaType);
} else if (jdbcType != null) {
handler = typeHandlerRegistry.getTypeHandler(jdbcType);
}
}
//最终都没有获得类型处理器,新建一个Object类型处理器
if (handler == null || handler instanceof UnknownTypeHandler) {
handler = new ObjectTypeHandler();
}
columnHandlers.put(propertyType, handler);
}
return handler;
}
(3)映射的Map加载:
//加载已经映射的和未映射的列名
private void loadMappedAndUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {
List<String> mappedColumnNames = new ArrayList<>();
List<String> unmappedColumnNames = new ArrayList<>();
final String upperColumnPrefix = columnPrefix == null ? null : columnPrefix.toUpperCase(Locale.ENGLISH);
//给它加上upperColumnPrefix前缀
final Set<String> mappedColumns = prependPrefixes(resultMap.getMappedColumns(), upperColumnPrefix);
for (String columnName : columnNames) {
//在这里有个疑惑,字段名是小写的就不能映射了吗,存到unmappedColumnNames?
final String upperColumnName = columnName.toUpperCase(Locale.ENGLISH);
if (mappedColumns.contains(upperColumnName)) {
mappedColumnNames.add(upperColumnName);
} else {
unmappedColumnNames.add(columnName);
}
}
//resultMapId:前缀 为键,映射完成的list以及未完成的list为值的map
mappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), mappedColumnNames);
unMappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), unmappedColumnNames);
}
15.8.3 DefaultResultSetHandler
(1)结果集处理方法
//处理结果集
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap,
List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
try {
if (parentMapping != null) {
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
if (resultHandler == null) {
//如果没有结果处理器
//新建一个默认的结果处理器
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
//调用行结果处理方法
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
//添加对象工厂中的list到多结果集中
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
//关闭结果集,防止泄露
closeResultSet(rsw.getResultSet());
}
}
(2)行值获取
//获取到一行的值
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//创建行值对象
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
//通过行值新建元对象,用于后面的赋值
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, false)) {
//非嵌套的时候使用自动映射,以前的版本是默认前缀为空的,当前版本增加了columnPrefix
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
十六.parsing
看包名应该是用于解析的,包中的内容较少,只有一个接口,声明了一个解析token的方法。
16.1 GenericTokenParser
这个类中有三个属性,token的结束标记和开始标记,以及token的处理器,都通过构造器注入。解析起始符号和结束符号之间的字符串,使用自己实现的TokenHandler。
public String parse(String text) {
if (text == null || text.isEmpty()) {
return "";
}
// 查找token起始符号的位置,如果没有直接返回
int start = text.indexOf(openToken, 0);
if (start == -1) {
return text;
}
char[] src = text.toCharArray();
int offset = 0;
final StringBuilder builder = new StringBuilder();
StringBuilder expression = null;
//循环解析到所有起始符号和结束符号解析完毕,获取中间的值
while (start > -1) {
if (start > 0 && src[start - 1] == '\\') {
// this open token is escaped. remove the backslash and continue.
builder.append(src, offset, start - offset - 1).append(openToken);
offset = start + openToken.length();
} else {
// found open token. let's search close token.
if (expression == null) {
expression = new StringBuilder();
} else {
//清零,其实没有清零,只是toString的时候会是个空的字符串
expression.setLength(0);
}
builder.append(src, offset, start - offset);
offset = start + openToken.length();
int end = text.indexOf(closeToken, offset);
while (end > -1) {
if (end > offset && src[end - 1] == '\\') {
// this close token is escaped. remove the backslash and continue.
expression.append(src, offset, end - offset - 1).append(closeToken);
offset = end + closeToken.length();
end = text.indexOf(closeToken, offset);
} else {
expression.append(src, offset, end - offset);
offset = end + closeToken.length();
break;
}
}
if (end == -1) {
// close token was not found.
builder.append(src, start, src.length - start);
offset = src.length;
} else {
//使用自己的handler去处理解析到的值
builder.append(handler.handleToken(expression.toString()));
offset = end + closeToken.length();
}
}
start = text.indexOf(openToken, offset);
}
if (offset < src.length) {
//把尾巴也拼接上
builder.append(src, offset, src.length - offset);
}
return builder.toString();
}
16.2 PropertyParser属性解析器
属性解析器用传入的map中的value替换输入字符串中起始标记和结束标记之间的值(相当于key)。
16.3 XPathParser
第一次接触到这个XPath,XPath是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。XPath 是W3C XSLT标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。因此,对 XPath 的理解是很多高级 XML 应用的基础。
PS:关于xpath的源码都在javax的xml包中。
十七.plugin插件
这个包内部主要实现了拦截器的功能,为什么包名不叫interceptor呢?Interceptor接口内部声明了三个方法:
//拦截
Object intercept(Invocation invocation) throws Throwable;
//插入
Object plugin(Object target);
//设置属性
void setProperties(Properties properties);
17.1InterceptorChain拦截链
拦截链内部有个ArrayList存放各个拦截器,通过方法注入插件:
public Object pluginAll(Object target) {
//循环调用每个Interceptor.plugin方法
//让人捉摸不透的地方是,返回的target只能是最后一个interceptor
// 只有一个的情况下倒是没问题,多个的时候这样返回不就是有问题吗
for (Interceptor interceptor : interceptors) {
//在PluginTest中能够看到调用Plugin中的wrap方法,返回结果。
target = interceptor.plugin(target);
}
return target;
}
17.2 Invocation
我对于这个样式的类已经慕名已久了,在刚遇到反射的时候就看到有一个invoke方法,但是没有往下看去窥其全貌,仅仅保持了好奇心,到现在也没空去看这个方法,但是学过JVM之后大致知道它是怎么实现的,等学JDK反射部分的源码时再深入学习好了。
这个类内部具有三个属性通过构造器注入,通过proceed方法实际调用target中的method方法。:
//调用的对象
private Object target;
//调用的方法
private Method method;
//方法的参数表
private Object[] args;
17.3 Plugin
前面提到,拦截器中的plugin方法会调用到Plugin类中的静态方法wrap:
public static Object wrap(Object target, Interceptor interceptor) {
//取得签名Map
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
//取得要改变行为的类(ParameterHandler|ResultSetHandler|StatementHandler|Executor)
Class<?> type = target.getClass();
//取得接口
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
//产生代理
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
//取得签名Map
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
//取Intercepts注解,例子可参见ExamplePlugin.java
Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
// issue #251
//必须得有Intercepts注解,没有报错
if (interceptsAnnotation == null) {
throw new PluginException("No @Intercepts annotation was found in interceptor "
+ interceptor.getClass().getName());
}
//value是数组型,Signature的数组
Signature[] sigs = interceptsAnnotation.value();
//每个class里有多个Method需要被拦截,所以这么定义
Map<Class<?>, Set<Method>> signatureMap = new HashMap<Class<?>, Set<Method>>();
for (Signature sig : sigs) {
Set<Method> methods = signatureMap.get(sig.type());
if (methods == null) {
methods = new HashSet<Method>();
signatureMap.put(sig.type(), methods);
}
try {
Method method = sig.type().getMethod(sig.method(), sig.args());
methods.add(method);
} catch (NoSuchMethodException e) {
throw new PluginException("Could not find method on " + sig.type() + " named "
+ sig.method() + ". Cause: " + e, e);
}
}
return signatureMap;
}
//取得接口
private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
Set<Class<?>> interfaces = new HashSet<Class<?>>();
while (type != null) {
for (Class<?> c : type.getInterfaces()) {
//貌似只能拦截ParameterHandler|ResultSetHandler|StatementHandler|Executor
//拦截其他的无效
//当然我们可以覆盖Plugin.wrap方法,达到拦截其他类的功能
if (signatureMap.containsKey(c)) {
interfaces.add(c);
}
}
//获取它extends的类
type = type.getSuperclass();
}
return interfaces.toArray(new Class<?>[interfaces.size()]);
}
17.4 Intercepts和Signature注解
在PluginTest中找到一个用例,在自定义实现Interceptor接口,并在实现的类上标注注解,如下所示:
@Intercepts({@Signature(type = Map.class, method = "get", args = {Object.class})})
public static class AlwaysMapPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
return "Always";
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}