源码分析-Mybatis源码阅读-Mapper代理

源码解析-Mybatis
01 源码分析-Mybatis源码阅读准备
02 源码分析-Mybatis源码阅读-会话层
03 源码分析-Mybatis源码阅读-执行器
04 源码分析-Mybatis源码阅读-Statement语句处理器
05 源码分析-Mybatis源码阅读-参数处理器
06 源码分析-Mybatis源码阅读-结果集处理器
07 源码分析-Mybatis源码阅读-主键生成器
08 源码分析-Mybatis源码阅读-懒加载机制
09 源码分析-Mybatis源码阅读-游标
10 源码分析-Mybatis源码阅读-类型处理器
11 源码分析-Mybatis源码阅读-缓存
12 源码分析-Mybatis源码阅读-Mapper代理

一 Mapper代理类说明

Mapper代理类的相关代码,主要在org.apache.ibatis.bind绑定包中,以下是该包下所有类的说明:

1
2
3
4
5
6
7
8
9
10
.
└── org
└── apache
└── ibatis
└── binding
   ├── BindingException.java 绑定异常
   ├── MapperMethod.java 映射方法
   ├── MapperProxy.java 映射器代理
   ├── MapperProxyFactory.java 映射代理器工厂类
   └── MapperRegistry.java 映射器注册器

这几个类的UML图如下:

image-20210611182610433

二 Mapper代理类源码解读

MapperRegistry

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
/**
* 映射器注册器
* @author Clinton Begin
* @author Eduardo Macarron
* @author Lasse Voss
*/
public class MapperRegistry {

/** Mybatis全局配置信息 */
private final Configuration config;
/** 已注册的映射器接口类映射,key=>映射器接口类,value=>映射代理器工厂 */
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

/**
* @param config Mybatis全局配置信息
*/
public MapperRegistry(Configuration config) {
this.config = config;
}

/**
* 获取映射器
* @return
*/
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 获取type对应的映射代理器工厂
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
// 如果映射代理器工厂为null
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
// 创建type代理对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}

/**
* 判断是否已经进行注册该类
* <p>
* 从{@link #knownMappers}进行判断。
* </p>
* @param type Mapper.xml对应的接口类
* @return 如果{@code type} 存在knownMappers中,返回true;否则返回false
*/
public <T> boolean hasMapper(Class<T> type) {
return knownMappers.containsKey(type);
}

/**
* 将 Mapper.xml对应的接口类 加入到knownMapper中
* @param type Mapper.xml对应的接口类
*/
public <T> void addMapper(Class<T> type) {
// 只有接口才会进行注册
if (type.isInterface()) {
// 如果在knownMappers已经找到了对应的type,将抛出异常
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
// 已加载完成标记
boolean loadCompleted = false;
try {
// 将type和对应的映射代理器工厂添加到knowMappers中
knownMappers.put(type, new MapperProxyFactory<>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
/*
* 在解析器运行之前添加 type 到 knownMappers 很重要,
* 否则映射器解析器可能会自动尝试绑定。
* 如果类型已知,则不会尝试。
*/
// 新建一个 映射器注解构建器
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
/*
* 解析映射接口类,解析mapper标签下的所有方法和注解,并对解析出来的信息加以封装,
* 然后添加到Mybatis全局配置信息中。然后重新解析Mybatis全局配置信息中未能完成解析的Method重新解析
*/
parser.parse();
// 设置已加载完成标记为true
loadCompleted = true;
} finally {
// 如果未能完成加载的接口映射类
if (!loadCompleted) {
// 从knownMappers中移除接口映射类
knownMappers.remove(type);
}
}
}
}

/**
* 获取已注册的映射接口类集合
* Gets the mappers.
*
* @return the mappers
* @since 3.2.2
*/
public Collection<Class<?>> getMappers() {
return Collections.unmodifiableCollection(knownMappers.keySet());
}

/**
* 添加映射器
* Adds the mappers.
*
* @param packageName
* the package name
* @param superType
* the super type
* @since 3.2.2
*/
public void addMappers(String packageName, Class<?> superType) {
// ResolverUtil:用于查找在类路径可用并满足任意条件的类。
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
// 查找在packageName下的superType的子类
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
// 获取匹配的类集合
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
// 遍历映射类集合
for (Class<?> mapperClass : mapperSet) {
// 将 映射接口类 加入到knownMappper中
addMapper(mapperClass);
}
}

/**
* 添加映射器
* Adds the mappers.
*
* @param packageName
* the package name
* @since 3.2.2
*/
public void addMappers(String packageName) {
addMappers(packageName, Object.class);
}

}

MapperProxyFactory

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
/**
* 映射代理器工厂类
* @author Lasse Voss
*/
public class MapperProxyFactory<T> {

/** 映射器接口类 */
private final Class<T> mapperInterface;
/** 方法缓存Map,映射接口类方法对象-映射方法类对象 */
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();

public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}

/**
* 获取映射接口类
* @return {@link #mapperInterface}
*/
public Class<T> getMapperInterface() {
return mapperInterface;
}

/**
* 方法缓存Map,映射接口类方法对象-映射方法类对象
* @return {@link #mapperInterface}
*/
public Map<Method, MapperMethodInvoker> getMethodCache() {
return methodCache;
}

/**
* 创建mapperInterface代理对象
* @param mapperProxy 映射代理器对象
* @return mapperInterface代理对象
*/
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

/**
* 创建mapperInterface代理对象
* @param sqlSession 数据库对话对象
* @return
*/
public T newInstance(SqlSession sqlSession) {
// 新建mapperInterface的 映射代理器对象
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
// 创建mapperInterface代理对象
return newInstance(mapperProxy);
}

}

