Devin's Blogs

个人点滴记录

主要研究 DefaultSqlSession 对象的查询方法

流程图

https://www.processon.com/view/link/655092a17b996f7b645b648d

多行查询

定位: org.apache.ibatis.session.defaults.DefaultSqlSession#selectList

作用: 根据条件查询, 返回 list 集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 @Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
}

// 核心selectList
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
// 根据 statement id 找到对应的 MappedStatement
MappedStatement ms = configuration.getMappedStatement(statement);
// 转用执行器来查询结果, 注意这里传入的 ResultHandler 是 null
// 如果存在插件, 即(executor 被代理), 则会执行 org.apache.ibatis.plugin.Plugin#invoke
return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
// 清空错误上下文
ErrorContext.instance().reset();
}
}
// 若参数为集合或数组, 则转换成 Map 对象, 否则返回原对象
public static Object wrapToMapIfCollection(Object object, String actualParamName) {
if (object instanceof Collection) {
// 参数若是 Collection 型,做 collection 标记
ParamMap<Object> map = new ParamMap<>();
map.put("collection", object);
if (object instanceof List) {
// 参数若是 List 型,做 list 标记
map.put("list", object);
}
Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
return map;
} else if (object != null && object.getClass().isArray()) {
// 参数若是数组型,做 array 标记
ParamMap<Object> map = new ParamMap<>();
map.put("array", object);
Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
return map;
}
// 参数若不是集合型,直接返回原来值
return object;
}

插件和拦截器

定位: org.apache.ibatis.plugin.Plugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// org.apache.ibatis.plugin.Plugin#invoke
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 获取当前方法所在类或接口中,可被当前Interceptor拦截的方式
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
// 如果当前调用的方式需要被拦截,则调用intercept方法进行拦截处理
if (methods != null && methods.contains(method)) {
//调用Interceptor.intercept,也即插入了我们自己的逻辑
return interceptor.intercept(new Invocation(target, method, args));
}
// 如果当前调用的方法不能被拦截,则调用target对象的相应方法
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
public static Object wrap(Object target, Interceptor interceptor) {
// 获取用户自定义Interceptor中@Signature注解的信息,getSignatureMap方法负责处理@Signture注解
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
// 获取目标类型
Class<?> type = target.getClass();
// 获取目标类型实现的接口,拦截器可以拦截的 4 类对象都实现了相应的接口,这也是能使用 JDK 动态代理的方式创建代理对象的基础
// 支持被拦截的接口有: Executor, StatementHandler, ParameterHandler, ResultSetHandler
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
// 使用 JDK 动态代理的方式创建代理对象
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
// 使用 InvocationHandler 对象就是 Plugin 对象
new Plugin(target, interceptor, signatureMap));
}
return target;
}
// 取得签名 Map
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
// 取 Intercepts 注解
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<>();
for (Signature sig : sigs) {
Set<Method> methods = MapUtil.computeIfAbsent(signatureMap, sig.type(), k -> new HashSet<>());
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;
}

自定义拦截器

1
2
3
4
5
6
7
8
9
10
11
// 自定义实现拦截器
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class MyInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("-------" + invocation + "================");
Object result = invocation.proceed();
System.out.println("-------" + result + "================");
return result;
}
}

CachingExecutor 查询

定位: org.apache.ibatis.executor.CachingExecutor

作用: CachingExecutor 作为二级缓存执行器, 添加了缓存机制, 其实际查询逻辑仍然由 BaseExecutor#query 的实现类(即delegate)来执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 获取 BoundSql 对象
BoundSql boundSql = ms.getBoundSql(parameterObject);
// 创建 CacheKey 对象
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

// 被 ResultLoader.selectList 调用
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
// 获取查询语句所在命名空间对应的二级缓存
Cache cache = ms.getCache();
// 是否开启了二级缓存
if (cache != null) {
// 根据 select 节点的配置,决定是否需要清空二级缓存
flushCacheIfRequired(ms);
// 检测 SQL 节点的 useCache 配置以及是否使用了 resultHandler 配置
if (ms.isUseCache() && resultHandler == null) {
// 二级缓存不能保存输出类型的参数,如果查询操作调用了包含输出参数的存储过程,则报错
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
// 查询二级缓存
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
// 二级缓存没有相应的结果集,调用封装的 Executor 对象的 query 方法
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
// 将查询结果保存到 TransactionalCache.entriesToAddOnCommit 集合中
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
// 没有启动二级缓存,直接调用底层Executor执行数据库查询操作
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

BaseExecutor 查询

查询: org.apache.ibatis.executor.BaseExecutor#query

作用: BaseExecutor 的实现类有: SimpleExecutor(简单执行器), ReuseExecutor(重用执行器), BatchExecutor(批处理执行器)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
// 检测当前 Executor 是否已经关闭
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
// 非嵌套查询,并且 select 节点配置的 flushCache 属性为 true 时,才会清空一级缓存, flushCache 配置项是影响一级缓存中结果对象存活时长的第一个方面
clearLocalCache();
}
List<E> list;
try {
// 增加查询层数
queryStack++;
// 查询一级缓存
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
// 针对存储过程调用的处理,在一级缓存命中时,获取缓存中保存的输出类型参数,并设置到用户传入的实参对象中
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 调用 doQuery 方法完成数据库查询,并得到映射后的结果对象
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
// 当前查询完成,查询层数减少
queryStack--;
}
if (queryStack == 0) {
// 在最外层的查询结束时,所有嵌套查询也已经完成,相关缓存项也已经完全记载,所以在此处触发DeferredLoad 加载一级缓存中记录的嵌套查询的结果对象
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
// 加载完成后,清空deferredLoads集合
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
// 根据 LocalCacheScope 配置决定是否清空一级缓存
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;
// 在缓存中添加占位符
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) {
// 缓存输出类型的参数
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
// 创建缓存Key
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
// 检测当前 executor 是否已经关闭
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 创建 CacheKey 对象
CacheKey cacheKey = new CacheKey();
// 将 MappedStatemen t的 id 添加到 CacheKey 对象中
cacheKey.update(ms.getId());
// 将 offset 添加到 CacheKey 对象中
cacheKey.update(rowBounds.getOffset());
// 将 limit 添加到 CacheKey 对象中
cacheKey.update(rowBounds.getLimit());
// 将 sql 添加到 CacheKey 对象中
cacheKey.update(boundSql.getSql());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
// 获取用户传入的实参,并添加到 CacheKey 对象中
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 对象中
cacheKey.update(value);
}
}
// 如果 environment 的 id 不为空,则将其添加到 CacheKey 中
if (configuration.getEnvironment() != null) {
// issue #176
cacheKey.update(configuration.getEnvironment().getId());
}
return cacheKey;
}

SimpleExecutor 查询

定位: org.apache.ibatis.executor.SimpleExecutor#doQuery

作用: 默认实现的查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
// 获取配置对象
Configuration configuration = ms.getConfiguration();
// 创建StatementHandler对象,实际返回的是RoutingStatementHandler对象
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 完成Statement的创建和初始化
stmt = prepareStatement(handler, ms.getStatementLog());
// 调用query方法执行sql语句,并通过ResultSetHandler完成结果集的映射
return handler.query(stmt, resultHandler);
} finally {
// 关闭Statement对象
closeStatement(stmt);
}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 获取数据库连接
Connection connection = getConnection(statementLog);
// 创建Statement对象
stmt = handler.prepare(connection, transaction.getTimeout());
// 处理占位符
handler.parameterize(stmt);
return stmt;
}
// org.apache.ibatis.session.Configuration#newStatementHandler
// 创建语句处理器
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 创建路由选择语句处理器
// 根据 MappedStatement 的配置,生成一个对应的 StatementHandler 对象
// SimpleStatementHandler, PreparedStatementHandler, CallableStatementHandler
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 引入插件
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}

PreparedStatementHandler 查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 准备语句
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
// 实例化 Statement
statement = instantiateStatement(connection);
// 设置超时
setStatementTimeout(statement, transactionTimeout);
// 设置读取条数
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
// 执行数据库查询
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 执行 jdbc 的查询
ps.execute();
// 解析返回结果
return resultSetHandler.handleResultSets(ps);
}

多行查询(map)

定位: org.apache.ibatis.session.defaults.DefaultSqlSession#selectMap

作用: 根据条件查询, 返回 map 对象, key 为 @MapKey 指定列, value 为查询列对象; 与多行查询的不同点在于, 返回结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
}
// 核心selectMap
@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
// 调用 selectList, 此方法实现参考"多行查询"介绍
final List<? extends V> list = selectList(statement, parameter, rowBounds);
final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
final DefaultResultContext<V> context = new DefaultResultContext<>();
for (V o : list) {
// 循环用 DefaultMapResultHandler 处理每条记录
context.nextResultObject(o);
mapResultHandler.handleResult(context);
}
// 注意这个 DefaultMapResultHandler 里面存了所有已处理的记录(内部实现可能就是一个Map),最后再返回一个 Map
return mapResultHandler.getMappedResults();
}

游标查询

定位: org.apache.ibatis.session.defaults.DefaultSqlSession#selectCursor

作用: 根据条件查询, 返回游标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public <T> Cursor<T> selectCursor(String statement, Object parameter) {
return selectCursor(statement, parameter, RowBounds.DEFAULT);
}
@Override
public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
registerCursor(cursor);
return cursor;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

CachingExecutor 游标查询

定位: org.apache.ibatis.executor.CachingExecutor#queryCursor

1
2
3
4
5
6
@Override
public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {
flushCacheIfRequired(ms);
// 没有二级缓存
return delegate.queryCursor(ms, parameter, rowBounds);
}

BaseExecutor 游标查询

定位: org.apache.ibatis.executor.BaseExecutor#queryCursor

1
2
3
4
5
@Override
public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
return doQueryCursor(ms, parameter, rowBounds, boundSql);
}

SimpleExecutor 游标查询

定位: org.apache.ibatis.executor.SimpleExecutor#doQueryCursor

1
2
3
4
5
6
7
8
9
@Override
protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
Cursor<E> cursor = handler.queryCursor(stmt);
stmt.closeOnCompletion();
return cursor;
}

PreparedStatementHandler 游标查询

定位: org.apache.ibatis.executor.statement.PreparedStatementHandler#queryCursor

1
2
3
4
5
6
@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.handleCursorResultSets(ps);
}

普通结果集

定位: org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

