从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生成、缓存、事务