MapperProxy

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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/**
* 映射器代理
* @author Clinton Begin
* @author Eduardo Macarron
*/
public class MapperProxy<T> implements InvocationHandler, Serializable {

private static final long serialVersionUID = -4724728412955527868L;
/** 允许的模式 */
private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
| MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC;
/** Lookup的构造 只当privateLookupIn方法不存在是 该属性才会有值 */
private static final Constructor<Lookup> lookupConstructor;
/** privateLookupIn方法 该方法从jdk9之后才有的 */
private static final Method privateLookupInMethod;
/** 数据库会话对象 */
private final SqlSession sqlSession;
/** 映射器接口类 */
private final Class<T> mapperInterface;
/** 方法缓存Map,映射接口类方法对象-映射方法类对象 */
private final Map<Method, MapperMethodInvoker> methodCache;

/**
* @param sqlSession 数据库会话对象
* @param mapperInterface 映射器接口类
* @param methodCache 方法缓存Map,映射接口类方法对象-映射方法类对象
*/
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}

static {
Method privateLookupIn;
try {
// 获取 privateLookupIn方法 该方法从jdk9之后才有的
privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
} catch (NoSuchMethodException e) {
privateLookupIn = null;
}
// 赋值给对象属性
privateLookupInMethod = privateLookupIn;

Constructor<Lookup> lookup = null;
// 如果 privateLookupIn 方法不存在
if (privateLookupInMethod == null) {
// JDK 1.8
try {
// 获取 Lookup 构造
lookup = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
// Lookup 构造设置为可访问
lookup.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(
"There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.",
e);
} catch (Exception e) {
lookup = null;
}
}
// 赋值 Lookup构造 给对象属性
lookupConstructor = lookup;
}

/**
* 代理方法回调
* @param proxy 代理后的实例对象
* @param method 对象被调用方法
* @param args 调用时的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// Method.getDeclaringClass:返回声明的该方法的类
// 如果声明method的类是Object
if (Object.class.equals(method.getDeclaringClass())) {
// 直接执行
return method.invoke(this, args);
} else {
// 先获取到方法调用者再执行invoke
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}

/**
* 获取方法调用者
* @param method
* @return
* @throws Throwable
*/
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
try {
return MapUtil.computeIfAbsent(methodCache, method, m -> {
// Method.isDefault:如果此方法是默认方法,则返回true ; 返回false其他 默认方法是公共非抽象实例方法,即具有主体的非静态方法,以接口类型声明
// 如果method是默认方法(默认方法是在接口中声明的公共非抽象实例方法)
if (m.isDefault()) {
try {
// 不存在privateLookupIn方法 则使用 java8的方法句柄实现
if (privateLookupInMethod == null) {
return new DefaultMethodInvoker(getMethodHandleJava8(method));
// 存在则用java9的方法句柄实现
} else {
return new DefaultMethodInvoker(getMethodHandleJava9(method));
}
} catch (IllegalAccessException | InstantiationException | InvocationTargetException
| NoSuchMethodException e) {
throw new RuntimeException(e);
}
} else {
// 默认返回普通方法调用者
return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
});
} catch (RuntimeException re) {
Throwable cause = re.getCause();
throw cause == null ? re : cause;
}
}