处理配置 resultMap, resultSet 和 resultSets 的结果映射(支持多个结果集)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
// 该集合用于保存映射结果得到的结果对象
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// 获取第一个 ResultSet 对象
ResultSetWrapper rsw = getFirstResultSet(stmt);

// 获取 MappedStatement.resultMaps 集合
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
// 如果集合集不为空,则 resultMaps 集合不能为空,否则抛出异常
validateResultMapsCount(rsw, resultMapCount);
// 遍历 resultMaps 集合
while (rsw != null && resultMapCount > resultSetCount) {
// 获取该结果集对应的 ResultMap 对象
ResultMap resultMap = resultMaps.get(resultSetCount);
// 根据 ResultMap 中定义的映射规则对 ResultSet 进行映射,并将映射的结果对象添加到multipleResult 集合中保存
handleResultSet(rsw, resultMap, multipleResults, null);
// 获取下一个结果集
rsw = getNextResultSet(stmt);
// 清空 nestedResultObjects 集合
cleanUpAfterHandlingResultSet();
// 递增 resultSetCount
resultSetCount++;
}

// 获取 MappedStatement.resultSets 属性,该属性对多结果集的情况使用,该属性将列出语句执行后返回的结果集,并给每个结果集一个名称,名称是逗号分隔的,
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
// 根据 resultSet 的名称,获取未处理的 ResultMapping
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
// 根据 ResultMap 对象映射结果集
handleResultSet(rsw, resultMap, null, parentMapping);
}
// 获取下一个结果集
rsw = getNextResultSet(stmt);
// 清空 nestedResultObjects 集合
cleanUpAfterHandlingResultSet();
// 递增 resultSetCount
resultSetCount++;
}
}

return collapseSingleResultList(multipleResults);
}

定位: org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

处理单个结果集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 处理结果集
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) {
// 如果用户未指定处理映射结果对象的 ResultHandler 对象,则使用 DefaultResultHandler 作为默认的 ResultHandler 对象
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
// 对 ResultSet 进行映射,并将映射得到的结果对象添加到 DefaultResultHandler 对象中暂存
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
// 将 DefaultResultHandler 中保存的结果对象添加到 multipleResults 集合中
multipleResults.add(defaultResultHandler.getResultList());
} else {
// 使用用户指定的 ResultHandler 对象处理结果对象
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
// 调用 ResultSet.close 方法关闭结果集
closeResultSet(rsw.getResultSet());
}
}
// 处理一行的所有字段值
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
// 针对存在嵌套 ResultMap 的情况
if (resultMap.hasNestedResultMaps()) {
// 检测是否允许在嵌套映射中使用 RowBound
ensureNoRowBounds();
checkResultHandler();
// 检测是否允许在嵌套映射中使用用户自定义的 ResultHandler
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
// 针对不含嵌套映射的简单映射的处理
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}

非嵌套结果集

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForSimpleResultMap
遍历结果集的所有行, 将一行的数据自动映射成一个对象,并将此对象添加到 resultList 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
// 默认上下文对象
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
ResultSet resultSet = rsw.getResultSet();
// 根据 RowBounds 中的 offset 定位到指定的记录
skipRows(resultSet, rowBounds);
// 检测已经处理的行数是否已经达到上限(RowBounds,limit)以及ResultSet中是否还有可处理的记录
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
// 根据该行记录以及 ResultMap.discriminator,决定映射使用的 ResultMap
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
// 根据最终确定的 ResultMap 对 ResultSet 中的该行记录进行映射,得到映射后的结果对象
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
// 将映射创建的结果对象添加到 ResultHandler.resultList 中保存
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}


org.apache.ibatis.executor.resultset.DefaultResultSetHandler#resolveDiscriminatedResultMap

使用配置字段的结果值来决定使用哪个 resultMap

1
2
3
4
<!-- 配置 -->
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
// 记录已经处理过的 ResultMap 的 id
Set<String> pastDiscriminators = new HashSet<>();
// 获取 ResultMap 中的 Discriminator 对象
Discriminator discriminator = resultMap.getDiscriminator();
while (discriminator != null) {
// 获取记录中对应列的值,其中会使用相应的 TypeHandler 对象将该列值转换成 Java 类型
final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
// 根据该列值获取对应的 ResultMap 的 id
final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
if (configuration.hasResultMap(discriminatedMapId)) {
// 根据上述获取的 id 查找相应的 ResultMap 对象
resultMap = configuration.getResultMap(discriminatedMapId);
// 记录当前 Discriminator 对象
Discriminator lastDiscriminator = discriminator;
// 获取 ResultMap 对象中的 Discrimination
discriminator = resultMap.getDiscriminator();
// 检测 Discriminator 是否出现了环形引用
if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
break;
}
} else {
break;
}
}
// 该 ResultMap 对象为映射最终使用的 ResultMap
return resultMap;
}

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue
创建实体类对象;自动映射结果集中有的column,但 resultMap 中并没有配置;根据 resultMap 节点中配置的映射关系进行映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  // 核心,取得一行的值
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
// 实例化 ResultLoaderMap (延迟加载器)
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 创建该行记录映射之后得到的结果对象,该结果对象的类型由 ResultMap 节点的 type 属性指定
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
// 创建上述结果对象相应的 MetaObject 对象
final MetaObject metaObject = configuration.newMetaObject(rowValue);
// 成功映射任意属性,则 foundValues 为 true,否则 foundValues 为 false
boolean foundValues = this.useConstructorMappings;
// 检测是否需要进行自动映射
if (shouldApplyAutomaticMappings(resultMap, false)) {
// 自动映射 ResultMap 中未明确指定的列
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
// 映射 ResultMap 中明确指定需要映射的列
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
// 如果没有成功映射任何属性,则根据 mybatis-config.xml 中的 returnInstanceForEmptyRow 配置决定返回空的结果对象还是返回 null
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
// 自动映射
// 如果配置了自动映射, 跟根据 typeHandler 来解析列
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
// 获取 ResultSet 中存在,但 ResultMap 中没有明确映射的列所对应的UnMappedColumnAutoMapping 集合,如果 ResultMap 中设置的 resultType 为 HashMap 的话,则全部的列都会在这里获取到
List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
boolean foundValues = false;
if (!autoMapping.isEmpty()) {
// 遍历 autoMapping 集合
for (UnMappedColumnAutoMapping mapping : autoMapping) {
// 使用 TypeHandler 获取自动映射的列值
final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
if (value != null) {
foundValues = true;
}
if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
// gcode issue #377, call setter on nulls (value is not 'found')
// 将自动映射的属性值设置到结果对象中
metaObject.setValue(mapping.property, value);
}
}
}
return foundValues;
}
// 根据 <resultMap> 节点中配置的映射关系进行映射
private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
// 获取该 ResultMap 中明确需要进行映射的列名集合
final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
boolean foundValues = false;
// 获取 ResultMap.propertyResultMappings 集合,其中记录了映射使用的所有 ResultMapping 对象
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
for (ResultMapping propertyMapping : propertyMappings) {
// 处理列前缀
String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
if (propertyMapping.getNestedResultMapId() != null) {
// the user added a column attribute to a nested result map, ignore it
// 该属性需要使用一个嵌套 ResultMap 进行映射,忽略 column 属性
column = null;
}
// 下面的逻辑主要处理三种场景
// 场景1:column是{prop1=col1,prop2=col2}这种形式的,一般与嵌套查询配合使用,表示将col1和col2的列值传递给内层嵌套查询作为参数
// 场景2:基本类型的属性映射
// 场景3:多结果集的场景处理,该属性来自于另一个结果集
if (propertyMapping.isCompositeResult() // 场景1
|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) // 场景2
|| propertyMapping.getResultSet() != null) { // 场景3
// 通过 getPropertyMappingValue 方法完成映射,并得到属性值
Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
// issue #541 make property optional
// 获取属性名称
final String property = propertyMapping.getProperty();
if (property == null) {
continue;
} else if (value == DEFERRED) {
// DEFERRED表示的是占位符对象
foundValues = true;
continue;
}
if (value != null) {
foundValues = true;
}
if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
// gcode issue #377, call setter on nulls (value is not 'found')
// 设置属性值
metaObject.setValue(property, value);
}
}
}
return foundValues;
}
// 嵌套查询, 加载出此字段的值; 多结果集: 直接返回占位符; 否则根据 typeHandler 来解析返回值
private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
// 嵌套查询
if (propertyMapping.getNestedQueryId() != null) {
return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
// 多结果集的处理
} else if (propertyMapping.getResultSet() != null) {
addPendingChildRelation(rs, metaResultObject, propertyMapping); // TODO is that OK?
// 返回占位符对象
return DEFERRED;
} else {
// 获取 ResultMapping 中记录的 TypeHandler 对象
final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
// 使用 TypeHandler 对象获取属性值
return typeHandler.getResult(rs, column);
}
}

org.apache.ibatis.reflection.MetaObject

元对象, 各种get,set方法类似ognl表达式的解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// MetaObject 的构造方法是 private 修饰的,只能通过 forObject 这个静态方法创建 MetaObject 对象
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
if (object == null) {
// 若 object 为 null ,则统一返回 SystemMetaObject.NULL_META_OBJECT
return SystemMetaObject.NULL_META_OBJECT;
} else {
return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}
}
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
// 初始化上述字段
this.originalObject = object;
this.objectFactory = objectFactory;
this.objectWrapperFactory = objectWrapperFactory;
this.reflectorFactory = reflectorFactory;

if (object instanceof ObjectWrapper) {
// 如果对象本身已经是 ObjectWrapper 型,则直接赋给 objectWrapper
this.objectWrapper = (ObjectWrapper) object;
} else if (objectWrapperFactory.hasWrapperFor(object)) {
// 若 ObjectWrapperFactory 能够为该原始对象创建对应的 ObjectWrapper 对象,则优先使用ObjectWrapperFactory,而
// DefaultObjectWrapperFactory.hasWrapperFor 始终返回 false,用户可以自定义ObjectWrapperFactory 实现进行扩展
this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
} else if (object instanceof Map) {
// 若原始对象为 map 对象,则创建 MapWrapper 对象
this.objectWrapper = new MapWrapper(this, (Map) object);
} else if (object instanceof Collection) {
// 若原始对象是 Collection 类型,则创建 CollectionWrapper 对象
this.objectWrapper = new CollectionWrapper(this, (Collection) object);
} else {
// 若原始对象是普通的 javaBean 对象,则创建 BeanWrapper 对象
this.objectWrapper = new BeanWrapper(this, object);
}
}
public Object getValue(String name) {
// 解析属性表达式
PropertyTokenizer prop = new PropertyTokenizer(name);
// 处理子表达式
if (prop.hasNext()) {
// 根据 PropertyTokenizer 解析后制定的属性,创建相应的 MetaObject 对象
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
// 如果上层就是 null 了,那就结束,返回 null
return null;
} else {
// 递归处理子表达式
return metaValue.getValue(prop.getChildren());
}
} else {
// 通过 ObjectWrapper 获取指定的属性值
return objectWrapper.get(prop);
}
}

