从org.apache.ibatis.binding.MapperProxy开始。
MapperProxy是一个代理类实现java标准代理接口,私有构造,另提供一个获得动态代理的静态方法。
1. newMapperProxy
@SuppressWarnings("unchecked")
public static <T> T newMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {
ClassLoader classLoader = mapperInterface.getClassLoader();
Class<?>[] interfaces = new Class[]{mapperInterface};
MapperProxy proxy = new MapperProxy(sqlSession);
return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
}
newMapperProxy是一个java动态代理,支持泛型。mapperInterface就是自己定义的Mapper接口,SqlSession则从外部生成,传入。以后再学习、研究。现在主要来看MapperProxy.invoke。
2. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
final Class<?> declaringInterface = findDeclaringInterface(proxy, method);
final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession);
final Object result = mapperMethod.execute(args);
主要是获得被代理对象的接口,委托org.apache.ibatis.binding.MapperMethod执行,并获得结果。重点转到MapperMethod对象。
3.
public MapperMethod(Class<?> declaringInterface, Method method, SqlSession sqlSession) {
//........
this.config = sqlSession.getConfiguration();
}
在构造方法里将自定义的Mapper接口的方法(方法定义、传参数、返回值、方法相关的注解)与配置文件(config)关联起来:
//代码不连续,只选择部分关键代码
//完整的 类名.方法名 组成commandName
this.commandName = declaringInterface.getName() + "." + method.getName();
//通过commandName关联配置信息
//type为:public enum SqlCommandType { UNKNOWN, INSERT, UPDATE, DELETE, SELECT; }
MappedStatement ms = config.getMappedStatement(commandName);
type = ms.getSqlCommandType();
//参数的注解信息,顺序
paramName = ((Param) paramAnnos[j]).value();
//返回值信息
if (List.class.isAssignableFrom(method.getReturnType()))
在Object execute(Object[] args)方法中根据type调用SqlSession不同的方法
public Object execute(Object[] args) {
Object result = null;
if (SqlCommandType.INSERT == type) {
Object param = getParam(args);
result = sqlSession.insert(commandName, param);
}//......
} else if (SqlCommandType.SELECT == type) {
if (returnsVoid && resultHandlerIndex != null) {
executeWithResultHandler(args);//取交集 ???
} else if (returnsList) {
result = executeForList(args);//委托sqlSession.selectList
} else if (returnsMap) {
result = executeForMap(args);//委托sqlSession.selectMap
} else { //可能返回一个自定义的类
Object param = getParam(args);
result = sqlSession.selectOne(commandName, param);
}
return result;
}
目前为止,自定义的Mapper接口的使命就完成了,所有的查询都交给SqlSession处理。那么SqlSession怎么生成的,怎么处理即成为了重点。
a.连接的生成、结果集的封转。
b.配置文件的解析,动态sql生成、缓存、事务