/**
* 获取方法句柄 - java9
* @param method
* @return
* @throws NoSuchMethodException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private MethodHandle getMethodHandleJava9(Method method)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
// 获取声明method的类
final Class<?> declaringClass = method.getDeclaringClass();
/*
* privateLookupIn 方法 说明
* 返回一个 {@link Lookup 查找对象},具有模拟所有支持的字节码行为的完整功能,包括在目标类上的<a href="MethodHandles.Lookup.htmlprivacc">私有访问<a>。
* 此方法检查是否允许指定为 {@code Lookup} 对象的调用者对目标类进行<em>深度反射<em>。
* 如果 {@code m1} 是包含 {@link LookuplookupClass() 查找类} 的模块,而 {@code m2} 是包含目标类的模块,则此检查确保
* <ul>
* <li>{@code m1 } {@link ModulecanRead 读取} {@code m2}.<li>
* <li>{@code m2} {@link ModuleisOpen(String,Module) opens}包含目标类的包至少为{@code m1}。 <li>
* <li>查找有{@link LookupMODULE MODULE}查找模式。<li>
* <ul>
* 如果有安全管理器,则调用其{@code checkPermission}方法检查{@code ReflectPermission ("suppressAccessChecks")}。
* @apiNote {@code MODULE} 查找模式用于验证查找对象是由调用者模块中的代码创建的(或派生自最初由调用者创建的查找对象)。
* 具有 {@code MODULE} 查找模式的查找对象可以与受信任方共享,而无需向调用方提供 {@code PRIVATE} 和 {@code PACKAGE} 访问权限。
* @param targetClass 目标类
* @param lookup 调用者查找对象
*/
return ((Lookup) privateLookupInMethod.invoke(null, declaringClass, MethodHandles.lookup())).findSpecial(
declaringClass, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()),
declaringClass);
}

/**
* 获取方法句柄 - java8
* @param method
* @return
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
*/
private MethodHandle getMethodHandleJava8(Method method)
throws IllegalAccessException, InstantiationException, InvocationTargetException {
// 获取声明method的类
final Class<?> declaringClass = method.getDeclaringClass();
/*
* constructor.newInstance(declaringClass,
* MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
* | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
* :通过constructor构建MethodHandles.Lookup实例对象
* MethodHandles.Lookup.unreflectSpecial:生成可以调用反射方法【declaringClass的method】的方法处理器
* MethodHandle.bindTo(proxy):绑定需要反射方法的对象
* MethodHandle.invokeWithArguments:传入args,反射方法
*/
return lookupConstructor.newInstance(declaringClass, ALLOWED_MODES).unreflectSpecial(method, declaringClass);
}

/**
* 映射方法调用者接口
*/
interface MapperMethodInvoker {
/**
* 执行方法
* @param proxy 代理后的实例对象
* @param method 对象被调用方法
* @param args 调用方法的参数
* @param sqlSession 数据库会话对象
* @return
* @throws Throwable
*/
Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable;
}

/**
* 普通方法调用者
*/
private static class PlainMethodInvoker implements MapperMethodInvoker {
private final MapperMethod mapperMethod;

public PlainMethodInvoker(MapperMethod mapperMethod) {
super();
this.mapperMethod = mapperMethod;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
return mapperMethod.execute(sqlSession, args);
}
}

/**
* 默认方法调用者
*/
private static class DefaultMethodInvoker implements MapperMethodInvoker {
private final MethodHandle methodHandle;

public DefaultMethodInvoker(MethodHandle methodHandle) {
super();
this.methodHandle = methodHandle;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
/*
* MethodHandle.bindTo(proxy):绑定需要反射方法的对象
* MethodHandle.invokeWithArguments:传入args,反射方法
*/
return methodHandle.bindTo(proxy).invokeWithArguments(args);
}
}
}