// 设置值
public void setValue(String name, Object value) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
if (value == null) {
// 如果上层就是 null了,还得看有没有儿子,没有那就结束
// don't instantiate child path if value is null
return;
} else {
// 否则还得 new 一个,委派给 ObjectWrapper.instantiatePropertyValue
metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
}
}
// 递归调用 setValue
metaValue.setValue(prop.getChildren(), value);
} else {
// 到了最后一层了,所以委派给ObjectWrapper.set
objectWrapper.set(prop, value);
}
}

嵌套结果集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
// 创建 DefaultResultContext 对象
final DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
ResultSet resultSet = rsw.getResultSet();
// 定位到指定的记录行
skipRows(resultSet, rowBounds);
Object rowValue = previousRowValue;
// 检测是否能继续映射结果集中剩余的记录行
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
// 通过 resolveDiscriminatedResultMap 方法决定映射使用的 ResultMap 对象
final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
// 为该行记录生成 CacheKey
final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
// 根据 CacheKey 查找 nestedResultObjects 集合
Object partialObject = nestedResultObjects.get(rowKey);
// issue #577 && #542
// 检测 resultOrdered 属性
if (mappedStatement.isResultOrdered()) {
// 主结果对象发生变化
if (partialObject == null && rowValue != null) {
// 清空 nestedResultObjects 集合
nestedResultObjects.clear();
// 调用 storeObject 方法保存主结果对象
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
// 完成该行记录的映射返回结果对象,将结果对象添加到 nestedResultObjects 集合中
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
} else {
// 完成该行记录的映射返回结果对象,将结果对象添加到 nestedResultObjects 集合中
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
// 调用 storeObject 方法保存结果对象
if (partialObject == null) {
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
}
// 对 resultOrdered 属性为 true 时的特殊处理,调用 storeObject 方法保存结果对象
if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
previousRowValue = null;
} else if (rowValue != null) {
previousRowValue = rowValue;
}
}

游标结果集

定位: org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleCursorResultSets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling cursor results").object(mappedStatement.getId());

// 获取结果集并封装成 ResultSetWrapper 对象
ResultSetWrapper rsw = getFirstResultSet(stmt);

// 获取映射使用的 ResultMap 对象集合
List<ResultMap> resultMaps = mappedStatement.getResultMaps();

// 边界检测,只能映射一个结果集,所以只能存在一个 ResultMap 对象
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
if (resultMapCount != 1) {
throw new ExecutorException("Cursor results cannot be mapped to multiple resultMaps");
}
// 使用第一个 ResultMap 对象
ResultMap resultMap = resultMaps.get(0);
// 将 ResultSetWrapper 对象、映射使用的 ResultMap 对象一级控制映射的起止位置的 RowBounds 对象封装成 DefaultCursor 对象
return new DefaultCursor<>(this, resultMap, rsw, rowBounds);
}

默认游标

定位: org.apache.ibatis.cursor.defaults.DefaultCursor

在调用游标迭代器的 hasNext 或者 next 方法时,会将 ResultSet 中的列封装成实体对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
protected T fetchNextUsingRowBound() {
// 映射一行数据库记录,得到结果对象
T result = fetchNextObjectFromDatabase();
// 从结果集开始一条条记录映射,但是将RowBounds.offset之前的映射结果全部忽略
while (objectWrapperResultHandler.fetched && indexWithRowBound < rowBounds.getOffset()) {
result = fetchNextObjectFromDatabase();
}
return result;
}

protected T fetchNextObjectFromDatabase() {
// 检测当前右表对象是否关闭
if (isClosed()) {
return null;
}

try {
objectWrapperResultHandler.fetched = false;
// 更新游标状态
status = CursorStatus.OPEN;
if (!rsw.getResultSet().isClosed()) {
// 通过DefaultResultSetHandler.handleRowValues方法完成映射,
resultSetHandler.handleRowValues(rsw, resultMap, objectWrapperResultHandler, RowBounds.DEFAULT, null);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}

// 获取结果对象
T next = objectWrapperResultHandler.result;
if (objectWrapperResultHandler.fetched) {
// 统计返回的结果对象数量
indexWithRowBound++;
}
// No more object or limit reached
// 检测是否还存在需要映射的记录,如果没有,则关闭游标并修改状态
if (!objectWrapperResultHandler.fetched || getReadItemsCount() == rowBounds.getOffset() + rowBounds.getLimit()) {
// 关闭结果集以及对应的Statement对象
close();
status = CursorStatus.CONSUMED;
}
objectWrapperResultHandler.result = null;

// 返回结果对象
return next;
}
// org.apache.ibatis.cursor.defaults.DefaultCursor$CursorIterator
protected class CursorIterator implements Iterator<T> {
T object;
int iteratorIndex = -1;
public boolean hasNext() {
if (!objectWrapperResultHandler.fetched) {
object = fetchNextUsingRowBound();
}
return objectWrapperResultHandler.fetched;
}
public T next() {
// Fill next with object fetched from hasNext()
// 在 hasNext 方法也会调用 fetchNextUsingRowBound 方法,并将映射结果对象记录到 object 字段中
T next = object;
if (!objectWrapperResultHandler.fetched) {
// 对结果集进行映射的核心
next = fetchNextUsingRowBound();
}
if (objectWrapperResultHandler.fetched) {
objectWrapperResultHandler.fetched = false;
object = null;
// 记录返回结果对象的个数
iteratorIndex++;
return next;
}
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException("Cannot remove element from Cursor");
}
}

存储过程输出参数

定位: org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleOutputParameters

将存储过程中 OUT 参数结果设置到调用方的参数列表对象中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@Override
public void handleOutputParameters(CallableStatement cs) throws SQLException {
// 获取用户传入的实际参数,并为其创建相应的MetaObject对象
final Object parameterObject = parameterHandler.getParameterObject();
final MetaObject metaParam = configuration.newMetaObject(parameterObject);
// 获取 BoundSql.parameterMappings 集合,其中记录了参数相关信息
final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// 遍历所有参数信息
for (int i = 0; i < parameterMappings.size(); i++) {
final ParameterMapping parameterMapping = parameterMappings.get(i);
// 只处理 OUT|INOUT
if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
// 如果存在输出类型的参数,则解析参数值,并设置到 parameterObject 中
if (ResultSet.class.equals(parameterMapping.getJavaType())) {
// 如果指定该输出参数为 ResultSet 类型,则需要进行映射
handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
} else {
// 使用 TypeHandler 获取参数值,并设置到 parameterObject 中
final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
}
}
}
}

// 处理游标(OUT参数)
private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam) throws SQLException {
if (rs == null) {
return;
}
try {
// 获取映射使用的 ResultMap 对象
final String resultMapId = parameterMapping.getResultMapId();
final ResultMap resultMap = configuration.getResultMap(resultMapId);
// 将结果集封装成 ResultSetWrapper
final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
if (this.resultHandler == null) {
// 创建用于保存映射结果对象的 DefaultResultHandler 对象
final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
// 通过 handleRowValues 方法完成映射操作,并将结果对象保存到 DefaultResultHandler 中
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
// 将映射得到的结果对象保存到 parameterObject 中
metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
}
} finally {
// issue #228 (close resultsets)
closeResultSet(rs);
}
}

流程图

https://www.processon.com/view/link/655098457b996f7b645b6afe

更新

定位: org.apache.ibatis.session.defaults.DefaultSqlSession#update

1
2
3
4
5
6
7
8
9
10
11
12
13
public int update(String statement, Object parameter) {
try {
//每次要更新之前,dirty标志设为true
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
// 用执行器来update结果
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

org.apache.ibatis.executor.CachingExecutor#update

1
2
3
4
5
public int update(MappedStatement ms, Object parameterObject) throws SQLException {  
// 刷新二级缓存完再 update
flushCacheIfRequired(ms);
return delegate.update(ms, parameterObject);
}

org.apache.ibatis.executor.BaseExecutor#update

1
2
3
4
5
6
7
8
9
10
11
12
// SqlSession.update/insert/delete 都会调用此方法
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
// 判断当前Executor是否已经关闭
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 先清局部缓存(一级缓存),再更新,如何更新交由子类,模板方法模式
clearLocalCache();
// 执行sql语句
return doUpdate(ms, parameter);
}

org.apache.ibatis.executor.SimpleExecutor#doUpdate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// 新建一个 StatementHandler
// 这里看到 ResultHandler 传入的是 null
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 准备语句
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}

org.apache.ibatis.executor.statement.PreparedStatementHandler#update

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 调用 PreparedStatement.execute
ps.execute();
// 调用 PreparedStatement.getUpdateCount
int rows = ps.getUpdateCount();
// 获取实际入参
Object parameterObject = boundSql.getParameterObject();
// 若配置了 useGeneratedKeys 并且是 insert 语句,
// 则返回 Jdbc3KeyGenerator.INSTANCE, 否则返回 NoKeyGenerator.INSTANCE
// 若配置了 sekectKey, 则使用 SelectKeyGenerator 的实例
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
// 执行主键生成器的后置方法, 主要给入参设置对应的主键值
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
// 返回更新的行数
return rows;
}

插入

org.apache.ibatis.session.defaults.DefaultSqlSession#insert

1
2
3
4
5
6
7
8
9
@Override
public int insert(String statement) {
return insert(statement, null);
}
@Override
public int insert(String statement, Object parameter) {
// 调用更新
return update(statement, parameter);
}

PreparedStatementHandler 更新

定位: org.apache.ibatis.executor.statement.BaseStatementHandler#BaseStatementHandler

作用: 语句处理器的基类, 其子类有PreparedStatementHandler, SimpleStatementHandler, CallableStatementHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 初始化字段
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;

this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();

if (boundSql == null) { // issue #435, get the key before calculating the statement
// 调用 KeyGenerator.processBefore方法获取主键
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}

