接上文:获取线程不安全的SqlSession 上文已经获取到了SqlSession,那么下一步将通获取mapper了:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
继续跟踪这个过程:
上文中得到的SqlSession的实现是DefaultSqlSession,那么看看它的getMapper方法:
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
哦豁,还是configuration干的,OK,继续源码:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
嗯,交给了mapperRegistry(mapper注册器):
// 在初始化的时候就看到过,MapperRegistry维护了一个已知mapper的映射表,以类型做key,值是类型对应的代理工厂,通过addMapper等方法注册时加入到该映射表
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
// 获取Mapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 首先拿到代理工厂,然后使用代理工厂产生一个实例返回
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
看来有必要跟一跟代理工厂了,怎么产生的这个实例:
// 又见动态代理
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
// 先调的这个,这个调上面的实现,不过核心在于new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
又见动态代理,既然是jdk动态代理,那么核心就在于MapperProxy了,他们构造方法只是设置了几个属性,那么按jdk动态代理实现规范,必然是实现 了InvocationHandler,那么看看他的invoke方法(虽还没执行到这儿,先看看干了啥):
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 定义该方法的类如果是Object就执行并返回
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
// 这是个什么东西
final MapperMethod mapperMethod = cachedMapperMethod(method);
// 很明显是执行器
return mapperMethod.execute(sqlSession, args);
}
纳尼?MapperMethod 是什么 东东? 我也没看懂,那就看看这个cachedMapperMethod方法吧:
// 属性: methodCache = new ConcurrentHashMap<Method, MapperMethod>();
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
// 这是关键,new一个MapperMethod,传入接口、方法、配置
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
哦,有点明白了,如果不是Object,不执行invoke,那么就拿到MapperMethod对象(新建或缓前面建了放在缓存里的),然后调用execute执行,再跟一跟这个execute方法?哦豁,有点长:
// 比较明显,按SQL类型执行命令
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);
}
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;
}
这个看上去应该能猜到,命令模式,按SQL的类型执行不同的命令,具体的SQL解析拼装先不管,需要专门讨论,具体执行命令的方法也不讨论,整体大根能看出来了,如何获取的Mapper;
这里面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);
}
具体这俩对象:
- sqlCommand只有俩属性名称和类型,并且提供了getter方法:String name/SqlCommandType type
- MethodSignature ,大概是描述一个方法的东西,先占坑后补,继续流程;