MapperMethod

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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
/**
* 映射方法
* @author Clinton Begin
* @author Eduardo Macarron
* @author Lasse Voss
* @author Kazuki Shimizu
*/
public class MapperMethod {

/** SQL命令 */
private final SqlCommand command;
/** 方法签名 */
private final MethodSignature method;

public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}

public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}

private Object rowCountResult(int rowCount) {
final Object result;
if (method.returnsVoid()) {
result = null;
} else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
result = rowCount;
} else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
result = (long) rowCount;
} else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
result = rowCount > 0;
} else {
throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
}
return result;
}

private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
if (!StatementType.CALLABLE.equals(ms.getStatementType())
&& void.class.equals(ms.getResultMaps().get(0).getType())) {
throw new BindingException("method " + command.getName()
+ " needs either a @ResultMap annotation, a @ResultType annotation,"
+ " or a resultType attribute in XML so a ResultHandler can be used as a parameter.");
}
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
} else {
sqlSession.select(command.getName(), param, method.extractResultHandler(args));
}
}

private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.selectList(command.getName(), param, rowBounds);
} else {
result = sqlSession.selectList(command.getName(), param);
}
// issue #510 Collections & arrays support
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}

private <T> Cursor<T> executeForCursor(SqlSession sqlSession, Object[] args) {
Cursor<T> result;
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.selectCursor(command.getName(), param, rowBounds);
} else {
result = sqlSession.selectCursor(command.getName(), param);
}
return result;
}

private <E> Object convertToDeclaredCollection(Configuration config, List<E> list) {
Object collection = config.getObjectFactory().create(method.getReturnType());
MetaObject metaObject = config.newMetaObject(collection);
metaObject.addAll(list);
return collection;
}

@SuppressWarnings("unchecked")
private <E> Object convertToArray(List<E> list) {
Class<?> arrayComponentType = method.getReturnType().getComponentType();
Object array = Array.newInstance(arrayComponentType, list.size());
if (arrayComponentType.isPrimitive()) {
for (int i = 0; i < list.size(); i++) {
Array.set(array, i, list.get(i));
}
return array;
} else {
return list.toArray((E[]) array);
}
}

private <K, V> Map<K, V> executeForMap(SqlSession sqlSession, Object[] args) {
Map<K, V> result;
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.selectMap(command.getName(), param, method.getMapKey(), rowBounds);
} else {
result = sqlSession.selectMap(command.getName(), param, method.getMapKey());
}
return result;
}

public static class ParamMap<V> extends HashMap<String, V> {

private static final long serialVersionUID = -2212268410512043556L;

@Override
public V get(Object key) {
if (!super.containsKey(key)) {
throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + keySet());
}
return super.get(key);
}

}