this.boundSql = boundSql;
// 生成 parameterHandler
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 生成 resultSetHandler
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
// 生成 key
protected void generateKeys(Object parameter) {
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
ErrorContext.instance().store();
// 调用主键生成器的前置方法
keyGenerator.processBefore(executor, mappedStatement, null, parameter);
ErrorContext.instance().recall();
}

org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator

主键生成器, 默认使用数据库的生成策略, 将生成后的主键赋值到入参对应的字段中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
// do nothing
}
@Override
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
// 将用户传入的实参 parameter 封装成集合类型,然后传入 processBatch 方法中处理
processBatch(ms, stmt, parameter);
}
public void processBatch(MappedStatement ms, Statement stmt, Object parameter) {
// 获取 keyProperties 属性指定的属性名称,它表示主键对应的属性名称
final String[] keyProperties = ms.getKeyProperties();
if (keyProperties == null || keyProperties.length == 0) {
return;
}
// 核心是使用 JDBC3 的 Statement.getGeneratedKeys
try (ResultSet rs = stmt.getGeneratedKeys()) {
// 获取ResultSet的元数据信息
final ResultSetMetaData rsmd = rs.getMetaData();
final Configuration configuration = ms.getConfiguration();
// 检测数据库生成的主键的列数与 keyProperties 属性指定的列数是否匹配
if (rsmd.getColumnCount() < keyProperties.length) {
// Error?
} else {
// 主键列的值赋值到入参对象中
assignKeys(configuration, rs, rsmd, keyProperties, parameter);
}
} catch (Exception e) {
throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);
}
}

删除

org.apache.ibatis.session.defaults.DefaultSqlSession#delete

1
2
3
4
5
6
7
8
9
@Override
public int delete(String statement) {
return update(statement, null);
}
@Override
public int delete(String statement, Object parameter) {
// delete 也是调用更新
return update(statement, parameter);
}

在使用 Mybatis 时, 需要通过 SqlSessionFactory 打开一个SqlSession, 然后实例化 Mapper 接口的动态代理对象, 执行数据库相关操作。

创建 SqlSessionFactory 对象

1
2
3
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>

在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来创建 SqlSessionFactorySqlSessionFactoryBean 实现了 Spring 的 FactoryBean 接口,Spring 将会在应用启动时为你创建 SqlSessionFactory,并使用 sqlSessionFactory 这个名字存储起来。

定位: org.mybatis.spring.SqlSessionFactoryBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
public class SqlSessionFactoryBean
implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
// Spring 初始化 bean 时, 会被调用
@Override
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
// configuration 和 configLocation 不能一起指定
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
// 初始化 SqlSessionFactory
this.sqlSessionFactory = buildSqlSessionFactory();
}
// 生成 SqlSessionFactory 对象
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
final Configuration targetConfiguration;
// 初始化 Configuration 全局配置对象
XMLConfigBuilder xmlConfigBuilder = null;
if (this.configuration != null) {
// 如果已存在 Configuration 对象
targetConfiguration = this.configuration;
if (targetConfiguration.getVariables() == null) {
targetConfiguration.setVariables(this.configurationProperties);
} else if (this.configurationProperties != null) {
targetConfiguration.getVariables().putAll(this.configurationProperties);
}
} else if (this.configLocation != null) {
// 配置了 mybatis-config.xml 配置文件
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
targetConfiguration = xmlConfigBuilder.getConfiguration();
} else {
LOGGER.debug(() -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
// 创建一个 Configuration 对象, 使用默认配置
targetConfiguration = new Configuration();
Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
}

/*
* 如果配置了 ObjectFactory(实例工厂)、ObjectWrapperFactory(ObjectWrapper工厂)、VFS(虚拟文件系统)
* 则分别往 Configuration 全局配置对象设置
*/Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);

/*
* 如果配置了需要设置别名的包路径,则扫描该包路径下的 Class 对象
* 往 Configuration 全局配置对象的 TypeAliasRegistry 别名注册表进行注册
*/
if (hasLength(this.typeAliasesPackage)) {
scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream()
// 过滤掉匿名类
.filter(clazz -> !clazz.isAnonymousClass())
// 过滤掉接口
.filter(clazz -> !clazz.isInterface())
// 过滤掉内部类
.filter(clazz -> !clazz.isMemberClass())
.forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);
}

/*
* 如果单独配置了需要设置别名的 Class 对象
* 则将其往 Configuration 全局配置对象的 TypeAliasRegistry 别名注册表注册
*/
if (!isEmpty(this.typeAliases)) {
Stream.of(this.typeAliases).forEach(typeAlias -> {
targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);
LOGGER.debug(() -> "Registered type alias: '" + typeAlias + "'");
});
}

// 往 Configuration 全局配置对象添加 Interceptor 插件
if (!isEmpty(this.plugins)) {
Stream.of(this.plugins).forEach(plugin -> {
targetConfiguration.addInterceptor(plugin);
LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");
});
}

// 扫描包路径,往 Configuration 全局配置对象添加 TypeHandler 类型处理器
if (hasLength(this.typeHandlersPackage)) {
scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass())
.filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
.forEach(targetConfiguration.getTypeHandlerRegistry()::register);
}

// 往 Configuration 全局配置对象添加 TypeHandler 类型处理器
if (!isEmpty(this.typeHandlers)) {
Stream.of(this.typeHandlers).forEach(typeHandler -> {
targetConfiguration.getTypeHandlerRegistry().register(typeHandler);
LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'");
});
}

// 设置默认的枚举类型处理器
targetConfiguration.setDefaultEnumTypeHandler(defaultEnumTypeHandler);

// 往 Configuration 全局配置对象添加 LanguageDriver 语言驱动
if (!isEmpty(this.scriptingLanguageDrivers)) {
Stream.of(this.scriptingLanguageDrivers).forEach(languageDriver -> {
targetConfiguration.getLanguageRegistry().register(languageDriver);
LOGGER.debug(() -> "Registered scripting language driver: '" + languageDriver + "'");
});
}
// 设置默认的 LanguageDriver 语言驱动
Optional.ofNullable(this.defaultScriptingLanguageDriver)
.ifPresent(targetConfiguration::setDefaultScriptingLanguage);

// 设置当前数据源的数据库 id
if (this.databaseIdProvider != null) {// fix #64 set databaseId before parse mapper xmls
try {
targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
} catch (SQLException e) {
throw new NestedIOException("Failed getting a databaseId", e);
}
}

// 添加 Cache 缓存
Optional.ofNullable(this.cache).ifPresent(targetConfiguration::addCache);

if (xmlConfigBuilder != null) {
try {
// 解析 xml 配置文件
xmlConfigBuilder.parse();
LOGGER.debug(() -> "Parsed configuration file: '" + this.configLocation + "'");
} catch (Exception ex) {
throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
} finally {
ErrorContext.instance().reset();
}
}

// 设置 Environment 环境信息
targetConfiguration.setEnvironment(new Environment(this.environment,
this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory,
this.dataSource));

if (this.mapperLocations != null) {
if (this.mapperLocations.length == 0) {
LOGGER.warn(() -> "Property 'mapperLocations' was specified but matching resources are not found.");
} else {
/*
* 配置了 XML 映射文件的路径, 遍历所有的 XML 映射文件
*/
for (Resource mapperLocation : this.mapperLocations) {
if (mapperLocation == null) {
continue;
}
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
// 解析 XML 映射文件
xmlMapperBuilder.parse();
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} finally {
ErrorContext.instance().reset();
}
LOGGER.debug(() -> "Parsed mapper file: '" + mapperLocation + "'");
}
}
} else {
LOGGER.debug(() -> "Property 'mapperLocations' was not specified.");
}

// 通过构造器创建一个 DefaultSqlSessionFactory 对象
return this.sqlSessionFactoryBuilder.build(targetConfiguration);
}
// Spring 事件监听
public void onApplicationEvent(ApplicationEvent event) {
// 需要快速失败,并且监听到了 Spring 容器初始化完成事件
if (failFast && event instanceof ContextRefreshedEvent) {
// fail-fast -> check all statements are completed
// 将 MyBatis 中还未完全解析的对象,在这里再进行解析
this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
}
}
// 扫描指定包下的指定子类或者子接口, 如果 assignableType 为空, 则返回这个包下的所有类
private Set<Class<?>> scanClasses(String packagePatterns, Class<?> assignableType) throws IOException {
Set<Class<?>> classes = new HashSet<>();
String[] packagePatternArray = tokenizeToStringArray(packagePatterns,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
for (String packagePattern : packagePatternArray) {
// 获取到 classpath 下包路径下的 Resource 对象
Resource[] resources = RESOURCE_PATTERN_RESOLVER.getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(packagePattern) + "/**/*.class");
for (Resource resource : resources) {
try {
// 获取 Resource 资源的 ClassMetadata 对象
ClassMetadata classMetadata = METADATA_READER_FACTORY.getMetadataReader(resource).getClassMetadata();
Class<?> clazz = Resources.classForName(classMetadata.getClassName());
if (assignableType == null || assignableType.isAssignableFrom(clazz)) {
classes.add(clazz);
}
} catch (Throwable e) {
LOGGER.warn(() -> "Cannot load the '" + resource + "'. Cause by " + e.toString());
}
}
}
return classes;
}
}

实例化 Mapper 接口

扫描 Mapper

通过定义 MapperScannerConfigurer 的 Spring bean 对象

1
2
3
4
5
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mybatis.spring.sample.mapper" />
<!-- 扫描被 Mapper 注解修饰的类(如果在 basePackage 包下存在非 Mapper 接口的文件, 并且不想要被代理, 则需要设置) -->
<property name="annotationClass" value="org.apache.ibatis.annotations.Mapper" />
</bean>
MapperScannerConfigurer

定位: org.mybatis.spring.mapper.MapperScannerConfigurer

