文章目录
Mapper方法调用过程
Mapper方法调用时序
@Test
public void testMybatis() throws IOException, SQLException {
BaseDataTest.createBlogDataSource();
InputStream inputStream = Resources.getResourceAsStream("MapperConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
CachedAuthorMapper cachedAuthorMapper = sqlSession.getMapper(CachedAuthorMapper.class);
cachedAuthorMapper.selectAuthorWithInlineParams(1);
}
使用Mybatis框架执行sql语句,在获取到sqlSession对象后,会调用getMapper方法根据自己定义的Mapper接口获取Mybatis为我们生成的动态代理对象,即MapperProxy。当我们调用Mapper接口的方法时,例如上面的selectAuthorWithInlineParams方法时会被MapperProxy拦截,进而执行invoke方法,在此方法中会调用MapperMethod的execute方法执行sql。在execute方法中,会调用SqlCommand对象的getType方法获取sql语句的类型,调用MethodSignature对象的resolveReturnType获取方法返回值类型,调用convertArgsToSqlCommandParam解析Mapper方法参数,最后根据sql语句类型调用SqlSession的对应方法执行sql语句。
MapperProxy拦截目标方法执行
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 从Object类继承的方法不做处理
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (method.isDefault()) {
if (privateLookupInMethod == null) {
return invokeDefaultMethodJava8(proxy, method, args);
} else {
return invokeDefaultMethodJava9(proxy, method, args);
}
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
// 对Mapper接口中定义的方法进行封装,生成MapperMethod对象
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
MapperMethod的execute方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
// 获取sql语句的类型
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;
}
SqlCommand
public static class SqlCommand {
private final String name;
private final SqlCommandType type;
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
final String methodName = method.getName();
final Class<?> declaringClass = method.getDeclaringClass();
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass, configuration);
if (ms == null) {
if (method.getAnnotation(Flush.class) != null) {
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException(
"Invalid bound statement (not found): " + mapperInterface.getName() + "." + methodName);
}
} else {
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
public String getName() {
return name;
}
public SqlCommandType getType() {
return type;
}
private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName, Class<?> declaringClass,
Configuration configuration) {
// 以mapper接口的类全限定名+方法名作为statementId
String statementId = mapperInterface.getName() + "." + methodName;
// 如果configuration中注册了MappedStatement则获取
if (configuration.hasStatement(statementId)) {
return configuration.getMappedStatement(statementId);
} else if (mapperInterface.equals(declaringClass)) {
return null;
}
// 如果是在Mapper父接口中定义的
// 则根据父接口获取对应的MappedStatement对象
for (Class<?> superInterface : mapperInterface.getInterfaces()) {
if (declaringClass.isAssignableFrom(superInterface)) {
MappedStatement ms = resolveMappedStatement(superInterface, methodName, declaringClass, configuration);
if (ms != null) {
return ms;
}
}
}
return null;
}
}
MethodSignature Mapepr方法签名
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
// 获取方法返回值类型
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
if (resolvedReturnType instanceof Class<?>) {
this.returnType = (Class<?>) resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
// 返回值类型为void
this.returnsVoid = void.class.equals(this.returnType);
// 返回值类型为集合
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
// 返回值类型为Cursor
this.returnsCursor = Cursor.class.equals(this.returnType);
// 返回值类型为Optional
this.returnsOptional = Optional.class.equals(this.returnType);
this.mapKey = getMapKey(method);
// 返回值类型为Map
this.returnsMap = this.mapKey != null;
// RowBounds参数位置索引
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
// ResultHandler参数位置索引
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
// ParamNameResolver解析Mapper方法参数
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
public Object convertArgsToSqlCommandParam(Object[] args) {
return paramNameResolver.getNamedParams(args);
}
MethodSignature构造方法做了3件事。
- 获取Mapper方法的返回值,通过boolean类型的属性进行标记。
- 记录RowBounds参数位置,用户处理后续的分页查询,同时记录ResultHandler参数位置,用于处理从数据库中检索的每一行参数。
- 创建ParamNameResolver对象。ParamNameResolver对象用于解析Mapper方法中的参数和参数注解信息。
ParamNameResolver解析Mapper方法参数
public ParamNameResolver(Configuration config, Method method) {
final Class<?>[] paramTypes = method.getParameterTypes();
// 获取所有参数注解
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<>();
int paramCount = paramAnnotations.length;
// get names from @Param annotations
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
if (isSpecialParameter(paramTypes[paramIndex])) {
// skip special parameters
continue;
}
String name = null;
for (Annotation annotation : paramAnnotations[paramIndex]) {
// 方法参数中是否有@Param注解
if (annotation instanceof Param) {
hasParamAnnotation = true;
// 获取参数名称
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// @Param was not specified.
// 默认使用实际参数名称
if (config.isUseActualParamName()) {
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// use the parameter index as the name ("0", "1", ...)
// gcode issue #71
// 使用参数index作为名称
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
来源:CSDN
作者:javazcw
链接:https://blog.csdn.net/qq_22866497/article/details/103483612