/**
* SQL命令
* <p>
* 通过mapperInterface+ method 找到的 MapperStatement对象,保存着MapperStatement对象的Id和SqlCommandType
* </p>
*/
public static class SqlCommand {

/** 通过mapperInterface+ method 找到的 MapperStatement对象的Id */
private final String name;
/** 通过mapperInterface+ method 找到的 MapperStatement对象的SQL脚本类型 */
private final SqlCommandType type;

/**
*
* @param configuration Mybatis全局配置信息
* @param mapperInterface 映射器接口类
* @param method 方法对象
*/
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
// 获取方法名
final String methodName = method.getName();
// 获取声明method的类
final Class<?> declaringClass = method.getDeclaringClass();
// 获取 mapperInterface+ methodName 对应的 MappedStatement对象
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
// 如果ms对象为null
if (ms == null) {
// 如果method加上了Flush注解
if (method.getAnnotation(Flush.class) != null) {
// 将 通过mapperInterface+ method 找到的 MapperStatement对象的Id 置为null
name = null;
// Sql命令类型设置成FLUSH
type = SqlCommandType.FLUSH;
// 如果没有加上Flush注解则抛出异常
} else {
throw new BindingException("Invalid bound statement (not found): "
+ mapperInterface.getName() + "." + methodName);
}
} else {
// 设置 通过mapperInterface+ method 找到的 MapperStatement对象的Id
name = ms.getId();
// 设置 ms的Sql命令类型
type = ms.getSqlCommandType();
// 如果ms的Sql命令类型为 UNKNOWN 则抛出异常
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}

public String getName() {
return name;
}

public SqlCommandType getType() {
return type;
}

/**
* 获取 {@code mapperInterface} + {@code methodName} 对应的 MappedStatement对象
* @param mapperInterface 映射器接口类
* @param methodName 方法名
* @param declaringClass 声明method的类
* @param configuration Mybatis全局配置信息
* @return {@code mapperInterface} + {@code methodName} 对应的 MappedStatement对象
*/
private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
Class<?> declaringClass, Configuration configuration) {
// 拼装statementId,取映射器接口包名+类名+'.'+方法名
String statementId = mapperInterface.getName() + "." + methodName;
// 如果存在statementId对应的MappedStatement对象
if (configuration.hasStatement(statementId)) {
// 取出对应statementId的MappedStatement对象,并返回
return configuration.getMappedStatement(statementId);
// 如果映射器接口类等于声明method的类
} else if (mapperInterface.equals(declaringClass)) {
// 直接返回null
return null;
}
// 遍历映射器接口类继承的所有接口
for (Class<?> superInterface : mapperInterface.getInterfaces()) {
// 如果声明method的类是superInterface的父类
if (declaringClass.isAssignableFrom(superInterface)) {
// 递归获取 superInterface + methodName 对应的 MappedStatement对象
MappedStatement ms = resolveMappedStatement(superInterface, methodName,
declaringClass, configuration);
// 如果ms不为null
if (ms != null) {
return ms;
}
}
}
// 从继承的接口中去找都找不到时,就返回null
return null;
}
}

/**
* 方法签名,封装着方法的返回类型的各个情况描述,指定类型的参数索引位置,以及参数名解析器
*/
public static class MethodSignature {

/** 如果返回类型为Collection的子类或者返回类型是数组,returnsMany为true */
private final boolean returnsMany;
/** 如果 {@link #mapKey} 不为null,returnMap为true */
private final boolean returnsMap;
/** 如果返回类型为Void,returnsVoid为true */
private final boolean returnsVoid;
/** 如果返回类型为Cursor类型,returnCursor为true */
private final boolean returnsCursor;
/** 如果返回类型为Optional类型,returnsOptional为true */
private final boolean returnsOptional;
/** 方法的返回类型 */
private final Class<?> returnType;
/** 只有当method的返回类型为Map,且有加上MapKey注解,就返回MapKey注解所定义的值;否则返回null */
private final String mapKey;
/** resultHandler类型参数在方法中索引位置 */
private final Integer resultHandlerIndex;
/** rowBounds类型参数在方法中索引位置 */
private final Integer rowBoundsIndex;
/** 参数名解析器: 参数名称解析器,用于构建sql脚本参数名+参数对象映射集合 */
private final ParamNameResolver paramNameResolver;

/**
*
* @param configuration Mybatis全局配置信息
* @param mapperInterface 映射器接口类
* @param method 方法对象
*/
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
// 获取method在mapperInterface中的返回类型
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
// 如果返回类型为Class实例
if (resolvedReturnType instanceof Class<?>) {
// 将返回类型强转为Class类型,赋值给returnType
this.returnType = (Class<?>) resolvedReturnType;
// 参数化类型说明 参考: https://blog.csdn.net/JustBeauty/article/details/81116144
// 如果返回类型为参数化类型,参数化类型
} else if (resolvedReturnType instanceof ParameterizedType) {
// 将返回类型强转为ParameterizedType类型,然后取出声明的类型,如List<T>,getRawType得到的就是List,然后强转声明类型为Class类型,赋值给returnType
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
// 取出方法的返回类型
this.returnType = method.getReturnType();
}
// 如果返回类型为Void,returnsVoid为true
this.returnsVoid = void.class.equals(this.returnType);
// 如果返回类型为Collection的子类或者返回类型是数组,returnsMany为true
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
// 如果返回类型为Cursor类型,returnCursor为true
this.returnsCursor = Cursor.class.equals(this.returnType);
// 如果返回类型为Optional类型,returnsOptional为true
this.returnsOptional = Optional.class.equals(this.returnType);
// 有当method的返回类型为Map,且有加上MapKey注解,就返回MapKey注解所定义的值;否则返回null
this.mapKey = getMapKey(method);
// 如果mapKey不为null,returnMap为true
this.returnsMap = this.mapKey != null;
// 获取RowBounds.class 在 method 的参数类型数组中的唯一位置,赋值给rowBoundsIndex
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
// 获取ResultHandler.class 在 method 的参数类型数组中的唯一位置,赋值给rowBoundsIndex
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
// 新建一个参数名解析器: 参数名称解析器,用于构建sql脚本参数名+参数对象映射集合
this.paramNameResolver = new ParamNameResolver(configuration, method);
}