作用:用于扫描 Mapper 接口,借助ClassPathMapperScanner扫描器注册 Mapper 接口的BeanDefinition 对象 (注意: 默认情况并没有设置 annotationClass )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class MapperScannerConfigurer
implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
/**
* 在 BeanDefinitionRegistry 完成后, 扫描 basePackage 下的类
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
// 处理属性中的占位符
processPropertyPlaceHolders();
}
// 创建一个 Bean 扫描器
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
// 是否要将 Mapper 接口添加到 Configuration 全局配置对象中
scanner.setAddToConfig(this.addToConfig);
// 如果 annotationClass 不为空,则扫描被 annotationClass 注解修饰的类
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
// 设置 SqlSessionFactory 的 BeanName
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
if (StringUtils.hasText(lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
}
if (StringUtils.hasText(defaultScope)) {
scanner.setDefaultScope(defaultScope);
}
// 会根据 annotationClass, markerInterface 生成过滤器
// 添加几个过滤器
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
}
ClassPathMapperScanner

定位: org.mybatis.spring.mapper.ClassPathMapperScanner

作用: 负责执行扫描,将用户配置信息,设置到扫描到的 Mapper 接口的 BeanDefinition 对象,如将 BeanClass 修改为 MapperFactoryBean,将 autowireMode 设置为根据类型注入,可以让 Spring 实例化的时候,会使用 MapperFactoryBean 类型,并自动注入 SqlSessionFactory 实例,实现创建 Mapper 动态代理对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
public void registerFilters() {
// 标记是否接受所有接口
boolean acceptAllInterfaces = true;
// if specified, use the given annotation and / or marker interface
// 如果配置了注解,则扫描有该注解的 Mapper 接口
if (this.annotationClass != null) {
addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
acceptAllInterfaces = false;
}
// override AssignableTypeFilter to ignore matches on the actual marker interface
// 如果配置了某个接口,则也需要扫描该接口
if (this.markerInterface != null) {
addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
@Override
protected boolean matchClassName(String className) {
return false;
}
});
acceptAllInterfaces = false;
}

if (acceptAllInterfaces) {
// default include filter that accepts all classes
// 如果上面两个都没有配置,则接受所有的类
addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
}

// exclude package-info.java
// 排除 package-info.java 文件
addExcludeFilter((metadataReader, metadataReaderFactory) -> {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
});
}
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 扫描指定包路径,根据上面的过滤器,获取到路径下 Class 对象的 BeanDefinition 对象
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

if (beanDefinitions.isEmpty()) {
LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
+ "' package. Please check your configuration.");
} else {
// 后置处理这些 BeanDefinition
processBeanDefinitions(beanDefinitions);
}

return beanDefinitions;
}

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
AbstractBeanDefinition definition;
// <1> 获取 BeanDefinition 注册表,然后开始遍历
BeanDefinitionRegistry registry = getRegistry();
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (AbstractBeanDefinition) holder.getBeanDefinition();
boolean scopedProxy = false;
if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {
// 获取被装饰的 BeanDefinition 对象
definition = (AbstractBeanDefinition) Optional
.ofNullable(((RootBeanDefinition) definition).getDecoratedDefinition())
.map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> new IllegalStateException(
"The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]"));
scopedProxy = true;
}
// <2> 获取对应的 Bean 的 Class 名称,也就是 Mapper 接口的 Class 对象
String beanClassName = definition.getBeanClassName();
LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
+ "' mapperInterface");

// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
// <3> 往构造方法的参数列表中添加一个参数,为当前 Mapper 接口的 Class 对象
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
/*
* <4> 修改该 Mapper 接口的 Class对象 为 MapperFactoryBean.class
* 这样一来当你注入该 Mapper 接口的时候,实际注入的是 MapperFactoryBean 对象,构造方法的入参就是 Mapper 接口
*/
definition.setBeanClass(this.mapperFactoryBeanClass);

// <5> 添加 addToConfig 属性
definition.getPropertyValues().add("addToConfig", this.addToConfig);

boolean explicitFactoryUsed = false;
// <6> 开始添加 sqlSessionFactory 或者 sqlSessionTemplate 属性
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
// 设置了 sqlSessionFactoryBeanName,则添加 sqlSessionFactory 对象的引用
definition.getPropertyValues().add("sqlSessionFactory",
new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
// 配置了 sqlSessionFactory 对象,则设置 sqlSessionFactory 属性值
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}

if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
// 如果上面已经清楚的使用了 SqlSessionFactory,则打印一个警告
LOGGER.warn(() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
// 配置了 sqlSessionTemplateBeanName,则添加 sqlSessionTemplate 对象的引用
definition.getPropertyValues().add("sqlSessionTemplate",
new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
LOGGER.warn(() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
// 配置了 sqlSessionTemplate 对象,则设置 sqlSessionTemplate 属性值
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}

/*
* 上面没有找到对应的 SqlSessionFactory,则设置通过类型注入
*/
if (!explicitFactoryUsed) {
LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
// Mapper 接口初始化中会自动根据类型注入 SqlSessionFactory 的实例
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}

definition.setLazyInit(lazyInitialization);

if (scopedProxy) {
// 已经封装过的则直接执行下一个
continue;
}

if (ConfigurableBeanFactory.SCOPE_SINGLETON.equals(definition.getScope()) && defaultScope != null) {
definition.setScope(defaultScope);
}
/*
* 如果不是单例模式,默认是
* 将 BeanDefinition 在封装一层进行注册
*/
if (!definition.isSingleton()) {
BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true);
if (registry.containsBeanDefinition(proxyHolder.getBeanName())) {
registry.removeBeanDefinition(proxyHolder.getBeanName());
}
registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());
}
}
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
// 必须是接口, 并且是顶级了或者内部类
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
}

通过注解 @MapperScan 扫描

使用例子:

1
2
3
4
@Configuration  
@MapperScan(value = "org.mybatis.spring.sample.mapper", annotationClass = Mapper.class)
public class AppConfig {
}
MapperScan 注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {

String[] value() default {};

String[] basePackages() default {};

Class<?>[] basePackageClasses() default {};

Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

Class<? extends Annotation> annotationClass() default Annotation.class;

Class<?> markerInterface() default Class.class;

String sqlSessionTemplateRef() default "";

String sqlSessionFactoryRef() default "";

Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;

String lazyInitialization() default "";

String defaultScope() default AbstractBeanDefinition.SCOPE_DEFAULT;
}
MapperScannerRegistrar

定位: org.mybatis.spring.annotation.MapperScannerRegistrar

作用: @MapperScann 的注册器,根据注解信息注册 MapperScannerConfigurer 对象,用于扫描 Mapper 接口

1
2
3
4
5
6
7
8
9
10
11
12
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) {
// 将 MapperScan 的注解信息封装成 MapperScannerConfigurer BeanDefinition 对象, 并注册到 Spring 中
registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
generateBaseBeanName(importingClassMetadata, 0));
}
}
}

通过 Mybatis-Spring 的 xml 配置(基本不用)

1
2
3
4
5
6
7
8
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
<mybatis:scan base-package="org.mybatis.spring.sample.mapper" />
</beans>

<mybatis:scan /> 的解析器 org.mybatis.spring.config.MapperScannerBeanDefinitionParser, 实现原理等同于 MapperScannerRegistrar, 解析 mybatis:scan 配置的标签信息并注册 MapperScannerConfigurer 对象

实例化 Mapper

MapperFactoryBean

定位: org.mybatis.spring.mapper.MapperFactoryBean

作用: 实现 FactoryBean 接口,继承 SqlSessionDaoSupport 抽象类,Mapper 接口对应 Spring Bean 对象,用于返回对应的动态代理对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
/**
* 继承了 DaoSupport 接口,它实现了 InitializingBean 接口
* 则在 Spring 容器中初始化该 Bean 的 afterPropertiesSet() 方法,也就调用该方法
*/
protected void checkDaoConfig() {
// 校验 sqlSessionTemplate 非空
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
/*
* 如果该 Mapper 接口没有被解析至 Configuration,则对其进行解析
*/
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
// 将该 Mapper 接口添加至 Configuration,会对该接口进行一系列的解析
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
throw new IllegalArgumentException(e);
} finally {
ErrorContext.instance().reset();
}
}
}
/**
* 在 Spring 容器中,注入当前 Bean 时调用该方法,也就是返回 Mapper 接口的动态代理对象(代理类为{@link org.apache.ibatis.binding.MapperProxy})
*/
public T getObject() throws Exception {
// getSqlSession() 方法返回 SqlSessionTemplate 对象
return getSqlSession().getMapper(this.mapperInterface);
}
}

SqlSessionDaoSupport

定位: org.mybatis.spring.support.SqlSessionDaoSupport

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSessionTemplate sqlSessionTemplate;
// 设置 DAO 使用的 MyBatis SqlSessionFactory, 并根据给定的 SqlSessionFactory 创建 SqlSessionTemplate 对象
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);
}
}
// 根据 sqlSessionFactory 创建 SqlSessionTemplate 对象
protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
// 显式设置 DAO 的 SqlSessionTemplate,作为指定 SqlSessionFactory 的替代方法
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
}

SqlSessionTemplate

SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSession。 SqlSessionTemplate 是线程安全的,可以被多个 DAO 或映射器所共享使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class SqlSessionTemplate implements SqlSession, DisposableBean {

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {

notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
notNull(executorType, "Property 'executorType' is required");

this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
// 创建一个 SqlSession 的动态代理对象,代理类为 SqlSessionInterceptor
this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class }, new SqlSessionInterceptor());
}
@Override
public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
return this.sqlSessionProxy.selectCursor(statement, parameter, rowBounds);
}
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
return this.sqlSessionProxy.selectList(statement, parameter, rowBounds);
}
@Override
public int update(String statement, Object parameter) {
return this.sqlSessionProxy.update(statement, parameter);
}
// 。。。
// 基本所有 SqlSession 接口的方法, 都由 sqlSessionProxy 来进行调用
// 。。。
@Override
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
}

// JDK 代理 Handler
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取 SqlSession 对象
SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
try {
// 执行 SqlSession 的方法
Object result = method.invoke(sqlSession, args);
// 当前 SqlSession 不是 Spring 托管的事务
if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
// 强制提交
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
// 关闭 SqlSession 会话,释放资源
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
// 对异常进行转换,差不多就是转换成 MyBatis 的异常
Throwable translated = SqlSessionTemplate.this.exceptionTranslator
.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
}

获取当前的 sqlSession

定位: org.mybatis.spring.SqlSessionUtils#getSqlSession

作用: 从当前线程变量中获取 SqlSession,如果不存在,则创建一个, 并将新创建的 SQL Session 添加到线程变量中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {

notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);

