//创建sqlsession以后获取mapper调用方法执行sql
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> all = employeeMapper.getAll();
但是上面的Mapper接口并没有实现类,那么为何最终能获取到结果呢,其实挺明显就是动态代理,接下来debug看代理类的生成和调用过程
DefaultSqlSession.class
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
Configuration.class
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry.class
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//检查是否扫描到了该接口,所以要注意<mapper namespace="mapper.EmployeeMapper">中内容,特别注意package名也加上
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//最终是代理工厂创建mapper
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
//创建代理类
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
从名字也可以看出来,MapperProxy就是mapper接口的代理类,点进去果不其然
//JDK动态代理
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
//缓存MapperMethod,这是封装sql操作的类
private final Map<Method, MapperMethod> methodCache;
...
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//Object类的方法直接调
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//!!!这是查询实际执行的地方
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
//如果还没调用过,生成MapperMethod并且缓存
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
接下来就是command执行过程
MapperMethod.class
public Object execute(SqlSession sqlSession, Object[] args) {
DefaultSqlSession
selectOne/selectMap...对应方法
Executor
...对应方法
总结:
mybatis先扫描配置类和mapper接口文件,生成保存配置和mapper信息的Configuration和MapperRegistry,在实际调用中利用jdk动态代理把执行交给 SqlSession对应方法。