/**
* 将参数对象转换为sql脚本参数,返回sql脚本参数名-参数对象映射集合;
* @param args 参数对象数值
* @return sql脚本参数名-参数对象映射集合
*/
public Object convertArgsToSqlCommandParam(Object[] args) {
return paramNameResolver.getNamedParams(args);
}

/**
* 是否存在RowRounds类型参数
* @return 存在返回true;否则返回false
*/
public boolean hasRowBounds() {
return rowBoundsIndex != null;
}

/**
* 提取RowBounds对象
* @param args 参数对象数组
* @return RowBounds对象
*/
public RowBounds extractRowBounds(Object[] args) {
return hasRowBounds() ? (RowBounds) args[rowBoundsIndex] : null;
}

/**
* 是否存在ResultHandler类型参数
* @return 存在返回true;否则返回false
*/
public boolean hasResultHandler() {
return resultHandlerIndex != null;
}

/**
* 提取ResultHandler对象
* @param args 参数对象数组
* @return ResultHandler对象
*/
public ResultHandler extractResultHandler(Object[] args) {
return hasResultHandler() ? (ResultHandler) args[resultHandlerIndex] : null;
}

public Class<?> getReturnType() {
return returnType;
}

public boolean returnsMany() {
return returnsMany;
}

public boolean returnsMap() {
return returnsMap;
}

public boolean returnsVoid() {
return returnsVoid;
}

public boolean returnsCursor() {
return returnsCursor;
}

/**
* return whether return type is {@code java.util.Optional}.
*
* @return return {@code true}, if return type is {@code java.util.Optional}
* @since 3.5.0
*/
public boolean returnsOptional() {
return returnsOptional;
}

/**
* 获取 {@code paramType} 在 {@code method} 的参数类型数组中的唯一位置
* @param method 方法对象
* @param paramType 参数类型
* @return {@code paramType} 在 {@code method} 的参数类型数组中的唯一位置,如果出现多个paramType的位置,会抛出异常
*/
private Integer getUniqueParamIndex(Method method, Class<?> paramType) {
Integer index = null;
// 获取method的参数类型数组
final Class<?>[] argTypes = method.getParameterTypes();
// 遍历参数类型数组
for (int i = 0; i < argTypes.length; i++) {
// 如果paramType为argType[i]的父类或者相同
if (paramType.isAssignableFrom(argTypes[i])) {
// 如果位置为null 赋值index
if (index == null) {
index = i;
// 如果出现多个paramType的位置,抛出异常
} else {
throw new BindingException(method.getName() + " cannot have multiple " + paramType.getSimpleName() + " parameters");
}
}
}
return index;
}

public String getMapKey() {
return mapKey;
}

/**
* 获取MapKey
* @param method 方法对象
* @return 只有当method的返回类型为Map,且有加上MapKey注解,就返回MapKey注解所定义的值;否则返回null
*/
private String getMapKey(Method method) {
String mapKey = null;
// 如果method的返回类型是Map的子类
if (Map.class.isAssignableFrom(method.getReturnType())) {
// 获取method中的MapKey注解
final MapKey mapKeyAnnotation = method.getAnnotation(MapKey.class);
// 如果method有加上MapKey注解
if (mapKeyAnnotation != null) {
// 获取MapKey注解的值
mapKey = mapKeyAnnotation.value();
}
}
// 只要当method的返回类型为Map,且有加上MapKey注解,mapKey才不为null
return mapKey;
}
}

}