// 从 Spring 事务管理器中获取一个 SqlSessionHolder 对象
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
// 获取到 SqlSession 对象
SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
return session;
}
// 上面没有获取到,则创建一个 SqlSession
session = sessionFactory.openSession(executorType);
// 将上面创建的 SqlSession 封装成 SqlSessionHolder,往 Spring 事务管理器注册
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}
// 将 sqlSession 对象注册到当前线程变量中
private static void registerSessionHolder(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator, SqlSession session) {
SqlSessionHolder holder;
if (TransactionSynchronizationManager.isSynchronizationActive()) {
Environment environment = sessionFactory.getConfiguration().getEnvironment();
// <1> 如果使用 Spring 事务管理器
if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
LOGGER.debug(() -> "Registering transaction synchronization for SqlSession [" + session + "]");
// <1.1> 创建 SqlSessionHolder 对象
holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
// <1.2> 绑定到 TransactionSynchronizationManager 中
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
// <1.3> 创建 SqlSessionSynchronization 到 TransactionSynchronizationManager 中
TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
// <1.4> 设置同步
holder.setSynchronizedWithTransaction(true);
// <1.5> 增加计数
holder.requested();
} else {
// <2> 如果非 Spring 事务管理器,抛出 TransientDataAccessResourceException 异常
if (TransactionSynchronizationManager.getResource(environment.getDataSource()) == null) {
LOGGER.debug(() -> "SqlSession [" + session
+ "] was not registered for synchronization because DataSource is not transactional");
} else {
throw new TransientDataAccessResourceException(
"SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
}
}
} else {
LOGGER.debug(() -> "SqlSession [" + session
+ "] was not registered for synchronization because synchronization is not active");
}
}

SqlSession 和 Mapper 关系

在 Mybatis 中, 每次打开 openSession 后, 都会创建一个新的 SqlSession 实例, 在从 SqlSession 中获取 Mapper 实例时, 也会创建一个新的 Mapper 代理对象;

在 Mybatis-Spring 中, Mapper 的代理对象由 Spring 容器的 MapperFactoryBean 对象创建, 并且为单例的,每次调用 Mapper 的增删改查时,会先 openSession ( 创建一个新 SqlSession 实例) 后, 通过 ThreadLocal 来实现当前线程持有当前的 SqlSession 实例对象

Mybatis-Spring 事务托管

使用 MyBatis-Spring 的其中一个主要原因是它允许 MyBatis 参与到 Spring 的事务管理中。而不是给 MyBatis 创建一个新的专用事务管理器,MyBatis-Spring 借助了 Spring 中的 DataSourceTransactionManager 来实现事务管理。

一旦配置好了 Spring 的事务管理器,你就可以在 Spring 中按你平时的方式来配置事务。并且支持 @Transactional 注解和 AOP 风格的配置。在事务处理期间,一个单独的 SqlSession 对象将会被创建和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。

1
2
3
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>

编程式事务管理案例

1
2
3
4
5
6
7
8
9
10
11
12
13
public class UserService {
private final PlatformTransactionManager transactionManager;
public UserService(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void createUser() {
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(txStatus -> {
userMapper.insertUser(user);
return null;
});
}
}

链接

https://mybatis.org/spring/zh/index.html

mybatis-spring 注释源码

常用设计模式

单例模式

私有构造器, 对外提供实例方法

  • ErrorContext
  • LogFactory

构造者模式

封装复杂的创建对象的过程, 通过 build 方法生成对象实例

  • SqlSessionFactoryBuilder: 构建 SqlSessionFactory 对象
  • XMLConfigBuilder: 解析整个Mybatis的配置
  • XMLMapperBuilder:解析Mapper映射器
  • XMLStatementBuilder:解析增删改查标签
  • XMLScriptBuilder:解析动态SQL

工厂模式

通过工厂创建出具体的对象

  • SqlSessionFactory
  • MapperProxyFactory
  • DataSourceFactory

动态代理

Mybatis 中定义方法的时候使用的都是接口的方式,接口是不能进行实例化操作的,因此在使用具体对象的时候需要使用动态代理来创建出具体的代理对象 MapperProxy

装饰者模式

Cache 包下,Cache是一个接口,具体的子类实现是 PertualCache, 在 decorators 包下包含了一系列的其他实现,通过装饰者模式实现的(如:WeakCache / BlockingCache / LruCache / FifoCache)

组合模式

  • ChooseSqlNode
  • IfSqlNode

模板方法模式

Executor,BaseTypeHandler,IntegerTypeHandler…..

责任链模式

在 plugins 模块中,包含了 interceptor, interceptorChain

适配器模式

日志模块使用适配器模式,各个子包实现

迭代器模式

PropertyTokenizer

常用接口

HandlerMethodArgumentResolver

作用: 用于解析调用Controller层方法的参数

1
2
3
4
5
6
7
8
9
10
11
12
public interface HandlerMethodArgumentResolver {
/**
* 判断是否可以解析传入的参数
*/
boolean supportsParameter(MethodParameter parameter);
/**
* 实际解析参数
*/
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}

常用实现类

  1. ServletRequestMethodArgumentResolver / ServletResponseMethodArgumentResolver
    自动绑定 HttpServletRequest 和 HttpServletResponse
  2. RequestParamMapMethodArgumentResolver
    处理被 @RequestParam 修饰的参数
  3. RequestHeaderMapMethodArgumentResolver
    处理被 @RequestHeader 修饰的参数
  4. PathVariableMapMethodArgumentResolver
    处理被 @PathVariable 修饰的参数
  5. ModelAttributeMethodProcessor
    处理被 @ModelAttribute 修饰的参数
  6. RequestResponseBodyMethodProcessor
    处理被 @RequestBody 修饰的参数

HandlerMethodReturnValueHandler

作用: 处理处理器执行后的返回值,主要有三个功能:

  • 1、将相应的参数添加到model中
  • 2、设置view
  • 3、如果请求已经处理完, 则设置 ModelAndViewContainer 的 requestHandled 为 true
1
2
3
4
5
6
7
8
9
10
11
12
13
public interface HandlerMethodReturnValueHandler {

/**
* 判断是否支持
*/
boolean supportsReturnType(MethodParameter returnType);

/**
* 具体处理返回值
*/
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
  1. ModelAttributeMethodProcessor
    处理被 @ModelAttribute 修饰的方法
  2. RequestResponseBodyMethodProcessor
    处理被 @RequestBody 修饰的方法
  3. ViewMethodReturnValueHandler
    处理View类型返回值,如果是 redirect 类型则设置 mavContainer 的 redirectModelScenario

HttpMessageConverter

作用: 转换HTTP请求体和响应体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public interface HttpMessageConverter<T> {

/**
* 能否读取(处理请求体)
*/
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

/**
* 能够写入(处理响应体)
*/
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

/**
* 获取支持的 MediaType
*/
List<MediaType> getSupportedMediaTypes();

/**
* 读取请求体
*/
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;

/**
* 设置响应体
*/
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;

}

常用实现类

  1. ByteArrayHttpMessageConverter
  2. StringHttpMessageConverter
  3. ResourceHttpMessageConverter
  4. SourceHttpMessageConverter
  5. AllEncompassingFormHttpMessageConverter
  6. Jaxb2RootElementHttpMessageConverter
  7. MappingJackson2HttpMessageConverter

HandlerInterceptor

作用: Controller 层调用拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface HandlerInterceptor {
/**
* preHandler 方法是在 Controller 处理之前调用,SpringMVC 的拦截器是链式的,可以同时存在多个 Interceptor,
* 然后 SpringMVC 会根据声明的顺序执行。SpringMVC 拦截器的链式是可以中断的,
* 当 preHandler 的返回值是 false 时整个请求就结束了
*/
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
/**
* postHandle 在 Controller 方法调用之后,在 DispatcherServlet 进行视图渲染之前执行,
* 也就是说在这个方法中可以操作 ModelAndView,也可以在 DispatcherServlet 中看到调用拦截器的 postHandler 是传入了 ModelAndView 参数。
* 这个方法的链式结构和声明的顺序是相反的,也就是先声明拦截器反而后执行
*/
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
/**
* afterCompletion 在整个请求执行完之后执行,也就是 DispatcherServlet 视图渲染之后执行,这个方法主要作用是用于清理资源
*/
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}

常用实现类

  1. AbstractHandlerMapping.CorsInterceptor
    处理跨域请求
  2. UserRoleAuthorizationInterceptor
    检查当前用户的授权情况

常用注解

ControllerAdvice

作用:此注解的Controller是一个增强的Controller,主要有三个功能
– 全局异常处理
– 全局数据绑定
– 全局数据预处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@ControllerAdvice
public class ControllerAdviceController {
//全局异常处理
@ExceptionHandler(Exception.class)
public ModelAndView customerException(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("message", e.getMessage());
mv.setViewName("myerror");
return mv;
}
// 全局数据绑定
@ModelAttribute(name = "mock")
public Map<String, Object> mockData() {
HashMap<String, Object> map = new HashMap<>();
map.put("age", 99);
map.put("sex", "man");
return map;
}
// 全局数据预处理
@InitBinder("field")
public void defaultPrefix(WebDataBinder binder) {
binder.setFieldDefaultPrefix("field.");
}
}

ExceptionHandler

作用: 用于处理异常的注解。@ExceptionHandler是一个用于处理控制器中出现的异常的注解。它可以用于方法级别,用于指定处理控制器中出现的异常的方式。


SpringMVC 如何实现实现异步处理

原创文章

在 SpringMVC 中为了方便使用异步请求专门提供了 AsyncWebRequest 类型的 request,并且提供了处理异步请求的管理器 WebAsyncManager 和工具 WebAsyncUtils。

AsyncWebRequest:专门来处理异步请求的,会将原来的 HttpServletRequest 类型做一层封装

WebAsyncManager:SpringMVC 异步请求处理过程中最核心的类型,管理着整个异步处理的过程

WebAsyncUtils:异步工具类,用来获取 WebAsyncManager 以及创建 AsyncWebRequest 对象

在 SpringMVC 中,对异步请求的处理提供了四个地方的支持:

(1)FrameworkServlet 中给当前请求的 WebAsyncManager 添加了 CallableProcessingInterceptor 类型的拦截器->RequestBindingInterceptor,
目的是为了在请求处理前将当前请求的 LocaleContext 和 ServletRequestAttributes 设置到 LocaleContextHolder 和 RequestContextHolder 中,
并在请求处理完成后恢复,添加过程在 FrameworkServlet#processRequest 方法中:

1
2
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

(2)RequestMappingHandlerAdapter#invokeHandlerMethod 方法中提供了对异步请求的核心支持,其中做了时间跟异步处理相关的事情:

  • 创建 AsyncWebRequest,并设置了超时时间
  • 对当前请求的 WebAsyncManager 设置四个属性
  • 如果当前请求是异步请求而且已经处理出了结果,则将异步结果与之前保存到 WebAsyncManager 里的 ModelAndViewContainer 取出来,并将 WebAsyncManager 异步执行结果取出,然后调用 ServletInvocableHandlerMethod#wrapConcurrentResult 方法创建 ConcurrentResultHandlerMethod 子类来替换 ServletInvocableHandlerMethod,创建出来的 ConcurrentResultHandlerMethod 并不执行请求,主要是判断异步处理的结果是不是异常类型,如果是则抛出,如果不是则使用返回值处理器 HandlerMethodReturnValueHandler 对其进行解析并将处理后的结果返回
  • 如果 requestMappingMethod#invokeAndHandler 方法执行完成后检查到当前请求已经启动了异步处理,则会直接返回 null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 创建 AsyncWebRequest 异步请求对象
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);

// 创建 WebAsyncManager 异步请求管理器对象
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
// 如果当前异步请求已经处理并得到结果,则将返回的结果放到 mavContainer 对象中,然后将 invocable 对象进行包装转换,转成需要的执行对象然后开始执行
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
// 转换具体的invocable执行对象
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 执行调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}

(3)返回值处理器:一个有四个处理异步请求的返回值处理器,分别是 AsyncTaskMethodReturnValueHandler、CallableMethodReturnValueHandler、DeferredResultMethodReturnValueHandler、ListenableFutureReturnValueHandler,每一种对应一种类型的返回值,主要作用是使用 WebAsyncManager 启动异步处理.

(4)在 DispatcherServlet#doDispatcher 方法中,当 HandlerAdpater 使用 handler 处理完请求时,会检查是否已经启动了异步处理器,如果启动了则不再往下处理,直接返回。

1
2
3
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}

注意处理流程如下:首先在处理器中返回需要启动异步处理的类型时,相应的返回值处理器会调用 WebAsyncManager 相关方法启动异步处理,
然后再 DispatcherServlet 中将原来请求直接返回,当异步处理完成后会重新发出一个相同的请求,这个是在 RequestMappingAdapter 中会使用特殊的 ServletInvocableHandlerMethod 来处理请求,处理方法是:如果是异步处理返回的结果是异常类型则抛出异常,否则直接返回异常处理结果,然后使用返回值处理器对其处理,接着返回 DispatcherServlet 中按正常流程往下处理。

WebAsyncTask和Callable类型异步请求的处理过程及方法

当处理器方法返回WebAsyncTask或者Callable类型时将自动启用异步处理,使用WebAsyncTask类型返回值的处理器AsyncTaskMethodReturnValueHandler,如果返回值为null,就会给mavContainer设置为请求已处理,然后返回,如果返回值不为空,调用WebAsyncManager的startCallableProcessing方法处理请求

1
2
3
4
5
6
7
8
9
10
11
<servlet>
<servlet-name>mvc-test</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--SpringMVC配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@ResponseBody
@RequestMapping(value = "/web_async_task",produces = "text/plain; charset=UTF-8")
public WebAsyncTask<String> webAsyncTask(){
System.out.println("WebAsyncTask处理器主线程进入");
WebAsyncTask<String> task = new WebAsyncTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(5*1000L);
System.out.println("WebAsyncTask处理执行中。。。");
return "久等了";
}
});
System.out.println("WebAsyncTask处理器主线程退出");
return task;
}
@ResponseBody
@RequestMapping(value = "/callable",produces = "text/plain; charset=UTF-8")
public Callable<String> callable(){
System.out.println("Callable处理器主线程进入");
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(5 * 1000L);
System.out.println("Callable处理执行中。。。");
return "久等了";
}
};
System.out.println("Callable处理器主线程退出");
return callable;
}

DispatcherServlet#processDispatchResult

定位: org.springframework.web.servlet.DispatcherServlet#processDispatchResult

处理 ModelAndView; 或者将异常转换为 ModelAndView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {

// 标记是否为处理生成异常的ModelAndView对象
boolean errorView = false;

// 如果请求处理过程中有异常抛出则处理异常
if (exception != null) {
// 从ModelAndViewDefiningException中获得ModelAndView对象
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
// 处理异常,生成ModelAndView对象
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}

// Did the handler return a view to render?
// 是否进行页面渲染
if (mv != null && !mv.wasCleared()) {
// 渲染页面
render(mv, request, response);
// 清理请求中的错误消息属性
// 因为上述的情况中,processHandlerException会通过WebUtils设置错误消息属性,所以需要进行清理
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}

// 如果启动了异步处理则返回
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}

// 发出请求处理完成通知,触发Interceptor的afterCompletion
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}

DispatcherServlet#processHandlerException

定位: org.springframework.web.servlet.DispatcherServlet#processHandlerException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {

// Success and error responses may use different content types
// 移除 PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE 属性
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);

// Check registered HandlerExceptionResolvers...
// 遍历 HandlerExceptionResolver 数组,解析异常,生成 ModelAndView 对象
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
// 遍历 HandlerExceptionResolver 数组
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
// 解析异常,生成 ModelAndView 对象
exMv = resolver.resolveException(request, response, handler, ex);
// 生成成功,结束循环
if (exMv != null) {
break;
}
}
}
// 情况一,生成了 ModelAndView 对象,进行返回
if (exMv != null) {
// ModelAndView 对象为空,则返回 null
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
// We might still need view name translation for a plain error model...
// 没有视图则设置默认视图
if (!exMv.hasView()) {
String defaultViewName = getDefaultViewName(request);
if (defaultViewName != null) {
exMv.setViewName(defaultViewName);
}
}
// 打印日志
if (logger.isTraceEnabled()) {
logger.trace("Using resolved error view: " + exMv, ex);
}
else if (logger.isDebugEnabled()) {
logger.debug("Using resolved error view: " + exMv);
}
// 设置请求中的错误消息属性
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
// 未生成 ModelAndView 对象,则抛出异常
throw ex;
}

常见三种 HandlerAdapter

  • SimpleControllerHandlerAdapter 处理实现 Controller 接口的方法
  • HttpRequestHandlerAdapter 处理实现 HttpRequestHandler 接口的方法
  • RequestMappingHandlerAdapter 处理使用 @RequestMapping 注解的方法

SimpleControllerHandlerAdapter#handle

定位: org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter#handle

处理实现 Controller 接口的方法

1
2
3
4
5
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// Controller 类型的调用
return ((Controller) handler).handleRequest(request, response);
}

HttpRequestHandlerAdapter#handle

定位: org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter#handle

处理实现 HttpRequestHandler 接口的方法

1
2
3
4
5
6
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// HttpRequestHandler 类型的调用
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}

RequestMappingHandlerAdapter

定位: org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
定位: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal

处理实现 Controller 接口的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ModelAndView mav;
// 校验请求(HttpMethod 和 Session 的校验)
checkRequest(request);

// Execute invokeHandlerMethod in synchronized block if required.
// 如果synchronizeOnSession为true,则对session进行同步,否则不同步
if (this.synchronizeOnSession) {
// 同步相同 Session 的逻辑,默认情况false
HttpSession session = request.getSession(false);
if (session != null) {
// 获取Session的锁对象
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}

// 响应不包含'Cache-Control'头
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}

return mav;
}

RequestMappingHandlerAdapter#invokeHandlerMethod

定位: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod

构造 Controller 方法的参数和执行方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

// 使用request和response创建ServletWebRequest对象
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 创建WebDataBinderFactory对象,此对象用来创建WebDataBinder对象,进行参数绑定,
// 实现参数跟String之间的类型转换,ArgumentResolver在进行参数解析的过程中会用到WebDataBinder
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 创建ModelFactory对象,此对象主要用来处理model,主要是两个功能,1是在处理器具体处理之前对model进行初始化,2是在处理完请求后对model参数进行更新
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

// 创建ServletInvocableHandlerMethod对象,并设置其相关属性,实际的请求处理就是通过此对象来完成的,参数绑定、处理请求以及返回值处理都在里边完成
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 设置参数处理器
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 设置返回值处理器
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 设置参数绑定工厂对象
invocableMethod.setDataBinderFactory(binderFactory);
// 设置参数名称发现器
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

// 创建ModelAndViewContainer对象,用于保存model和View对象
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 将flashmap中的数据设置到model中
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 使用modelFactory将sessionAttributes和注释了@ModelAttribute的方法的参数设置到model中
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
// 根据配置对ignoreDefaultModelOnRedirect进行设置
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

// 创建AsyncWebRequest异步请求对象
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);

// 创建WebAsyncManager异步请求管理器对象
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}

// 执行调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 处理完请求后的后置处理,此处一共做了三件事,
// 1、调用ModelFactory的updateModel方法更新model,包括设置SessionAttribute和给Model设置BinderResult
// 2、根据mavContainer创建了ModelAndView
// 3、如果mavContainer里的model是RedirectAttributes类型,则将其设置到FlashMap
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
// 标记请求完成
webRequest.requestCompleted();
}
}

RequestMappingHandlerAdapter#getDataBinderFactory

定位: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDataBinderFactory

处理 @InitBinder 注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
Class<?> handlerType = handlerMethod.getBeanType();
// 检查当前Handler中的initBinder方法是否已经存在于缓存中
Set<Method> methods = this.initBinderCache.get(handlerType);
// 如果没有则查找并设置到缓冲中
if (methods == null) {
methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);// 将当前Controller中所有被@InitBinder注解修饰的方法都获取到
this.initBinderCache.put(handlerType, methods);
}
// 定义保存InitBinder方法的临时变量
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
// Global methods first
// 将所有符合条件的全局InitBinder方法添加到initBinderMethods
this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
Object bean = controllerAdviceBean.resolveBean();
for (Method method : methodSet) {
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
});
// 将当前handler中的initBinder方法添加到initBinderMethods
for (Method method : methods) {
// 创建当前方法对应的bean对象
Object bean = handlerMethod.getBean();
// 将method适配为可执行的invocableHandlerMethod
initBinderMethods.add(createInitBinderMethod(bean, method));
}
// 创建DataBinderFactory并返回
return createDataBinderFactory(initBinderMethods);
}

RequestMappingHandlerAdapter#getModelFactory

定位: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getModelFactory

处理 @ModelAttribute 注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
// 获取sessionAttributesHandler
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
// 获取处理器类的类型
Class<?> handlerType = handlerMethod.getBeanType();
// 获取处理器类中注释了@modelAttribute而且没有注释@RequestMapping的类型,第一个获取后添加到缓存,以后直接从缓存中获取
Set<Method> methods = this.modelAttributeCache.get(handlerType);
if (methods == null) {
methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
this.modelAttributeCache.put(handlerType, methods);
}
// 注释了@ModelAttribute的方法
List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
// Global methods first
// 先添加全局的@ModelAttribute方法,后添加当前处理器定义的@ModelAttribute方法
this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
Object bean = controllerAdviceBean.resolveBean();
for (Method method : methodSet) {
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
}
});
for (Method method : methods) {
Object bean = handlerMethod.getBean();
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
// 新建ModelFactory对象,此处需要三个参数,第一个是注释了@ModelAttribute的方法,第二个是WebDataBinderFactory,第三个是SessionAttributeHandler
return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}

ServletInvocableHandlerMethod#invokeAndHandle

定位: org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle

执行方法, 处理返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

// 调用父类的invokeForRequest执行请求
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 处理@ResponseStatus注解
setResponseStatus(webRequest);

// 处理返回值,判断返回值是否为空
if (returnValue == null) {
// request的NotModified为true,有@ResponseStatus,RequestHandled为true,三个条件有一个成立,则设置请求处理完成并返回
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
// 返回值不为null,@ResponseStatus存在reason,这是请求处理完成并返回
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}

// 前面都不成立,则设置RequestHandled为false即请求完成??????????
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 使用returnValueHandlers处理返回值
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
InvocableHandlerMethod#invokeForRequest

定位: org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest

执行方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

// 准备方法所需要的参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 具体调用method
return doInvoke(args);
}
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

// 获取方法的参数
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}

// 用于保存解析出参数的值
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
// 给parameter设置参数名解析器
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
// 如果相应类型的参数已经在providedArgs中提供了,则直接设置到parameter
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 使用argumentResolvers解析参数
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
// Leave stack trace for later, exception may actually be resolved and handled...
if (logger.isDebugEnabled()) {
String exMsg = ex.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw ex;
}
}
return args;
}
protected Object doInvoke(Object... args) throws Exception {
//强制方法可调用
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// 执行
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
}
HandlerMethodReturnValueHandlerComposite#handleReturnValue

定位: org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue

处理返回值

1
2
3
4
5
6
7
8
9
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 根据返回值确定 Handler
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

DispatcherServlet#checkMultipart

定位: org.springframework.web.servlet.DispatcherServlet#checkMultipart

检测请求是否为上传请求,如果是则通过 multipartResolver 将其封装成 MultipartHttpServletRequest 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
// 如果该请求是一个涉及到 multipart (文件)的请求
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
if (request.getDispatcherType().equals(DispatcherType.REQUEST)) {
logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
}
}
else if (hasMultipartException(request)) {
logger.debug("Multipart resolution previously failed for current request - " +
"skipping re-resolution for undisturbed error rendering");
}
else {
try {
// 将 HttpServletRequest 请求封装成 MultipartHttpServletRequest 对象,解析请求里面的参数以及文件
return this.multipartResolver.resolveMultipart(request);
}
catch (MultipartException ex) {
if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
logger.debug("Multipart resolution failed for error dispatch", ex);
// Keep processing error dispatch with regular request handle below
}
else {
throw ex;
}
}
}
}
// If not returned before: return original request.
return request;
}

DispatcherServlet#getHandler

定位: org.springframework.web.servlet.DispatcherServlet#getHandler
定位: org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 获得处理器(HandlerMethod或者HandlerExecutionChain),该方法是抽象方法,由子类实现
Object handler = getHandlerInternal(request);
// 获得不到,则使用默认处理器
if (handler == null) {
handler = getDefaultHandler();
}
// 还是获得不到,则返回 null
if (handler == null) {
return null;
}
// Bean name or resolved handler?
// 如果找到的处理器是String类型,则从Spring容器中找到对应的Bean作为处理器
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}

// 创建HandlerExecutionChain对象(包含处理器和拦截器)
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}

// 针对跨域请求的处理
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}

return executionChain;
}

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal

RequestMappingHandlerMapping 实现了 AbstractHandlerMethodMapping
RequestMappingHandlerMapping 处理添加 @RequestMapping 的 API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取访问的路径,一般类似于request.getServletPath(),返回不含contextPath的访问路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
// 获得读锁
this.mappingRegistry.acquireReadLock();
try {
// 获取HandlerMethod作为handler对象,这里涉及到路径匹配的优先级
// 优先级: 精确匹配>最长路径匹配>扩展名匹配
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// handlerMethod内部包含有bean对象,其实指的是对应的controller
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
// 释放读锁
this.mappingRegistry.releaseReadLock();
}
}

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
// Match数组,存储匹配上当前请求的结果(Mapping + HandlerMethod)
List<Match> matches = new ArrayList<>();
// 首先根据lookupPath获取到匹配条件
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// 将找到的匹配条件添加到matches
addMatchingMappings(directPathMatches, matches, request);
}
// 如果不能直接使用lookupPath得到匹配条件,则将所有匹配条件加入matches
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}

// 将包含匹配条件和handler的matches排序,并取第一个作为bestMatch,如果前面两个排序相同则抛出异常
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
// 创建MatchComparator对象,排序matches结果,排序器
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
// 获得首个Match对象,也就是最匹配的
bestMatch = matches.get(0);
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
// 比较bestMatch和secondBestMatch,如果相等,说明有问题,抛出IllegalStateException异常
// 因为,两个优先级一样高,说明无法判断谁更优先
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
// 处理首个Match对象
handleMatch(bestMatch.mapping, lookupPath, request);
// 返回首个Match对象的handlerMethod属性
return bestMatch.handlerMethod;
}
// 如果匹配不到,则处理不匹配的情况
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}

org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#getHandlerInternal

BeanNameUrlHandlerMapping 和 SimpleUrlHandlerMapping 实现了 AbstractUrlHandlerMapping
BeanNameUrlHandlerMapping 处理容器 bean 对象的名称为当前 url
eg: <bean name="/hello01" class="controller.HelloController01"/>
SimpleUrlHandlerMapping 处理通过配置设置到处理对象
eg:

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello02">helloController02</prop>
<prop key="/hello03">helloController03</prop>
</props>
</property>
</bean>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
// 截取用于匹配的URL有效路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
// 根据路径寻找handler,此处并不是直接从map中获取,很多handler都有通配符的写法,甚至有多个匹配项,此时需要做好选择
Object handler = lookupHandler(lookupPath, request);
// 如果找不到处理器,则使用rootHandler或defaultHandler处理器
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
Object rawHandler = null;
// 如果是根路径,则使用rootHandler处理器
if (StringUtils.matchesCharacter(lookupPath, '/')) {
// 如果请求的路径仅仅是“/”,那么使用RootHandler进行处理
rawHandler = getRootHandler();
}
// 如果无法找到handler,则使用默认的handler
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
// 如果找到的处理器是String类型,则从容器中找到该beanName对应的Bean作为处理器
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = obtainApplicationContext().getBean(handlerName);
}
// 空方法,校验处理器。目前暂无子类实现该方法
validateHandler(rawHandler, request);
// 创建处理器(HandlerExecutionChain对象)
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
return handler;
}

org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#lookupHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// Direct match?
// 直接根据url进行查找handler
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
// 如果找到的处理器是String类型,则从容器中找到该beanName对应的Bean作为处理器
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 空方法,校验处理器。目前暂无子类实现该方法
validateHandler(handler, request);
// 创建处理器
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}

// Pattern match?
// 通过表达式进行匹配具体通过antPathMatcher实现
List<String> matchingPatterns = new ArrayList<>();
// 情况二,Pattern匹配合适的,并添加到 matchingPatterns 中
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
// 路径通过Pattern匹配成功
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern + "/");
}
}
}

// 获得首个匹配(最优)的结果
String bestMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
// 排序
matchingPatterns.sort(patternComparator);
if (logger.isTraceEnabled() && matchingPatterns.size() > 1) {
logger.trace("Matching patterns " + matchingPatterns);
}
bestMatch = matchingPatterns.get(0);
}
if (bestMatch != null) {
// 获得bestMatch对应的处理器
handler = this.handlerMap.get(bestMatch);
if (handler == null) {
if (bestMatch.endsWith("/")) {
handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
}
// 如果获得不到,抛出IllegalStateException异常
if (handler == null) {
throw new IllegalStateException(
"Could not find handler for best pattern match [" + bestMatch + "]");
}
}
// Bean name or resolved handler?
// 如果找到的处理器是String类型,则从容器中找到该beanName对应的Bean作为处理器
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 空方法,校验处理器。目前暂无子类实现该方法
validateHandler(handler, request);
// 获得最匹配的路径
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);

// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
// for all of them
// 之前通过sort方法进行排序,然后拿第一个作为bestPatternMatch的,不过有可能有多个pattern的顺序相同,也就是sort方法返回0,这里就是处理这种情况
Map<String, String> uriTemplateVariables = new LinkedHashMap<>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (logger.isTraceEnabled() && uriTemplateVariables.size() > 0) {
logger.trace("URI variables " + uriTemplateVariables);
}
// 创建处理器
return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
}

// No handler found...
return null;
}

org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 创建 HandlerExecutionChain 对象
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

// 获得请求路径
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
// 遍历 adaptedInterceptors 数组,获得请求匹配的拦截器
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 需要匹配,若路径匹配,则添加到 chain 中
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
// 无需匹配,直接添加到 chain 中
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}

DispatcherServlet#getHandlerAdapter

定位: org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter

1
2
3
4
5
6
7
8
9
10
11
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

HandlerExecutionChain#applyPreHandle

定位: org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 获取拦截器数组,然后循环调用执行preHandle, interceptorIndex 这个变量设计的比较巧妙,
* 假设现在有3个拦截器,第3个拦截器的 preHandler 返回 false,那么 interceptorIndex 此时为1,会执行 triggerAfterCompletion 方法
* 第1个开始往前 大于等于0的拦截器对应上面的例子就是第2和3的拦截器的afterCompletion方法会执行
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取拦截器数组
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// 遍历拦截器数组
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
// 前置处理
if (!interceptor.preHandle(request, response, this.handler)) {
// 已完成处理拦截器
triggerAfterCompletion(request, response, null);
// 返回false,前置处理失败
return false;
}
// 标记interceptorIndex位置
this.interceptorIndex = i;
}
}
return true;
}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
// 获得拦截器数组
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// 遍历拦截器数组,倒序
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
// 已完成处理拦截器
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
// 如果执行失败,仅仅会打印错误日志,不会结束循环
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
0%